使用@
将稠密的numpy矩阵与稀疏的scipy向量相乘效率极低。似乎它根本没有利用向量的稀疏性。
说我们有
A = np.eye(5000)
x = np.eye(5000)[333]
x = scipy.sparse.coo_matrix(x).T # make it a sparse vector
然后使用@
进行乘法运算:
%timeit A @ x
8 ms ± 78.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
让我们自己编写一个极其糟糕的稀疏乘法:
def mult_dense_with_sparse(A, x):
return (A[:,x.nonzero()[0]] @ x.toarray()[x.nonzero()[0]]).T[0]
瞧瞧:
%timeit mult_dense_with_sparse(A, x)
50.3 µs ± 45.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
这快了很多!即使此实现首先通过再次添加所有零来创建密集向量,然后再次删除所有零...所以我想知道,如果不是@
,如何将密集的numpy矩阵与有效地稀疏向量向量?这样的基本操作肯定是scipy的一部分吗?
编辑:在其他问题中提供的解决方案没有帮助,因为它的效率与@
一样低:
%timeit scipy.sparse.csr_matrix.dot(A, x)
7.97 ms ± 113 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
在Responaw Hameer Abbasi中编辑2:
Line # Hits Time Per Hit % Time Line Contents
==============================================================
101 @profile
102 def ratio(self, n):
103 80 51.0 0.6 0.0 s = n + 1
104 80 11401854.0 142523.2 16.1 self.sfpc = self.scolPCA(s) # sparse first principal component
106 80 351898.0 4398.7 0.5 wSums = (self.signals[:,self.sfpc.nonzero()[0]] @ self.sfpc.toarray()[self.sfpc.nonzero()[0]]).T[0]
108 80 56487433.0 706092.9 79.7 wSums = self.sfpc.T.dot(self.signals.T)[0]
110 80 2521189.0 31514.9 3.6 self.Flag, self.threshold, self.incline, self.deltaVar = self.actFunctOpt(list(wSums))
111 80 160.0 2.0 0.0 return self.deltaVar / (2 + s)
在这里您可以看到我们的“ hack”花费了该功能约0.5%的时间,而使用dot
花费了该函数79.7%的时间。
答案 0 :(得分:1)
在您的示例中,A
的类型为np.ndarray
,而x
的类型为scipy.sparse.coo_matrix
。
如果您正在寻找最简单的答案来加快速度,则为:
import numpy as np
import scipy.sparse as sps
A = np.random.rand(5000, 5000)
v = np.zeros((5000, 1))
v[333] = 1
v_s = sps.csc_matrix(v)
%timeit v_s.T.dot(A).T # 46.6 µs ± 1.11 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit A @ v # 6.75 ms ± 29.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
但是,如果您想了解此答案的原理,则:当前,由于bug,运算符@
不支持NumPy数组的重载。另外,scipy.sparse.coo_matrix
甚至没有 try 来覆盖@
,并且scipy.sparse.csr_matrix
的矩阵乘法更快({{1}首先将转换为{ {1}}进行乘法运算。)
那么发生的是NumPy将您的稀疏矢量转换为NumPy数组,然后执行密集乘法。
但是,coo_matrix
存在并且支持与密集NumPy数组的乘法。因此,我们使用属性csr_matrix
以及csr_matrix.dot
产生A @ B = (B.T @ A.T).T
来产生上述优化代码的事实。