Can I get rid of this for loop?

1 view (last 30 days)
Ryan
Ryan on 18 Mar 2016
Edited: Stephen23 on 18 Mar 2016
I have a matrix that has 3 columns that consist of -1, 0, and 1 (let's call them the "level columns"), and a fourth column that contains real numbers (call it the "data column"). For the level columns, I want to find the average of the "-1", "0", and "1" terms in the data column. So for the following matrix,
-1 -1 0 837
-1 0 -1 880
-1 0 1 879
-1 1 0 864
0 -1 -1 834
0 -1 1 833
0 0 0 874
0 0 0 875
0 0 0 876
0 1 -1 860
0 1 1 859
1 -1 0 829
1 0 -1 872
1 0 1 874
1 1 0 856
the -1 average for column 1 would be 865. Is there a way that I can do that all at once, for each level column, and each level column value? Right now, I loop over the level columns and do this:
[mean(testMat(testMat(:,col) == -1,4)) mean(testMat(testMat(:,col) == 0,4)) mean(testMat(testMat(:,col) == 1,4))]
Is there a better way?
Thanks!

Accepted Answer

Stephen23
Stephen23 on 18 Mar 2016
Edited: Stephen23 on 18 Mar 2016
You cannot get rid of the for loop, but you can hide it inside a cellfun call. Note that my answer works for any number of columns, unlike the other solutions.
M = [...
-1 -1 0 837
-1 0 -1 880
-1 0 1 879
-1 1 0 864
0 -1 -1 834
0 -1 1 833
0 0 0 874
0 0 0 875
0 0 0 876
0 1 -1 860
0 1 1 859
1 -1 0 829
1 0 -1 872
1 0 1 874
1 1 0 856 ];
%
[~,~,X] = cellfun(@unique,num2cell(M(:,1:end-1),1),'Uni',0);
N = cellfun(@(s)accumarray(s,M(:,end),[],@mean),X, 'Uni',0);
out = [N{:}]
creates this output matrix, where the rows correspond to [-1;0;1]:
>> out
out =
865 833.25 861.5
858.71 875.71 858.71
857.75 859.75 861.25

More Answers (2)

Star Strider
Star Strider on 18 Mar 2016
I would use three concatenated accumarray calls:
M = [-1 -1 0 837
-1 0 -1 880
-1 0 1 879
-1 1 0 864
0 -1 -1 834
0 -1 1 833
0 0 0 874
0 0 0 875
0 0 0 876
0 1 -1 860
0 1 1 859
1 -1 0 829
1 0 -1 872
1 0 1 874
1 1 0 856];
Result = [accumarray(M(:,1)+2, M(:,4), [], @mean), accumarray(M(:,2)+2, M(:,4), [], @mean), accumarray(M(:,3)+2, M(:,4), [], @mean)];
Result =
865 833.25 861.5
858.71 875.71 858.71
857.75 859.75 861.25
Here, the columns correspond to those in ‘M(:,1:3)’ and the rows correspond to ‘[-1; 0; 1]’ respectively.

Image Analyst
Image Analyst on 18 Mar 2016
If you have the Statistics and Machine Learning Toolbox, you can use grpstats(), but I don't know if it would be any more compact that what you're already doing.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!