在Python中动态构造磁盘上的稀疏矩阵

Ced*_*oom 9 python memory numpy matrix scipy

目前,我正在做一些内存密集型的文字处理,我必须构建sparse matrixfloat32s与尺寸~ (2M, 5M).我在阅读5M文档的语料库时逐列构建此矩阵.为此,我使用了稀疏dok_matrix数据结构SciPy.但是,当到达第500 000个文档时,我的内存已满(使用大约30GB)并且程序崩溃.我最终想要做的是,使用矩阵对矩阵执行降维算法sklearn,但是,如上所述,不可能在内存中保持和构造整个矩阵.我已经研究过numpy.memmap,正如sklearn支持这一点,并尝试memmap了SciPy稀疏矩阵的一些潜在的numpy数据结构,但我无法成功实现这一点.

我不可能以密集格式保存整个矩阵,因为这需要40TB的磁盘空间.所以,我认为,HDF5PyTables对我来说没有选项(?).

我现在的问题是:如何动态构建稀疏矩阵,但是直接写入磁盘而不是内存,以后我可以在sklearn中使用它?

谢谢!

Rob*_*bin 0

如果您能提供最少的工作代码,那就太好了。我看不出你的矩阵是否因构造而变得太大(1),或者只是因为你有太多数据(2)。如果你不太关心自己构建这个矩阵,可以直接看我的评论2。

对于问题(1),在下面的示例代码中,我创建了一个包装类来逐块构建 csr_matrix。这个想法是只添加列表的(行,列,数据)元组,直到达到缓冲区限制(参见备注 1),并在此时实际更新矩阵。当达到限制时,它将减少内存中的数据,因为 csr_matrix 构造函数添加具有相同(行,列)元组的数据。这部分只是让你能够快速构造稀疏矩阵(比为每行创建稀疏矩阵快得多),并避免当一个单词在文档中出现多次时,由于(行,列)的冗余而导致的内存错误。

import numpy as np
import scipy.sparse

class SparseMatrixBuilder():
    def __init__(self, shape, build_size_limit):
        self.sparse_matrix = scipy.sparse.csr_matrix(shape)
        self.shape = shape
        self.build_size_limit = build_size_limit
        self.data_temp = []
        self.col_indices_temp = []
        self.row_indices_temp = []


    def add(self, data, col_indices, row_indices):
        self.data_temp.append(data)
        self.col_indices_temp.append(col_indices)
        self.row_indices_temp.append(row_indices)
        if len(self.data_temp) == self.build_size_limit:
            self.sparse_matrix += scipy.sparse.csr_matrix(
                (np.concatenate(self.data_temp),
                 (np.concatenate(self.col_indices_temp),
                  np.concatenate(self.row_indices_temp))),
                shape=self.shape
            )
            self.data_temp = []
            self.col_indices_temp = []
            self.row_indices_temp = []

    def get_matrix(self):
        self.sparse_matrix += scipy.sparse.csr_matrix(
            (np.concatenate(self.data_temp),
             (np.concatenate(self.col_indices_temp),
              np.concatenate(self.row_indices_temp))),
            shape=self.shape
        )
        self.data_temp = []
        self.col_indices_temp = []
        self.row_indices_temp = []
        return self.sparse_matrix
Run Code Online (Sandbox Code Playgroud)

对于问题(2),您可以通过添加一个保存方法来轻松扩展此类,该方法在达到限制(或第二个限制)时将矩阵存储在磁盘上。因此,您最终将在磁盘上得到多个稀疏矩阵块。然后,您需要一个可以处理分块矩阵的降维算法(请参阅备注 2)。

备注 1:这里的缓冲区限制并没有真正明确定义。最好检查 numpy 数组 data_temp、col_indices_temp 和 row_indices_temp 的实际大小与机器上可用的 RAM 相比(这很容易使用 python 实现自动化)。

备注 2:gensim是一个 Python 库,它的一大优点是使用分块文件来构建 NLP 模型。因此,您可以构建一个字典,构建一个稀疏矩阵并使用该库减少其维度,而不需要太多 RAM。