3
votes

I have two M by N matrices, labeled A and B, and I would like to create a vector containing the sum of all items in B for each unique value of A. For example I have the following matrices:

A = [6 2 3 4
     5 2 3 3
     5 5 6 2];

B = [.2 .5 .4 .1
     .7 .2 .5 .1
     .6 .6 .1 .9];

and I would like to create a vector C where each index corresponds to the index of D = unique(A). So for this case, D = [2,3,4,5,6] and

for I = 1:length(D)
    C(I) = sum(B(A(:)==D(I));
end

This gets really slow when D is 2000 items long and A and B both are ~4000x20 matrices. Any help on speeding this up? I tried doing the following:

Indxs = bsxfun(@eq,A,reshape(D,1,1,length(D)));
for I = 1:size(Indxs,3)
    C(I) = sum(B(Indxs(:,:,I));
end

but it's not really any faster.

1
Also, I am preallocating C to speed it up that way. - user3329648

1 Answers

4
votes

You can do this with the usual combination of unique and accumarray:

[D, ~, uA] = unique(A(:));
C = accumarray(uA, B(:));

With your example data, the result is:

>> D
D =
     2
     3
     4
     5
     6

>> C
C =
    1.6000
    1.0000
    0.1000
    1.9000
    0.3000

What accumarray does, in its most basic form (two input arguments), is to sum all second-argument values that have the same first-argument value.


If A contains only positive integers, there's a one-line solution with sparse and find:

[D, ~, C] = find(sparse(A(:), 1, B(:)));

This works because sparse accumulates values corresponding to the same index.