Tensordot用于numpy数组和scipy稀疏矩阵

时间:2013-09-19 18:05:42

标签: numpy matrix scipy sparse-matrix

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

例如:

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

对于numpy数组,使用

很容易实现
Y = X.dot(A.T) 

现在我想将A存储为稀疏矩阵,因为它是稀疏的,并且只包含非常有限数量的非零项,这会导致大量不必要的乘法。遗憾的是,由于numpy点不适用于稀疏矩阵,因此上述解决方案无效。据我所知,scipy稀疏没有类似数字的操作。

有人知道使用稀疏矩阵Y计算上述数组A的一种有效且有效的方法吗?

1 个答案:

答案 0 :(得分:3)

显而易见的方法是在矢量上运行循环并使用稀疏矩阵的.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方法,这意味着返回是转置的,这意味着在转置后,最后一个reshape将触发整个数组的副本。因此,对于相当大的IJ值,加上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