首页 > 解决方案 > 在 Python 中,通过重用以前的计算来计算 EMA 的更快方法是什么?

问题描述

我一直在使用 TA-Lib 来计算 EMA,但每次我向数组添加一个新数字时,TA-Lib 都会再次从头开始计算。

我正在对一组相当大的数据(> 1M 行)进行分析,这很慢。

添加新值时,计算新 EMA 的最快方法是什么?

标签: pythonmoving-averageta-lib

解决方案


x为包含样本的长度向量n,即x[0], ..., x[n-1]。设y为包含 EMA 的向量。然后y由等式给出:

y[k] = y[k-1] * a + x[k] * (1-a)

EMA参数在哪里a,介于0和1之间。越接近1,曲线越平滑。

因此,要计算 EMA,您只需要:

a = 0.9
y[0] = x[0]
for k in range(1, n):
    y[k] = y[k-1]*a + x[k]*(1-a)

然后,如果您获得另一个样本,即x[n],您可以计算 EMAy[n]而无需使用以下方法进行完整计算:

y[n] = y[n-1]*a + x[n]*(1-a)

这是伪代码,所以如果你使用列表,它应该是这样的:

y.append(y[-1]*a + x[-1]*(1-a))

编辑:

如果您真的想提高计算 EMA(一次整个 EMA)的速度,您可以使用numba和 numpy:

import numpy as np
from numba import njit
from timeit import timeit

n=1000000
x_np = np.random.randn(n) # your data
x_list = list(x_np)
a = 0.9

def ema_list(x, a):
     y = [x[0]]
     for k in range(1, n):
          y.append(y[-1]*a + x[k]*(1-a))
     return y


@njit("float64[:](float64[:], float64)")
def ema_np(x, a):
     y = np.empty_like(x)
     y[0] = x[0]
     for k in range(1, n):
          y[k] = y[k-1]*a + x[k]*(1-a)
     return y


print(timeit(lambda: ema_list(x_list, a), number=1)) # 0.7080 seconds
print(timeit(lambda: ema_np(x_np, a), number=1)) # 0.008015 seconds

列表实现大约需要 708 毫秒,而 numba 和 numpy 需要 8 毫秒,大约快 88 倍。没有 numba 的 numpy 实现与列表实现所需的时间相似。


推荐阅读