【问题标题】:How to cluster very big sparse data set using low memory in Python?如何在 Python 中使用低内存对非常大的稀疏数据集进行聚类?
【发布时间】:2017-11-03 00:27:11
【问题描述】:

我的数据形成了一个 1000 x 1e9 形状的稀疏矩阵。我想使用 K-means 将 1000 个示例聚类为 10 个聚类。

矩阵非常稀疏,小于1/1e6的值。

我的笔记本电脑有 16 个 RAM。我在 scipy 中尝试了稀疏矩阵。不幸的是,矩阵使聚类过程需要比我更多的内存。有人可以建议一种方法吗?

运行以下测试sn-p时我的系统崩溃了

import numpy as np
from scipy.sparse import csr_matrix
from sklearn.cluster import KMeans

row = np.array([0, 0, 1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8])
col = np.array([0, 2, 2, 0, 1, 2] * 3)
data = np.array([1, 2, 3, 4, 5, 6] * 3)
X = csr_matrix((data, (row, col)), shape=(9, 1e9))

resC = KMeans(n_clusters=3).fit(X)
resC.labels_

感谢任何有用的建议。

【问题讨论】:

    标签: python cluster-analysis


    【解决方案1】:

    KMeans 中心将不再是稀疏的,因此这需要针对稀疏情况进行仔细优化(对于通常情况而言这可能代价高昂,因此可能不会以这种方式进行优化)。

    您可以尝试 ELKI(不是 python,而是 Java),它通常更快,并且数据类型也稀疏。您也可以尝试使用单精度浮点数也会有所帮助。

    但最终,结果将是有问题的:k-means 在统计上植根于最小二乘。它假设您的数据来自 k 个信号加上一些高斯误差。因为你的数据是稀疏的,它显然没有这种高斯形状。当大多数值为 0 时,它不能是高斯。

    只有 1000 个数据点,我宁愿使用 HAC。

    【讨论】:

      【解决方案2】:

      无论您做什么(对于您的数据;考虑到您的内存限制):kmeans 还没有准备好!

      这包括:

      • 在线 KMeans / MiniBatch Kmeans;正如另一个答案中所建议的
        • 它只有助于处理许多样本(并且会受到后面提到的相同效果的伤害)!
      • 不同语言的各种 KMeans 实现(这是一个算法问题;不受实现的约束)

      忽略潜在的理论原因(高维和非凸启发式优化)我只是在这里提到实际问题:

      • 您的质心可能变得不稀疏! (在sidenote by SOs clustering-expert 中提到;这个链接也提到了替代品!)
        • 这意味着:使用的稀疏数据结构将变得非常不稀疏,最终会炸毁您的内存!
        • (我更改了 sklearn 的代码以观察上述链接已经提到的内容)
          • 相关sklearn代码:center_shift_total = squared_norm(centers_old - centers)

      即使您移除/关闭所有占用大量内存的组件,例如:

      • init=some_sparse_ndarray(而不是k-means++

      • n_init=1 而不是10

      • precompute_distances=False 而不是True(不清楚是否有帮助)

      • n_jobs=1 而不是-1

      以上将是您关心的问题!

      【讨论】:

      • 感谢您的回答和解释。您认为任何其他聚类方法对我有用吗?如果 k-means 在我的情况下不好,我想使用不同的方法。
      【解决方案3】:

      虽然KMeans 接受稀疏矩阵作为输入,但算法中使用的质心具有密集表示,而且您的特征空间太大,即使 10 个质心也无法放入 16GB 的 RAM。

      我有两个想法:

      1. 如果丢弃所有空列,能否将集群放入 RAM?如果您有 1000 个样本并且只占用了大约 1/1e6 的值,那么 1000 列中可能只有不到 1 列包含任何非零条目。
      2. scikit-learn 中的一些聚类算法将接受样本之间的距离矩阵,而不是完整数据,例如sklearn.cluster.SpectralClustering。您可以预先计算 1000x1000 矩阵中的成对距离,然后将其传递给您的聚类算法。 (我无法具体推荐聚类方法或计算距离的合适函数,因为这取决于您的应用程序)

      【讨论】:

      • 感谢 myrtlecat。由于不同的样本可能会获得不同的特征值,因此第二种解决方案应该是一种解决方法。
      【解决方案4】:

      考虑使用dict,因为它只会存储分配的值。我想一个很好的方法是创建一个像这样的SparseMatrix 对象:

      class SparseMatrix(dict):
          def __init__(self, mapping=[]):
              dict.__init__(self, {i:mapping[i] for i in range(len(mapping))})
      
          #overriding this method makes never-accessed indexes return 0.0
          def __getitem__(self, i):
              try:
                  return dict.__getitem__(self, i)
              except KeyError:
                  return 0.0
      
      >>> my_matrix = SparseMatrix([1,2,3])
      >>> my_matrix[0]
      1
      >>> my_matrix[5]
      0.0
      

      编辑:

      对于多维情况,您可能需要重写两个项目管理方法,如下所示:

      def __getitem__(self, ij):
          i,j = ij
          dict.__setitem__(i*self.n + j)
      
      def __getitem__(self, ij):
          try:
              i,j = ij
              return dict.__getitem__(self, i*self.n + j)
          except KeyError:
              return 0.0
      
      >>> my_matrix[0,0] = 10
      >>> my_matrix[1,2]
      0.0
      >>> my_matrix[0,0]
      10
      

      还假设您将self.n 定义为矩阵行的长度。

      【讨论】:

      • 他已经在使用基于 scipy 的设置,其中许多高质量的稀疏矩阵数据结构可用并由 sklearn 的 kmeans 支持。所以我认为这个答案没有多大帮助。
      猜你喜欢
      • 2017-10-05
      • 2011-03-11
      • 1970-01-01
      • 2013-07-28
      • 1970-01-01
      • 2015-09-05
      • 2020-12-30
      • 2022-01-11
      • 1970-01-01
      相关资源
      最近更新 更多