稀疏矩阵上的按行外积

时间:2019-07-18 17:18:50

标签: python numpy matrix scipy sparse-matrix

给出两个稀疏的Scipy矩阵A, B,我想计算行外乘积。

我可以通过多种方式使用numpy进行此操作。最简单的也许是

np.einsum('ij,ik->ijk', A, B).reshape(n, -1)

(A[:, :, np.newaxis] * B[:, np.newaxis, :]).reshape(n, -1)

其中nAB中的行数。

但是,在我的情况下,经过密集的矩阵会占用过多的RAM。 因此,我发现的唯一选择是使用python循环:

sp.sparse.vstack((ra.T@rb).reshape(1,-1) for ra, rb in zip(A,B)).tocsr()

虽然使用较少的RAM,但是速度非常慢。

因此,我的问题是,是否存在一种稀疏(RAM高效)方式来获取两个矩阵的按行外积,从而使事物保持向量化?

(类似的问题是numpy elementwise outer product with sparse matrices,但所有答案都通过稠密矩阵。)

1 个答案:

答案 0 :(得分:3)

我们可以直接计算结果的csr表示形式。这不是超快的速度(在100,000x768上约为3秒),但可能还可以,具体取决于您的用例:

import numpy as np
import itertools
from scipy import sparse

def spouter(A,B):
    N,L = A.shape
    N,K = B.shape
    drows = zip(*(np.split(x.data,x.indptr[1:-1]) for x in (A,B)))
    data = [np.outer(a,b).ravel() for a,b in drows]
    irows = zip(*(np.split(x.indices,x.indptr[1:-1]) for x in (A,B)))
    indices = [np.ravel_multi_index(np.ix_(a,b),(L,K)).ravel() for a,b in irows]
    indptr = np.fromiter(itertools.chain((0,),map(len,indices)),int).cumsum()
    return sparse.csr_matrix((np.concatenate(data),np.concatenate(indices),indptr),(N,L*K))

A = sparse.random(100,768,0.03).tocsr()
B = sparse.random(100,768,0.03).tocsr()

print(np.all(np.einsum('ij,ik->ijk',A.A,B.A).reshape(100,-1) == spouter(A,B).A))

A = sparse.random(100000,768,0.03).tocsr()
B = sparse.random(100000,768,0.03).tocsr()

from time import time
T = time()
C = spouter(A,B)
print(time()-T)

样品运行:

True
3.1073222160339355