Python Scipy稀疏矩阵求幂:a**16比a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a慢?

Python Scipy稀疏矩阵求幂:a**16比a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a慢?,python,scipy,sparse-matrix,Python,Scipy,Sparse Matrix,我正在使用scipy-0.17进行一个简单的稀疏矩阵求幂,a**16。(注意,不是元素乘法)。然而,在我的机器上(运行Debian stable和Ubuntu LTS),这比使用for循环或做一些愚蠢的事情(如a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a)慢十倍。这没有道理,所以我想我做错了什么,但是什么 import scipy.sparse from time import time a=scipy.sparse.rand(2049,2049,.002) print

我正在使用scipy-0.17进行一个简单的稀疏矩阵求幂,
a**16
。(注意,不是元素乘法)。然而,在我的机器上(运行Debian stable和Ubuntu LTS),这比使用for循环或做一些愚蠢的事情(如
a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
)慢十倍。这没有道理,所以我想我做错了什么,但是什么

import scipy.sparse
from time import time

a=scipy.sparse.rand(2049,2049,.002)

print ("Trying exponentiation (a**16)")
t=time()
x=a**16
print (repr(x))
print ("Exponentiation took %f seconds\n" % (time()-t))

print ("Trying expansion (a*a*a*...*a*a)")
t=time()
y=a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
print (repr(y))
print ("Expansion took %f seconds\n" % (time()-t))

print ("Trying a for loop (z=z*a)")
t=time()
z=scipy.sparse.eye(2049)
for i in range(16):
    z=z*a
print (repr(z))
print ("Looping took %f seconds\n" % (time()-t))

# Sanity check, all approximately the same answer, right? 
assert (abs(x-z)>=1e-9).nnz==0
assert (abs(x-y)>=1e-9).nnz==0

@hpaulj关于非零数量的评论很重要。 在计算
a的高次幂时,非零元素的数量
增加。对于稀疏矩阵,计算矩阵的时间
乘积随着非零元素的数量增加而增加

用于计算**16
的算法实际上是:

a2 = a*a
a4 = a2*a2
a8 = a4*a4
a16 = a8*a8
现在看看这些矩阵中非零元素的数量 对于
a=sparse.rand(20492049,0.002)

在上一个产品中,
a16=a8*a8
,因子为96%非零。计算 使用稀疏矩阵乘法的乘积速度很慢。 最后一步需要97%的时间来计算**16

另一方面,当计算
a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
时, 稀疏矩阵乘法执行15次,但仅执行一次 每种产品中的系数的百分比总是很小(0.002) 具有非零值,因此每个产品都可以合理执行 效率高

这表明可能存在计算乘积的最佳策略,平衡乘法的数量和因子的稀疏性。例如,计算
a2=a*a;a16=a2*a2*a2*a2*a2*a2*a2*a2*a2
a16=a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
快:

In [232]: %timeit a2 = a*a; a4 = a2*a2; a8 = a4*a4; a16 = a8*a8
14.4 s ± 199 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [233]: %timeit a16 = a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
1.77 s ± 4.78 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [234]: %timeit a2 = a*a; a16 = a2*a2*a2*a2*a2*a2*a2*a2
1.42 s ± 3.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

或者,因为您知道最终结果将是密集的,所以从一开始或在某个中间步骤切换到标准numpy数组,在该步骤中密集矩阵乘法比稀疏矩阵乘法更有效。

无法复制。在我的测试中,求幂运算更快。(另外,您打印的是结果的
\uuuu repr\uuuu
方法,而不是
repr
表示。)嗯,我想这对某人来说很好。你使用的是scipy-0.17吗?(顺便说一句,我会修正问题中的repr。我注意到我也忘了把abs放在健康检查中。这对我的问题来说都不重要,但如果它让人讨厌,我最好修正一下。)有了你的大矩阵大小,
a*,…
快了10倍。同样,对于这个矩阵,结果的非零项比开始时多400倍。结果是密集的。对于小矩阵,非零项的数量减少。这为
scipy.sparse
特性请求提供了坚实的基础。
In [232]: %timeit a2 = a*a; a4 = a2*a2; a8 = a4*a4; a16 = a8*a8
14.4 s ± 199 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [233]: %timeit a16 = a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a
1.77 s ± 4.78 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [234]: %timeit a2 = a*a; a16 = a2*a2*a2*a2*a2*a2*a2*a2
1.42 s ± 3.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)