如何在Python中使用低内存对非常大的稀疏数据集进行集群?

如何在Python中使用低内存对非常大的稀疏数据集进行集群?,python,cluster-analysis,Python,Cluster Analysis,我的数据形成了一个1000 x 1e9形状的稀疏矩阵。我想使用K-means将1000个示例分为10个集群 矩阵非常稀疏,小于1/1e6值 我的笔记本电脑有16个内存。我在scipy中尝试了稀疏矩阵。不幸的是,矩阵使得聚类过程需要比我多得多的内存。有人能提出一个方法吗 我的系统在运行以下测试代码段时崩溃 import numpy as np from scipy.sparse import csr_matrix from sklearn.cluster import KMeans row =

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

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

我的笔记本电脑有16个内存。我在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_

任何有帮助的建议都将不胜感激。

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

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

这包括:

  • 在线KMeans/小批量KMeans;正如在另一份答复中提出的那样
    • 它只会帮助处理许多样本(并且会受到后面提到的相同效果的影响)
  • 不同语言中的各种KMeans实现(这是一个算法问题;不受实现的约束)
忽略潜在的理论原因(高维和非凸启发式优化),我只是在这里提到实际问题:

  • 您的质心可能会变得不稀疏!(在中提到;此链接还提到了备选方案!)
    • 这意味着:使用的稀疏数据结构将变得非常不稀疏,最终会耗尽您的内存
    • (我更改了sklearn的代码,以观察上面的链接已经提到的内容)
      • 相关sklearn代码:
        center\u shift\u total=squared\u norm(centers\u old-centers)
即使您删除/关闭了所有内存密集型组件,如:

  • init=一些稀疏数组
    (而不是
    k-means++

  • n_init=1
    而不是
    10

  • precompute\u distance=False
    而不是
    True
    (如果有帮助,则不清楚)

  • n_jobs=1
    而不是
    -1


以上将是您需要关注的问题

尽管
KMeans
接受稀疏矩阵作为输入,但算法中使用的质心具有密集表示,而且您的特征空间非常大,即使10个质心也无法容纳16GB的RAM

我有两个想法:

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

  • KMeans中心将不再是稀疏的,因此这需要对稀疏情况进行仔细的优化(通常情况下这可能会很昂贵,因此可能不会以这种方式进行优化)

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

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


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

    他已经在使用基于scipy的设置,其中有许多高质量的稀疏矩阵数据结构可用,并由sklearn的kmeans支持。所以这个答案在我看来没有多大帮助。谢谢你的回答和解释。你认为还有其他聚类方法适合我吗?如果k-means在我的情况下不好,我想用另一个。谢谢myrtlecat。由于不同的示例可能获得不同的特性值,第二种解决方案应该是一种变通方法。