在MATLAB中优化手工编码的k-均值?
所以我正在用MATLAB编写一个k-means脚本,因为本机函数似乎不是很有效,而且似乎是完全可操作的。它似乎在我使用的小训练集上工作(这是一个通过文本文件馈送的150x2矩阵)。但是,对于我的目标数据集(3924x19矩阵),运行时所用的时间呈指数级增长 我不是矢量化方面的高手,所以任何建议都将不胜感激。这是我到目前为止的k-means脚本(我知道我必须调整收敛条件,因为它正在寻找一个精确的匹配,对于这么大的数据集,我可能需要更多的迭代,但我希望它能够在合理的时间内首先完成,然后再增加这个数字): 这里有很多循环,所以我觉得有很多优化要做。然而,我想我已经盯着这个代码看太久了,所以一些新鲜的眼睛可能会有所帮助。如果我需要澄清代码块中的任何内容,请告诉我在MATLAB中优化手工编码的k-均值?,matlab,optimization,vectorization,k-means,Matlab,Optimization,Vectorization,K Means,所以我正在用MATLAB编写一个k-means脚本,因为本机函数似乎不是很有效,而且似乎是完全可操作的。它似乎在我使用的小训练集上工作(这是一个通过文本文件馈送的150x2矩阵)。但是,对于我的目标数据集(3924x19矩阵),运行时所用的时间呈指数级增长 我不是矢量化方面的高手,所以任何建议都将不胜感激。这是我到目前为止的k-means脚本(我知道我必须调整收敛条件,因为它正在寻找一个精确的匹配,对于这么大的数据集,我可能需要更多的迭代,但我希望它能够在合理的时间内首先完成,然后再增加这个数字
根据MATLAB的profiler,在大数据集上执行上述代码块(在上下文中)时,需要3732.152秒才能对150个集群进行完整的25次迭代(我假设它还没有根据我的标准“收敛”),但其中大约130个集群返回NAN(在Muu_k中为130行)。评测将有所帮助,但是,重新编写代码的地方是避免在数据点的数量上循环(
for point=1:size(data,1)
)。矢量化
在迭代的循环中,这里有一个快速的部分示例
[nPoints,nDims] = size(data);
% Calculate all high-dimensional distances at once
kdiffs = bsxfun(@minus,data,permute(mu_k,[3 2 1])); % NxDx1 - 1xDxK => NxDxK
distances = sum(kdiffs.^2,2); % no need to do sqrt
distances = squeeze(distances); % Nx1xK => NxK
% Find closest cluster center for each point
[~,ik] = min(distances,[],2); % Nx1
% Calculate the new cluster centers (mean the data)
mu_k_new = zeros(c,nDims);
for i=1:c,
indk = ik==i;
clustersizes(i) = nnz(indk);
mu_k_new(i,:) = mean(data(indk,:))';
end
这不是唯一(或最好)的方法,但它应该是一个不错的例子
其他一些评论:
不要使用input
,而是将此脚本变成一个函数,以有效地处理输入参数
如果需要一种简单的指定文件的方法,请参阅uigetfile
使用许多MATLAB函数,如max
、min
、sum
、mean
等,可以指定函数应在其上运行的维度。这样,您可以在矩阵上运行它,同时计算多个条件/维度的值
<> LI>一旦你得到了不错的性能,考虑迭代更长,具体地,直到中心不再改变或改变簇的样本数量变小。
每个点距离最小的簇,ik
,与平方欧氏距离相同
我们可以指出很多罪魁祸首,但您确实应该从分析开始优化<代码>配置文件打开;myScript;概况报告;轮廓关闭代码>这真的很简单,你会学到很多。我确实做到了……我想。我在执行时使用了“Run and Time”(运行和时间)按钮,并且在完成程序运行后弹出探查器报告。下面是一个关于发生了什么的例子。这就是你说的吗?是的,就是这样pdist大约占您计算时间的77%,因此您只能将精力集中在kmeans
的“自我时间”部分。单击kmeans
查看哪些行是错误的。查看pdist
正在做什么(在它到达pdistmex
之前)以及是否有办法解决它也无妨。我刚刚注意到你的循环超过了点数。这就是你的问题,把这个循环矢量化,我确实怀疑。这将是迭代过程中最长的循环。当涉及到pdist和pdistmex时,我真的不确定如何解释分析器输出;然而,看起来pdistmex是花费时间最多的地方。不过,那里发生了很多事情。我很抱歉要求一些牵手,但矢量化似乎是相当命中或错过了我。如何改革该部分以避免循环?更新了示例。刚刚修复了mu_k__new
。哦,这个例子不仅删除了循环的点,还做了很多其他的事情。你能解释一下indk=ik==i是做什么的吗?我以前从未见过这样的公式。事实上,当我可以获得更好的运行时,我将以数百左右的顺序进行迭代。ik==I
测试ik
的每个值是否与I
相等,并返回与ik
大小相同的逻辑数组。太棒了!如果那样的话,时间将从一小时减少到几分钟。我已经标记了你的答案(还没有足够的声誉来提升投票:()),并不是说还有其他答案可供选择…谢谢你的帮助!
[nPoints,nDims] = size(data);
% Calculate all high-dimensional distances at once
kdiffs = bsxfun(@minus,data,permute(mu_k,[3 2 1])); % NxDx1 - 1xDxK => NxDxK
distances = sum(kdiffs.^2,2); % no need to do sqrt
distances = squeeze(distances); % Nx1xK => NxK
% Find closest cluster center for each point
[~,ik] = min(distances,[],2); % Nx1
% Calculate the new cluster centers (mean the data)
mu_k_new = zeros(c,nDims);
for i=1:c,
indk = ik==i;
clustersizes(i) = nnz(indk);
mu_k_new(i,:) = mean(data(indk,:))';
end