MATLAB: How to use accumarray over a matrix avoiding a loop

accumarrayloopmatrix

Hi,
I want to sum elements of a matrix according to an index. If instead of the matrix I had a vector, I could use accumarray. However, accumarray does not accept matrices as second argument. Any ideas on how to do this avoiding a loop to sum for each vector separately?
For example:
A=[1;1;2;3;3;3];
B=rand(6,10);
C=accumarray(A,B);
gives the output ??? Error using ==> accumarray Second input VAL must be a vector with one element for each row in SUBS, or a scalar.
I could do this by columns of B
C=zeros(size(unique(A),1),10);
for i=1:10,
C(:,i)=accumarray(A,B(:,i));
end
But if the number of columns of B is large, this will be quite slow and I would like this step to be done quickly as it has to be done as part of a minimization routine, so it is done every time the objective function is evaluated.
Thanks,

Best Answer

You could always use accumarray with two dimensions of subs rather than vals:
A=[1;1;2;3;3;3];
B=rand(6,10);
[xx, yy] = ndgrid(A,1:size(B,2));
C=accumarray([xx(:) yy(:)],B(:));
Frankly, I'll bet the for-loop will be fastest.
More And my suspicions are right depending on how big A and B actually are. I am seeing the for-loop be faster with small arrays and accumarray with two-dimensional subs being faster for larger ones.
arrayfun/cell2mat etc are really slow since they require the conversion to cells which are slow and arrayfun is just slower than a for-loop anyway.
function timeAccumarray
A=[1;1;2;3;3;3];
B=rand(6,10);
[t1,t2,t3] = deal(0);
for ii = 1:100
tic
[xx, yy] = ndgrid(A,1:size(B,2));
C=accumarray([xx(:) yy(:)],B(:));
t1 = t1+toc;
tic
for jj=size(B,2):-1:1 %dynamically preallocate, avoiding slow unique()
C2(:,jj)=accumarray(A,B(:,jj));
end
t2=t2+toc;
tic
C3=cell2mat(arrayfun(@(x) accumarray(A,B(:,x)),1:size(B,2),'un',0));
t3 = t3+toc;
end
isequal(C,C2,C3)
[t1 t2 t3]
ans = 0.0072 0.0289 0.1381