我正在使用python 3进行缓慢的numpy操作。
我有以下操作:
DocumentFile
其中
np.sum(np.log(X.T * b + a).T, 1)
我的问题是这个操作很慢(大约1.5秒),并且它在一个循环中,所以重复大约100次,这使我的代码的运行时间很长。
我想知道是否有更快的实现此功能。
也许有用的事实:X非常稀疏(只有0.08%的条目是非零的),但它是一个NumPy数组。
答案 0 :(得分:2)
我们可以优化对数运算,这似乎是瓶颈,并且作为超越函数之一可以用numexpr
module然后sum-reduce
和NumPy加速,因为NumPy做得更好,因此给我们一个混合的,像这样 -
import numexpr as ne
def numexpr_app(X, a, b):
XT = X.T
return ne.evaluate('log(XT * b + a)').sum(0)
仔细观察广播业务:XT * b + a
,我们看到有两个广播阶段,我们可以进一步优化。目的是看看是否可以将其缩减到一个阶段,这似乎可以通过某种划分来实现。这给了我们一个稍微修改过的版本,如下所示 -
def numexpr_app2(X, a, b):
ab = (a/b)
XT = X.T
return np.log(b).sum() + ne.evaluate('log(ab + XT)').sum(0)
运行时测试和验证
原创方法 -
def numpy_app(X, a, b):
return np.sum(np.log(X.T * b + a).T, 1)
计时 -
In [111]: # Setup inputs
...: density = 0.08/100 # 0.08 % sparse
...: m,n = 30000, 1000
...: X = scipy.sparse.rand(m,n,density=density,format="csr").toarray()
...: a = np.random.rand(n,1)
...: b = np.random.rand(n,1)
...:
In [112]: out0 = numpy_app(X, a, b)
...: out1 = numexpr_app(X, a, b)
...: out2 = numexpr_app2(X, a, b)
...: print np.allclose(out0, out1)
...: print np.allclose(out0, out2)
...:
True
True
In [114]: %timeit numpy_app(X, a, b)
1 loop, best of 3: 691 ms per loop
In [115]: %timeit numexpr_app(X, a, b)
10 loops, best of 3: 153 ms per loop
In [116]: %timeit numexpr_app2(X, a, b)
10 loops, best of 3: 149 ms per loop
只是为了证明开始时所说的观察log
部分是原始NumPy方法的瓶颈,这里有时间 -
In [44]: %timeit np.log(X.T * b + a)
1 loop, best of 3: 682 ms per loop
改善意义重大 -
In [120]: XT = X.T
In [121]: %timeit ne.evaluate('log(XT * b + a)')
10 loops, best of 3: 142 ms per loop
答案 1 :(得分:1)
有点不清楚为什么你会np.sum(your_array.T, axis=1)
代替np.sum(your_array, axis=0)
。
您可以使用scipy sparse matrix :(对X使用列压缩格式,以便X.T被行压缩,因为您乘以具有一行X.T形状的b)
X_sparse = scipy.sparse.csc_matrx(X)
并将X.T * b替换为:
X_sparse.T.multiply(b)
但是,如果a不稀疏,它将无法帮助你。
这些是我为此操作获得的加速:
In [16]: %timeit X_sparse.T.multiply(b)
The slowest run took 10.80 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 374 µs per loop
In [17]: %timeit X.T * b
10 loops, best of 3: 44.5 ms per loop
使用:
import numpy as np
from scipy import sparse
X = np.random.randn(30000, 1000)
a = np.random.randn(1000, 1)
b = np.random.randn(1000, 1)
X[X < 3] = 0
print(np.sum(X != 0))
X_sparse = sparse.csc_matrix(X)