如何在Python中使用低内存聚类非常大的稀疏数据集?

时间:2017-11-03 00:27:12

标签: python cluster-analysis

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

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

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

运行以下测试代码段时,我的系统崩溃了

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_

感谢任何有用的建议。

4 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

无论你做什么(对于你的数据;考虑到你的记忆限制): kmeans还没准备好!

这包括:

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

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

  • 您的质心可能会变得非稀疏! (在sidenote by SOs clustering-expert中提到;此链接还提到了替代方案!)
    • 这意味着:使用的稀疏数据结构将变得非常稀疏并最终炸毁你的记忆!
    • (我更改了sklearn的代码以观察上面提到的链接)
      • 相关的sklearn代码:Worksheets("Sheet3").OLEObjects.Add filename:="C:\Users\myname\Desktop\" & fName, Link:=False, DisplayAsIcon:=False, Left:=40, Top:=40, Width:=150, Height:=10

即使您删除/关闭所有内存繁重的组件,例如:

  • 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

以上将是你需要关心的问题!

答案 2 :(得分:0)

虽然KMeans接受稀疏矩阵作为输入,但算法中使用的质心具有密集表示,并且您的特征空间非常大,甚至10个质心也不适合16GB的RAM。

我有两个想法:

  1. 如果丢弃所有空列,是否可以将聚类放入RAM中?如果您有1000个样本且仅占用约1 / 1e6个值,则1000个列中可能少于1个将包含任何非零条目。
  2. scikit-learn中的几种聚类算法将接受样本之间的距离矩阵,而不是完整数据,例如: sklearn.cluster.SpectralClustering。您可以预先计算1000x1000矩阵中的成对距离,并将其传递给您的聚类算法。 (我不能对聚类方法做出具体建议,也不能根据你的应用提出合适的函数来计算距离)

答案 3 :(得分:-2)

考虑使用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定义为矩阵行的长度。