matlab删除矩阵计算中的循环

时间:2014-12-21 23:43:18

标签: matlab for-loop matrix vectorization

根据Matrix,我正在研究Matlab上的一个问题。我认为我的代码可以通过删除for循环来改进。但我真的不知道如何解决这个问题。有人可以帮帮我吗? 代码是:

K = 3;
X = [1 2; 3 4; 5 6; 7 8];
idx = [1;2;3;1];
for i = 1:K
    ids = (idx == i);
    centroids(i,:) = sum(bsxfun(@times, X, ids))./ sum(ids);
end

在此代码中,数据点X为4x2。有K = 3个质心,因此质心是3x2的矩阵。此代码是K均值函数的一部分,该函数使用数据点及其最近的质心来查找质心的新位置。 我想把代码作为没有FOR循环的东西,可能就像这样开始:

ids = bsxfun(@eq, idx, 1:K);
centroids = ..............

2 个答案:

答案 0 :(得分:4)

您可以申请accumarray。请注意,accumarray仅在X为列时有效。因此,如果X两列,您可以拨打accumarray两次:

centroids(:,1) = accumarray(idx, X(:,1), [], @mean)
centroids(:,2) = accumarray(idx, X(:,2), [], @mean)

或者,如果X包含两列实数,您可以使用complex将两列“打包”到一个复杂列中,然后解压缩结果:

centroids = accumarray(idx, complex(X(:,1),X(:,2)), [], @mean);
centroids = [ real(centroids) imag(centroids)];

如果X任意列数,可能包含复数,则可以循环列:

centroids = NaN(K, size(X,2)); %// preallocate
for col = 1:size(X,2);
    centroids(:,col) = accumarray(idx, X(:,col), [], @mean);
end

答案 1 :(得分:4)

您可以通过使用逻辑索引来避免bsxfun,这似乎是值得的性能提升,至少对于小矩阵X而言。最好是小K,以及X的少量行。

K = 3;
X = [1 2; 3 4; 5 6; 7 8];
idx = [1;2;3;1];
centroids=zeros(K,2);
for i = 1:K
    ids = (idx == i);
    centroids(i,:) = sum(X(ids,:),1)./sum(ids);
end

如果X有大量行,则此方法最快:

K = 3;
X = [1 2; 3 4; 5 6; 7 8];
idx = [1;2;3;1];
centroids=zeros(K,2);
t=bsxfun(@eq,idx,1:K);
centroids=bsxfun(@rdivide,t.'*X,sum(t).');

如果K非常大,Luis'accumarray方法最快。