大佬教程收集整理的这篇文章主要介绍了如何使用 Numba 有效地加速简单的移动平均计算,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用 numba 来加速一些用于股票市场分析的简单迭代函数。我对 Pandas 或 Numpy 不感兴趣,我只是想了解无 python (@njit) 函数的方法。
这是一个简单的移动平均函数:
def sma_plain(src,p):
win = []
res = []
for n in src:
win.append(n)
if len(win) > p:
win = win[1:]
res.append(sum(win)/len(win))
return res
我可以立即知道我无法使用 numba 设置空的 win[] 和 res[] 列表。我尝试使用 numba 的 List(),但无法在函数内将其初始化为空。我尝试通过复制 src 作为输出开始,并使用 src 的一部分来实例化窗口(通过窗口我的意思是一组将被求和的值),但我的代码无法编译。同样在我的一次编译尝试中,与我的原始函数相比,timeit 产生的结果更慢。很可能是因为 sum() 不能使用。我在文档中看到的唯一示例是使用 gpuvectorization 和我不理解的语法。我对此不感兴趣,但我只想了解使用 numba for nopython 的过程。
我还创建了一个函数,它使用较小的窗口作为初始值,理想情况下我想在窗口尚未成熟时将 None 或 null 值写入列表,但似乎 numba 不允许空值。没关系,我想我可以在这种情况下简单地使用较短的列表,并在进行计算时跟踪偏移量,但如果能够跟踪空值,那就太好了。
这是我最后一次尝试,但它并不是真正有用,因为它无法编译。
@njit
def sma(src,p):
res = src.copy()
i = 0
length = len(srC)
while i < length:
win = src[max(0,i+1-p) : i+1]
win_length = len(win)
s = 0
for n in win:
s += n
s /= win_length
res[i] = s
return res
编辑: 我有一个编译函数,现在似乎允许 None 值。我不知道为什么它以前给我错误。所以现在我有以下类似的功能:
@njit
def sma(src,p):
slices = [src[i-p:i] for i in range(p,len(srC)+1)]
res = []
for slc in slices:
s = 0.0
for i in range(p):
s += slc[i]
res.append(s/p)
res = [None]*(p-1) + res
return res
def sma_plain(src,p):
win = []
res = []
for n in src:
win.append(n)
if len(win) > p:
win = win[1:]
if len(win) == p:
res.append(sum(win)/len(win))
else:
res.append(NonE)
return res
但是对于某些股票数据时间的 1000 次迭代,它报告 numba 函数为 39 秒,Python 函数为 7 秒。现在我想知道 numba 是否还能继续工作,因为它不会像以前那样为所有事情抛出错误。编译后的函数是否存在缓存问题导致它使用过时的版本之类的?
@H_607_0@解决方法只要你不想使用 Numpy,我就不推荐这个 ;-):
def sma_numpy_acc(a,p):
m = np.cumsum(a) / p
m[p:] -= m[:-p]
m[:p-1] = np.nan
return m
注意我使用 NaN 而不是 None,因为数组可以具有同构类型。
与原始函数相比的时序:
%timeit sma(a,p)
88.6 ms ± 1.58 ms per loop (mean ± std. dev. of 7 runs,10 loops each)
%timeit sma_plain(a,p)
2.18 s ± 65.1 ms per loop (mean ± std. dev. of 7 runs,1 loop each)
%timeit sma_numpy_acc(a,p)
3.95 ms ± 56.3 µs per loop (mean ± std. dev. of 7 runs,100 loops each)
可以通过 jitTing 函数稍微提高速度:
@nb.njit
def sma_numpy_acc_jit(a,p):
m = np.cumsum(a) / p
m[p:] = m[p:] - m[:-p] # Odd behavior of -= in numba
m[:p - 1] = np.nan
return m
%timeit sma_numpy_acc_jit(a,p)
3 ms ± 66.2 µs per loop (mean ± std. dev. of 7 runs,100 loops each)
使用累积和的相同想法,仍然使用 Numpy 数组,但不是 Numpy 函数:
@nb.njit
def sma_jit_acc(a,p):
acc = np.empty_like(a)
acc[0] = a[0]
n = len(a)
for i in range(1,n):
acc[i] = acc[i-1] + a[i]
for i in range(n-1,p-1,-1):
acc[i] = (acc[i] - acc[i-p]) / p
acc[p-1] /= p
for i in range(p-1):
acc[i] = np.nan
return acc
计时类似于纯 Numpy 函数。
%timeit sma_jit_acc(a,p)
3.69 ms ± 119 µs per loop (mean ± std. dev. of 7 runs,100 loops each)
使用列表的相同方法。没有 Numpy 的踪迹:
@nb.njit
def sma_jit_acc_lists(a,p):
n = len(a)
acc = [math.nan] * n
acc[0] = a[0]
for i in range(1,-1):
acc[i] = (acc[i] - acc[i-p]) / p
acc[p-1] /= p
return acc
使用列表会降低时间:
%timeit sma_jit_acc_lists(a,p)
24.2 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs,10 loops each)
以上是大佬教程为你收集整理的如何使用 Numba 有效地加速简单的移动平均计算全部内容,希望文章能够帮你解决如何使用 Numba 有效地加速简单的移动平均计算所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。