matlab中的k-均值是否内存不足取决于距离函数?

matlab中的k-均值是否内存不足取决于距离函数?,matlab,memory-management,cluster-analysis,distance,k-means,Matlab,Memory Management,Cluster Analysis,Distance,K Means,我在一个大而稀疏的矩阵(10000000000x1000)上使用了k-means和matlab。现在问题来了-使用余弦相似性作为距离函数,我在几分钟内得到“内存不足。键入帮助内存以获取选项”消息。然而,如果我使用欧几里德距离,它运行得非常完美(相同的矩阵) 这有点奇怪,因为距离是成对计算的,每次距离计算不需要超过一个小的常量内存 在较小的矩阵(1000x1000,但不是稀疏矩阵)上使用k-均值时,余弦效果非常好 技术细节: 这台机器是64位的,带有8GB RAM。 如果您想尝试:可以找到矩阵(它

我在一个大而稀疏的矩阵(10000000000x1000)上使用了k-means和matlab。现在问题来了-使用余弦相似性作为距离函数,我在几分钟内得到“内存不足。键入帮助内存以获取选项”消息。然而,如果我使用欧几里德距离,它运行得非常完美(相同的矩阵)

这有点奇怪,因为距离是成对计算的,每次距离计算不需要超过一个小的常量内存

在较小的矩阵(1000x1000,但不是稀疏矩阵)上使用k-均值时,余弦效果非常好

技术细节: 这台机器是64位的,带有8GB RAM。 如果您想尝试:可以找到矩阵(它位于sendspace上,因此它将在几周内可用)

文件采用稀疏格式:[行]\t[列]\t[值]\n

matlab代码:

f=load(filename);
v=spconvert(f);
c=kmeans(v,9);
c=kmeans(v,9,'distance','cosine');
  • 关于内存使用的不同,还有余弦距离和欧几里得距离吗

  • 你知道如何在一个大矩阵上使用余弦吗


  • 谢谢

    如果检查
    kmeans.m
    函数,则余弦距离的代码可归结为两个关键部分,这可能会引发内存不足错误。首先让我介绍一下涉及的主要变量:

    • X
      :行是观察向量,列是维度(数据)
    • C
      :行是质心,列是尺寸(簇质心)
    1) 第一段代码是将数据行规范化为单位长度(这在之前的已删除答案中指出,但原因错误):

    上面尝试使用一个索引将操作矢量化,以尽可能多的列重复范数向量,然后进行元素分割。只需检查变量大小即可了解这种方法的问题:

    >> whos X Xnorm
      Name             Size                 Bytes  Class     Attributes
    
      X          1017564x1000            83056640  double    sparse    
      Xnorm      1017564x1               12210776  double    sparse    
    
    因此,
    Xnorm(:,one(1,p))
    将尝试分配大小为
    12210776*1000字节=11.3722 GB的临时矩阵,这显然是导致内存不足错误的原因

    (对于感兴趣的人来说,双稀疏矩阵
    X
    内部需要
    12*nnz(X)+4*size(X,2)字节
    进行存储,而完整表示需要
    prod(size(X))*8字节
    。在您的情况下,这大约需要80MB而不是11.5GB的内存!)

    这一行可以用不同的(可能更慢的)方式编写,这样可以避免巨大的空间需求,这通常是矢量化的一个缺点。只需在每一行上循环并除以范数。更好的是,我们可以使用专门为此类情况设计的BSXFUN函数(避免使用REPMAT和索引技巧):

    有趣的是,在KMEANS文件的其他地方有注释的代码段,在这些地方,这个问题得到了明确的考虑,因此选择了使用较慢的for循环,但保证不会耗尽内存

    2) 第二个临界段是实际计算距离的地方。兴趣代码如下所示:

    n = size(X,1);
    nclusts = size(C,1);
    
    D = zeros(n,nclusts);
    for i = 1:nclusts
        D(:,i) = max(1 - X*C(i,:)', 0);
    end
    
    基本上,它计算每个数据实例与每个集群质心的内积(一次一个质心,相对于整个数据向量)。同样,如果这会导致问题,您可以简单地将矢量化产品展开成一个逐步循环,如下所示:

    for i = 1:nclusts
        for j = 1:n
            D(j,i) = max(1 - dot(X(j,:),C(i,:)), 0);
        end
    end
    
    所以你明白了;当你的矩阵非常大时,你必须小心那些会产生较大中间结果的操作,如果可能的话,用一个在较小范围内操作的显式循环来代替它们


    顺便说一句,使用欧几里德距离时,您不会遇到相同的问题,因为它是用循环而不是单线矢量化解决方案编写的。以下是计算距离函数的部分:

    for i = 1:nclusts
        D(:,i) = (X(:,1) - C(i,1)).^2;
        for j = 2:p
            D(:,i) = D(:,i) + (X(:,j) - C(i,j)).^2;
        end
        % D(:,i) = sum((X - C(repmat(i,n,1),:)).^2, 2);    %# <--- commented code
    end
    


    请注意,在完成之前,我没有尝试对整个数据进行集群。我在一台4GB的32位机器上运行(由于架构限制,其中MATLAB只能访问3GB),因此请报告建议的更改是否确实对64位/8GB硬件产生了影响;)

    第一个kmeans需要多长时间@ScienceFriction:下载文件太大。。您应该这样做:
    f=load(文件名);v=SPF;保存output.mat v
    然后上传mat文件(应该小得多),感谢您提供的详细答案。我会试着报告。在男性时代,我选择了这里描述的算法:(源代码可用:),它非常快,尽管不能保证是最优的。@ScienceFriction:我认为这是一个很好的选择。但为了澄清你的最后一句话,这个小批量方法被认为是相对于完全收敛的批处理Kmeans算法而言不是最优的,该算法本身只在给定初始种子的情况下给出局部最优。毕竟这是一个NP难问题,在相同的数据上花了大约20分钟。这很好。当然是局部最优的(我们尝试了不同的种子采样/创建方法,以获得更好的、仍然是启发式的结果。再次感谢。
    for i = 1:nclusts
        for j = 1:n
            D(j,i) = max(1 - dot(X(j,:),C(i,:)), 0);
        end
    end
    
    for i = 1:nclusts
        D(:,i) = (X(:,1) - C(i,1)).^2;
        for j = 2:p
            D(:,i) = D(:,i) + (X(:,j) - C(i,j)).^2;
        end
        % D(:,i) = sum((X - C(repmat(i,n,1),:)).^2, 2);    %# <--- commented code
    end
    
    for i=1:nclusts
        D(:,i) = sum(bsxfun(@minus, X, C(i,:)).^2, 2);
    end