在MATLAB中优化手工编码的k-均值?

在MATLAB中优化手工编码的k-均值?,matlab,optimization,vectorization,k-means,Matlab,Optimization,Vectorization,K Means,所以我正在用MATLAB编写一个k-means脚本,因为本机函数似乎不是很有效,而且似乎是完全可操作的。它似乎在我使用的小训练集上工作(这是一个通过文本文件馈送的150x2矩阵)。但是,对于我的目标数据集(3924x19矩阵),运行时所用的时间呈指数级增长 我不是矢量化方面的高手,所以任何建议都将不胜感激。这是我到目前为止的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