根据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 = ..............
答案 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
方法最快。