程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何使用 Numba 有效地加速简单的移动平均计算大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_607_0@如何解决如何使用 numba 有效地加速简单的移动平均计算? 开发过程中遇到如何使用 numba 有效地加速简单的移动平均计算的问题如何解决?下面主要结合日常开发的经验,给出你关于如何使用 numba 有效地加速简单的移动平均计算的解决方法建议,希望对你解决如何使用 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,请注明来意。