如何在纽比加速循环?

2024-09-29 21:28:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我想加速这个代码:

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

数据如下:

^{pr2}$

for循环太慢,我能做些什么来加速这个代码?我能把整个操作矢量化吗?在


Tags: 代码importforasnpwheredownd1
2条回答

看起来你在试图计算指数移动平均数(滚动平均数),但忘记了除法。如果是这样的话,你可能想看看thisSO问题。同时,这里有一个快速的简单移动平均值,它使用来自被引用链接的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文档中:

The nditer will try to provide chunks that are as large as possible to the inner loop. By forcing ‘C’ and ‘F’ order, we get different external loop sizes. This mode is enabled by specifying an iterator flag.

Observe that with the default of keeping native memory order, the iterator is able to provide a single one-dimensional chunk, whereas when forcing Fortran order, it has to provide three chunks of two elements each.

^{pr2}$

简而言之,我认为这就是循环的作用:

upgain=np.array([.1,.2,.3,.4])    
u=[]
up=1
for x in upgain:                  
    u1=10*up+x
    u.append(u1)
    up=u1

制作:

^{pr2}$

这里有np.cumprod([10,10,10,10]),加上[.1,.2,.3,.4]项的修改后的cumsum。但是我不能马上想到一种将这些函数与编译的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)

dtype=object需求已在前面的SO中指出,并且https://github.com/numpy/numpy/issues/4155

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µs v 21µ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)(为避免溢出,较小的数字),5x速比仍然存在。在

相关问题 更多 >

    热门问题