Calculate mean of columns for a unique value of column variable?

7 Ansichten (letzte 30 Tage)
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.

Akzeptierte Antwort

the cyclist
the cyclist am 18 Jun. 2017
This will do what you want with a for loop:
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];
[uniqueA1,~,k] = unique(A(1,:));
numberUniqueA1 = numel(uniqueA1);
meanArray = zeros(size(A,1),numberUniqueA1);
for nu = 1:numberUniqueA1
indexToThisUniqueValue = (nu==k)';
meanArray(:,nu) = mean(A(:,indexToThisUniqueValue),2);
end

Weitere Antworten (2)

dpb
dpb am 18 Jun. 2017
Bearbeitet: dpb am 18 Jun. 2017
>> [~,~,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
Andrei Bobrov am 18 Jun. 2017
Bearbeitet: Andrei Bobrov am 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 Kommentare
the cyclist
the cyclist am 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.
dpb
dpb am 18 Jun. 2017
Bearbeitet: dpb am 18 Jun. 2017
Less memory-intensive, too, if A gets really large...I hadn't thought of the 2D subscripting array into the full 1D vector, though...had pondered the thought of generating the 1D vector to go with it and that didn't seem attractive.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Elementary Math finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by