如何在不使用for循环的情况下求和不同大小的矩阵的各个部分?

时间:2018-06-27 10:21:33

标签: matlab matrix vectorization bsxfun

我有一个相对较大的矩阵NxN(N〜20,000)和一个Nx1向量,用于标识必须分组在一起的索引。

我想将矩阵的各个部分加在一起,原则上可以有不同数量的元素和不相邻的元素。 我很快写了一个双for循环,它可以正常工作,但是效率很低。探查器将这些循环识别为我代码中的瓶颈之一。

我试图找到一种智能的矢量化方法来解决该问题。我探索了arrayfuncellfunbsxfun函数,并寻找了类似问题的解决方案...但是我还没有找到最终的解决方案。

这是带有两个for循环的测试代码:

M=rand(10); % test matrix
idxM=[1 2 2 3 4 4 4 1 4 2]; % each element indicates to which group each row/column of M belongs
nT=size(M,1);
sumM=zeros(max(idxM),max(idxM));
for t1=1:nT
    for t2=1:nT
        sumM(t1,t2) = sum(sum(M(idxM==t1,idxM==t2)));
    end
end

3 个答案:

答案 0 :(得分:3)

您可以按以下方式使用accumarray

nT = size(M,1); % or nT = max(idxM)
ind = bsxfun(@plus, idxM(:), (idxM(:).'-1)*nT); % create linear indices for grouping
sumM = accumarray(ind(:), M(:), [nT^2 1]); % compute sum of each group
sumM = reshape(sumM, [nT nT]); % reshape obtain the final result

答案 1 :(得分:2)

使用cumsumdiff的解决方案。

[s,is] = sort(idxM);
sumM  = M(is,is);
idx = [diff(s)~=0 ,true];
CS = cumsum(sumM);
CS = cumsum(CS(idx,:),2);
n=sum(idx);
result = diff([zeros(n,1) diff([zeros(1,n); CS(:,idx)])],1,2);
sumM (:)=0;
sumM (s(idx),s(idx))=result;

答案 2 :(得分:1)

我想指出对另一个论坛提供的答案有兴趣的人

S=sparse(1:N,idxM,1); sumM=S.'*(M*S);

信用(和有用的讨论):

https://www.mathworks.com/matlabcentral/answers/407634-how-to-sum-parts-of-a-matrix-of-different-sizes-without-using-for-loops