ele*_*ora 4 python performance numpy cython
我有以下代码.原则上,它需要2 ^ 6*1000 = 64000次迭代,这是非常小的数字.然而,我的电脑需要9秒,我想至少运行n = 15.
from __future__ import division
import numpy as np
import itertools
n=6
iters = 1000
firstzero = 0
bothzero = 0
for S in itertools.product([-1,1], repeat = n+1):
for i in xrange(iters):
F = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = n)
while np.all(F ==0):
F = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = n)
FS = np.convolve(F,S, 'valid')
if (FS[0] == 0):
firstzero += 1
if np.all(FS==0):
bothzero += 1
print "firstzero", firstzero
print "bothzero", bothzero
Run Code Online (Sandbox Code Playgroud)
是否有可能加快这一速度或者我应该用C重写它?
分析表明它花费了大部分时间
258003 0.418 0.000 3.058 0.000 fromnumeric.py:1842(all)
130003 1.245 0.000 2.907 0.000 {method 'choice' of 'mtrand.RandomState' objects}
388006 2.488 0.000 2.488 0.000 {method 'reduce' of 'numpy.ufunc' objects}
128000 0.731 0.000 2.215 0.000 numeric.py:873(convolve)
258003 0.255 0.000 2.015 0.000 {method 'all' of 'numpy.ndarray' objects}
258003 0.301 0.000 1.760 0.000 _methods.py:35(_all)
130003 0.470 0.000 1.663 0.000 fromnumeric.py:2249(prod)
644044 1.483 0.000 1.483 0.000 {numpy.core.multiarray.array}
130003 0.164 0.000 1.193 0.000 _methods.py:27(_prod)
258003 0.283 0.000 0.624 0.000 numeric.py:462(asanyarray)
Run Code Online (Sandbox Code Playgroud)
几乎完全矢量化的代码版本要快得多(16.9%),假设您的代码名称为f():
def g():
n=6
iters = 1000
S=np.repeat(list(itertools.product([-1,1], repeat = n+1)),iters, axis=0).reshape((-1,n+1))
F=np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = (iters*(2**(n+2)),n)) #oversampling
F=F[~(F==0).all(1)][:iters*(2**(n+1))]
FS=np.asanyarray(map(lambda x, y: np.convolve(x, y, 'valid'), F, S))
firstzero=(FS[:,0]==0).sum()
bothzero=(FS==0).all(1).sum()
print "firstzero", firstzero
print "bothzero", bothzero
Run Code Online (Sandbox Code Playgroud)
时间结果:
In [164]:
%timeit f()
firstzero 27171
bothzero 12151
firstzero 27206
bothzero 12024
firstzero 27272
bothzero 12135
firstzero 27173
bothzero 12079
1 loops, best of 3: 14.6 s per loop
In [165]:
%timeit g()
firstzero 27182
bothzero 11952
firstzero 27365
bothzero 12174
firstzero 27318
bothzero 12173
firstzero 27377
bothzero 12072
1 loops, best of 3: 2.47 s per loop
Run Code Online (Sandbox Code Playgroud)
通过一次性生成所有随机选择,我很容易获得了 35-40% 的加速:
for S in itertools.product([-1,1], repeat = n+1):
Fx = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size=(iters,n))
for F in Fx:
Run Code Online (Sandbox Code Playgroud)
这取代了for i in xrange(iters)循环。
为了超越这一点,我怀疑您可以使用 scipy.signal.fftconvolve 对卷积本身进行矢量化(np.convolve 仅支持一维输入)。我没有尝试这个,部分原因是在我写这篇文章时 scipy.org 处于离线状态,但我希望这能让你继续下去。主要思想是减少您在 Python 中执行的循环,尽可能用矢量化操作替换它们。