如何在非常大的scipy稀疏矩阵之间计算Dot积

时间:2014-07-22 23:38:01

标签: python numpy scipy sparse-matrix matrix-multiplication

我正在尝试在巨大的矩阵与其自身之间找到点积。

矩阵的形状(371744,36154) Num of NonZero - 577731 [非常稀疏]

mat1是scipy.sparse.csr_matrix 如果我使用 mat1 * mat1.T 我得到一个值错误,这看起来像是因为在结果矩阵中有太多的非零元素,并且索引指针根据here溢出

    dp_data = data_m * data_m.T
  File "/usr/lib/python2.7/dist-packages/scipy/sparse/base.py", line 247, in __mul__
    return self._mul_sparse_matrix(other)
  File "/usr/lib/python2.7/dist-packages/scipy/sparse/base.py", line 300, in _mul_sparse_matrix
    return self.tocsr()._mul_sparse_matrix(other)
  File "/usr/lib/python2.7/dist-packages/scipy/sparse/compressed.py", line 290, in _mul_sparse_matrix
    indices = np.empty(nnz, dtype=np.intc)
ValueError: negative dimensions are not allowed

我也尝试了 np.dot

但是doc说,
“从NumPy 1.7开始,np.dot不知道稀疏矩阵,因此使用它会导致意外的结果或错误。应首先获得相应的密集矩阵”

当我到mat1.toarray()或todense()时,我得到一个内存错误,因为矩阵是巨大的!!我有16GB的内存!该程序似乎适用于较小的输入!

    data_array = data_m.toarray()
  File "/usr/lib/python2.7/dist-packages/scipy/sparse/compressed.py", line 550, in toarray
    return self.tocoo(copy=False).toarray()
  File "/usr/lib/python2.7/dist-packages/scipy/sparse/coo.py", line 219, in toarray
    B = np.zeros(self.shape, dtype=self.dtype)
MemoryError

我正在使用 Numpy版本1.8.1 Numpy版本0.9.0

我怎么做这个乘法?

2 个答案:

答案 0 :(得分:3)

将点积称为稀疏矩阵的方法:

dp_data = data_m.dot(data_m)

numpy.dot是一个Universal Function,它不知道你的矩阵的稀疏性,而scipy.sparse.csc_matrix.dot是一个为你的矩阵类型量身定制的方法,因此使用稀疏算法。

答案 1 :(得分:1)

首先,稀疏输出矩阵的大小和计算所需的CPU工作量取决于稀疏矩阵的结构。如果有很多空行,事情会变得更容易。另一方面,如果您的数据均匀分布,则需要计算很多。

首先要意识到的是,在这种特定情况下(a * a.T),您实际上是计算每行的每个行(36154元素向量)的点积。这有助于您将计算时间减半,因为结果将是对称的。 (这为您留下了大约5亿个矢量点产品。)

现在,无论你是否匆忙,问题都是很多。如果您赶时间(性能很重要),那么可能有一些方法可以使计算更快,具体取决于数据中非零的分布方式。

一个相当简单的算法如下:

# a is in row-form (n_row lists of non-zeros in each row)

for r in 0..n_row-1
    if all elements in the row are zero
        skip the row
    for c in r..n_row-1
        d := dot(a[c],a[r])
        if d <> 0
            result[r,c] = d
            result[c,r] = d

通过查找a[c]a[r]中非零元素集的交集,可以轻松计算点积。大部分时间交叉点都是空的,只有当它不为空时才需要进行计算。

根据矩阵中的空行数,这可能相对较快。另一方面,如果您没有任何空行或列,则需要花费时间计算500 000 000套交叉点。 (在这种情况下,大多数是在1组之间,因此它们是简单的比较。)

这种方法需要很少的内存,但仍然需要很多时间,从几小时到几天,除非有很多空行。