哪个是将大型稀疏矩阵与其转置相乘的最佳方法?

时间:2014-07-04 04:18:47

标签: python c++ linear-algebra sparse-matrix matrix-multiplication

我目前想要将大型稀疏矩阵(~1M x 200k)与其转置相乘。结果矩阵的值将为float。

  • 我尝试在scipy的稀疏矩阵中加载矩阵,并将第一矩阵的每一行与第二矩阵相乘。乘法需要2小时才能完成。

实现这种乘法的有效方法是什么?因为我在计算中看到了一个模式。

  • 矩阵大而稀疏。
  • 矩阵与其转置的乘法。因此,生成的矩阵将是对称的。

我想知道哪些库可以更快地实现计算。它可以是Python,R,C,C ++或任何其他。

3 个答案:

答案 0 :(得分:5)

我认为你的主要需求是节省内存。首先,当您将矩阵与其转置相乘时,您不需要任何转置的记忆:它的所有单元格都可以通过第一个矩阵直接访问(tA [i,j] = A [j,i])。几乎节省了1/3的内存。

我可以看到计算时间也不容忽视。由于生成的矩阵将是对称的,因此您只能计算一半并直接存储另一半。节省了近一半的计算时间。

如果你确定你的初始矩阵真的是稀疏的,所以希望得到的矩阵也是如此,你可以直接将结果存储在scipy稀疏矩阵中,COO格式: 只有三个列表来存储非空值。

但是......我不知道任何库可以做到这一点你必须用自己喜欢的语言自己编写代码(可能是python,因为你提到了scipy)。

Python代码示例(矩阵= A [M] [N])

I = []
J = []
V = []
for i in range(M):
    for j in range(i:M) :
        X = 0.0
        for k in range(N):
            X += A[i ][k] * A[k][j]
        if X != 0.0 # or abs (X) > epsilon if floating point accuracy is a concern ... 
            I.append (i )
            J.append(j)
            V.append(X)
            I.append (j )
            J.append(i)
            V.append(X)

我,J,V是scipy COO稀疏矩阵所需要的:

RESULT = sparse.coo_matrix((V,(I,J)),shape=(N, N))

答案 1 :(得分:1)

def URMdist(URM):
    NLin=URM.shape[0]
    NCol=URM.shape[1]
    URMt=URM.T
    Result = lil_matrix((NLin,NLin))
    for Lin in range(0,NLin):
        X = 0.0
        for Col in range(Lin,NLin):
            X = URM[Col,:].dot(URMt[:,Lin])
            if X != 0.0: 
                Result[Lin,Col] = Result[Col,Lin] = X
    return Result

答案 2 :(得分:0)

您遇到的问题是原始矩阵的剪切大小。如果A具有1e6行的顺序,则A*A.T具有1e12条目的顺序!绝对不可能在台式计算机中使用这种矩阵,并且期望它很快。另外,我认为问题不在使用Python,因为Scipy中的关键循环是用C或Fortran实现的(请参见here)。

话虽这么说,我本人正面临一个较小版本的问题(〜200k行,〜3k cols),我发现如果您小心谨慎并且在各处都使用稀疏矩阵,Python的效果会很好。 (我之所以打破稀疏性,是因为我将稀疏矩阵除以矢量。不要这样做。)

您可以使用稀疏矩阵的普通重载运算符*进行乘法。

import scipy.sparse as sp
import numpy as np

# ... in my case my sparse matrix is obtained from real data
# ... but we get something similar below

A = sp.rand(int(2e5), int(3e3), density=1e-3, format='csr')

# If used in the jupyter notebook
%time A * A.T      # Wall time: 2.95 s

# Another option
At = A.T.tocsr()
%time A * At       # Wall time: 2.89 s

我发现非常有趣的是,尽管文档表明第二个选项csr相乘的速度更快,但第二个选项的速度并没有明显提高。

请注意,结果还将取决于稀疏矩阵的密度。