【发布时间】:2016-02-22 09:07:52
【问题描述】:
我有一种情况,我需要从稀疏矩阵中提取单行,并用密集行获取其点积。使用 scipy 的 csr_matrix,这似乎比使用 numpy 的密集数组乘法要慢得多。这让我感到惊讶,因为我预计稀疏点积将涉及更少的操作。这是一个例子:
import timeit as ti
sparse_setup = 'import numpy as np; import scipy.sparse as si;' + \
'u = si.eye(10000).tocsr()[10];' + \
'v = np.random.randint(100, size=10000)'
dense_setup = 'import numpy as np; u = np.eye(10000)[10];' + \
'v = np.random.randint(100, size=10000)'
ti.timeit('u.dot(v)', setup=sparse_setup, number=100000)
2.788649031019304
ti.timeit('u.dot(v)', setup=dense_setup, number=100000)
2.179030169005273
对于矩阵向量乘法,稀疏表示很容易胜出,但在这种情况下并非如此。我尝试使用 csc_matrix,但性能更差:
>>> sparse_setup = 'import numpy as np; import scipy.sparse as si;' + \
... 'u = si.eye(10000).tocsc()[10];' + \
... 'v = np.random.randint(100, size=10000)'
>>> ti.timeit('u.dot(v)', setup=sparse_setup, number=100000)
7.0045155879925005
为什么在这种情况下 numpy 会击败 scipy.sparse?对于此类计算,是否有更快的矩阵格式?
【问题讨论】:
-
稀疏矩阵节省了内存,但在计算方面却更加复杂。
-
您如何计算“操作”?只是乘法和加法?或者您是否正在考虑索引、迭代等。在现代处理器上,将 2 个数字相乘并不是一项昂贵的操作。
dot也专门用于快速数值库。稀疏乘法也被编译,但不是使用相同的优化库。 -
为了清楚起见,您正在测试一个非常稀疏的向量(10000 个中的 1 个非零)乘以相同大小的密集向量。我认为它最终使用了
sparse._sparsetools.csr_matvec,一个编译函数。我必须查看 scipy github 才能进一步挖掘。 -
@hpaulj,我认为稀疏矩阵是行列值元组的集合。 k 元素稀疏行向量与 n 元素密集向量的点积应该只需要 O(k) 操作(常数因子高于密集),而密集乘法应该需要 O(n)。我会采纳你的好建议并阅读源代码。
-
当我改变
u(和密集等效项)中非零值的数量时,时间没有变化。(u.data * v[u.indices]).sum()更接近您想象的情况。它有点快,但它的时间仍然不是 O(k)。
标签: python numpy scipy sparse-matrix