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

Posted

技术标签:

【中文标题】用于 numpy 数组和 scipy 稀疏矩阵的 Tensordot【英文标题】:Tensordot for numpy array and scipy sparse matrix 【发布时间】:2013-09-24 23:11:32 【问题描述】:

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

例如:

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

对于 numpy 数组,这很容易实现

Y = X.dot(A.T) 

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

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

【问题讨论】:

【参考方案1】:

显而易见的方法是在向量​​上运行一个循环并使用稀疏矩阵的.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方法,也就是说return是转置的,也就是说转置后最后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

【讨论】:

以上是关于用于 numpy 数组和 scipy 稀疏矩阵的 Tensordot的主要内容,如果未能解决你的问题,请参考以下文章

如何将 numpy.matrix 或数组转换为 scipy 稀疏矩阵

python使用scipy中的sparse.csr_matrix函数将numpy数组转化为稀疏矩阵(Create A Sparse Matrix)

用布尔数组索引 SciPy 稀疏矩阵

将稀疏 scipy 矩阵加载到现有的 numpy 密集矩阵中

为啥 scipy 的稀疏 csr_matrix 的向量点积比 numpy 的密集数组慢?

哪个 SciPy 稀疏矩阵类最适合计算距离矩阵?