Calculate mean of columns for a unique value of column variable?
Show older comments
I have a matrix of 38767*31. I want to calculate mean of columns for unique value of variable in columns (in first row).Let me clarify my problem.
Let
A=[1 2 1 2 1 1 2 1 1
3 2 1 2 3 4 5 6 2
2 1 2 1 3 5 4 2 6]
for unique value for 1st row of A, I have to calculate mean of all corresponding columns. I mean I should get as follows,
B=[1 2; 3.66 3; 3.33 2];
for unique of 1st row (=1), mean of corresponding values (3+1+3+4+6+1)/6=3.166 for 2nd row and (2+2+3+5+2+6)/3=3.33 for 3rd row. for value of 1st row (=2), mean of corresponding values (2+2+5)/3=3 for 2nd row and (1+1+4)/3=2 for 3rd row.Hope I am understood. I tried using accumarray but not able to do. my code is,
A=importdata('abc.dat');
y=accumarray(unique(A(1,:)),A(1,:),[],@mean));
It shows following error, Second input VAL must be a vector with one element for each row in SUBS, or a scalar.? Help. Thanks in advance.
Accepted Answer
More Answers (2)
>> [~,~,ib]=unique(A(1,:));
>> C=A(2,:);
>> accumarray(ib,C,[],@mean)
ans =
3.1667
3.0000
>>
Unfortunately, accumarray only works on a vector val input, not columns in an array (it's convoluted-enough already without that complication so that's understandable although would be the cat's meow here, indeed.)
Let's see if there's another way without looping over every column...hmmm....well, let's try
>> ix=A(1,:);
>> u=unique(ix);
>> for i=1:length(u),mean(A(2:end,ix==u(i)),2),end
ans =
3.1667
3.3333
ans =
3
2
>>
You can mull over how to best code it for your situation...
ADDENDUM:
May not be any better speedwise than the loop, but for the record--
>> arrayfun(@(ix) accumarray(ib,A(ix,:).',[],@mean),2:size(A,1),'uniformoutput',0)
ans =
[2x1 double] [2x1 double]
>> ans{:}
ans =
3.1667
3.0000
ans =
3.3333
2.0000
>>
ib is the previous index vector from unique above, of course...
Try to figure out what that does two years down the road when you come back to it! :)
Andrei Bobrov
on 18 Jun 2017
Edited: Andrei Bobrov
on 18 Jun 2017
[g,ii] = findgroups(A(1,:)');
out = [ii,splitapply(@mean,A(2:3,:)',g)]';
or
[ii,jj] = ndgrid(A(1,:),1:2);
out = [unique(A(1,:)'), accumarray([ii(:),jj(:)],reshape(A(2:3,:)',[],1),[],@mean)]';
2 Comments
the cyclist
on 18 Jun 2017
The second solution can be simplified to
[ii,jj] = ndgrid(A(1,:),1:3);
out = [accumarray([ii(:),jj(:)],reshape(A',[],1),[],@mean)]';
Depending on the depth of one's understanding of accumarray, I feel like this solution is both more elegant and more obfuscated than my for-loop solution. Either way, I would be sure to add some comments so that future you remembers what is going on in this code.
In limited testing, the for-loop solution is the fastest of these.
Categories
Find more on Matrices and Arrays in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!