numpy阵列的Tensordot和scipy稀疏矩阵

numpy阵列的Tensordot和scipy稀疏矩阵,numpy,matrix,scipy,sparse-matrix,Numpy,Matrix,Scipy,Sparse Matrix,对于当前的项目,我必须用相同的矩阵计算很多向量的内积(非常稀疏)。向量与二维网格相关联,因此我将向量存储在三维数组中: 例如: X是一个dim(I,J,N)数组。矩阵A的尺寸(N,N)。现在的任务是为i,j中的每个i,j计算A.dot(X[i,j]) 对于numpy阵列,使用 Y = X.dot(A.T) 现在我想将存储为稀疏矩阵,因为它是稀疏的,并且只包含非常有限的非零项,这会导致大量不必要的乘法。不幸的是,上面的解决方案不起作用,因为numpy点不适用于稀疏矩阵。据我所知,对于scipy

对于当前的项目,我必须用相同的矩阵计算很多向量的内积(非常稀疏)。向量与二维网格相关联,因此我将向量存储在三维数组中:

例如:

X
是一个dim
(I,J,N)
数组。矩阵
A
的尺寸
(N,N)
。现在的任务是为
i,j
中的每个
i,j
计算
A.dot(X[i,j])

对于numpy阵列,使用

Y = X.dot(A.T) 
现在我想将
存储为稀疏矩阵,因为它是稀疏的,并且只包含非常有限的非零项,这会导致大量不必要的乘法。不幸的是,上面的解决方案不起作用,因为numpy点不适用于稀疏矩阵。据我所知,对于scipy sparse,没有类似tensordot的操作


有人知道用稀疏矩阵
a
计算上述数组
Y
的好方法吗?

显而易见的方法是在向量上运行一个循环,并使用稀疏矩阵的
.dot
方法:

def naive_sps_x_dense_vecs(sps_mat, dense_vecs):
    rows, cols = sps_mat.shape
    I, J, _ = dense_vecs.shape
    out = np.empty((I, J, rows))
    for i in xrange(I):
        for j in xrange(J):
            out[i, j] = sps_mat.dot(dense_vecs[i, j])
    return out
但是,通过将3d数组重新调整为2d并避免Python循环,您可以稍微加快速度:

def sps_x_dense_vecs(sps_mat, dense_vecs):
    rows, cols = sps_mat.shape
    vecs_shape = dense_vecs.shape
    dense_vecs = dense_vecs.reshape(-1, cols)
    out = sps_mat.dot(dense_vecs.T).T
    return out.reshape(vecs.shape[:-1] + (rows,))
问题是我们需要将稀疏矩阵作为第一个参数,这样我们就可以调用它的
.dot
方法,这意味着返回被转置,这反过来意味着在转置之后,最后一次重新整形将触发整个数组的副本。因此,对于相当大的
I
J
,再加上不太大的
N
值,后一种方法将比前一种方法快几倍,但对于其他参数组合,性能甚至可能相反:

n, i, j = 100, 500, 500
a = sps.rand(n, n, density=1/n, format='csc')
vecs = np.random.rand(i, j, n)

>>> np.allclose(naive_sps_x_dense_vecs(a, vecs), sps_x_dense_vecs(a, vecs))
True

n, i, j = 100, 500, 500
%timeit naive_sps_x_dense_vecs(a, vecs)
1 loops, best of 3: 3.85 s per loop
%timeit sps_x_dense_vecs(a, vecs)
1 loops, best of 3: 576 ms per 

n, i, j = 1000, 200, 200
%timeit naive_sps_x_dense_vecs(a, vecs)
1 loops, best of 3: 791 ms per loop
%timeit sps_x_dense_vecs(a, vecs)
1 loops, best of 3: 1.3 s per loop