我想加快这段代码:
import numpy as np
import pandas as pd
a = pd.read_csv(path)
closep = a['Clsprc']
delta = np.array(closep.diff())
upgain = np.where(delta >= 0, delta, 0)
downloss = np.where(delta <= 0, -delta, 0)
up = sum(upgain[0:14]) / 14
down = sum(downloss[0:14]) / 14
u = []
d = []
for x in np.nditer(upgain[14:]):
u1 = 13 * up + x
u.append(u1)
up = u1
for y in np.nditer(downloss[14:]):
d1 = 13 * down + y
d.append(d1)
down = d1
以下数据:
0 49.00
1 48.76
2 48.52
3 48.28
...
36785758 13.88
36785759 14.65
36785760 13.19
Name: Clsprc, Length: 36785759, dtype: float64
for循环太慢了,我该怎么做才能加快这段代码的速度?我可以对整个操作进行矢量化吗?
答案 0 :(得分:0)
看起来你正试图计算一个指数移动平均线(滚动平均值),但忘记了除法。如果是这种情况,那么您可能希望看到this SO问题。同时,这是一个快速的简单移动平均线,使用从引用链接获取的cumsum()
函数。
def moving_average(a, n=14) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n - 1:] / n
如果不是这种情况,并且您确实需要所描述的功能,则可以通过在迭代中使用external_loop
标志来提高迭代速度。从numpy文档:
nditer将尝试提供尽可能大的块 内循环。通过强制'C'和'F'顺序,我们会有所不同 外部循环大小。通过指定迭代器来启用此模式 标志。
观察默认情况下保持本机内存顺序, 迭代器能够提供单个一维块,而 当强制Fortran命令时,它必须提供三个两个块 每个元素。
for x in np.nditer(upgain[14:], flags=['external_loop'], order='F'):
# x now has x[0],x[1], x[2], x[3], x[4], x[5] elements.
答案 1 :(得分:0)
简单来说,我认为这就是循环正在做的事情:
upgain=np.array([.1,.2,.3,.4])
u=[]
up=1
for x in upgain:
u1=10*up+x
u.append(u1)
up=u1
制造
[10.1, 101.2, 1012.3, 10123.4]
np.cumprod([10,10,10,10])
已经存在,加上cumsum
条款的修改后的[.1,.2,.3,.4]
。但我不能想到将这些与编译的numpy
函数结合起来的方法。我们可以编写自定义ufunc
,并使用其accumulate
。或者我们可以在cython
(或其他c
接口)中编写它。
https://stackoverflow.com/a/27912352表明frompyfunc
是撰写广义accumulate
的一种方式。我不希望节省大量时间,也许是2倍。
要使用frompyfunc
,请定义:
def foo(x,y):return 10*x+y
循环应用程序(上面)将是
def loopfoo(upgain,u,u1):
for x in upgain:
u1=foo(u1,x)
u.append(u1)
return u
'矢量化'版本将是:
vfoo=np.frompyfunc(foo,2,1) # 2 in arg, 1 out
vfoo.accumulate(upgain,dtype=object).astype(float)
先前的SO和https://github.com/numpy/numpy/issues/4155
中注明了dtype=object
要求
In [1195]: loopfoo([1,.1,.2,.3,.4],[],0)
Out[1195]: [1, 10.1, 101.2, 1012.3, 10123.4]
In [1196]: vfoo.accumulate([1,.1,.2,.3,.4],dtype=object)
Out[1196]: array([1.0, 10.1, 101.2, 1012.3, 10123.4], dtype=object)
对于这个小清单,loopfoo
更快(3μsv21μs)
对于100个元素的数组,例如biggain=np.linspace(.1,1,100)
,vfoo.accumulate
更快:
In [1199]: timeit loopfoo(biggain,[],0)
1000 loops, best of 3: 281 µs per loop
In [1200]: timeit vfoo.accumulate(biggain,dtype=object)
10000 loops, best of 3: 57.4 µs per loop
对于更大的biggain=np.linspace(.001,.01,1000)
(更小的数字以避免溢出),5倍速比仍然存在。