熊猫如何计算引擎盖下的指数移动平均值?

时间:2018-10-12 16:20:17

标签: python arrays pandas time numba

我正在尝试将pandas EMA的性能与numba的性能进行比较。

一般来说,如果它们已经使用pandas内置,我不会编写函数,因为pandas总是比我慢速的手工编码python函数要快。例如quantilesort values等。我相信这是因为许多熊猫都是在C语言的幕后编写的,而且熊猫.apply()的方法比显式python for循环要快得多进行向量化(但是如果不正确,我可以公开说明)。但是在这里,对于计算EMA,我发现使用numba的性能远远优于熊猫。

我编写的EMA由定义

S_t = Y_1,t = 1

S_t = alpha * Y_t +(1-alpha)* S_ {t-1},t> 1

其中Y_t是时间t的时间序列的值,S_t是时间t的移动平均值的值,而alpha是平滑参数。

代码如下

from numba import jit
import pandas as pd
import numpy as np

@jit
def ewm(arr, alpha):
    """
    Calculate the EMA of an array arr
    :param arr: numpy array of floats
    :param alpha: float between 0 and 1
    :return: numpy array of floats
    """
    # initialise ewm_arr
    ewm_arr = np.zeros_like(arr)
    ewm_arr[0] = arr[0]
    for t in range(1,arr.shape[0]):
        ewm_arr[t] = alpha*arr[t] + (1 - alpha)*ewm_arr[t-1]

    return ewm_arr

# initialize array and dataframe randomly
a = np.random.random(10000)
df = pd.DataFrame(a)

%timeit df.ewm(com=0.5, adjust=False).mean()
>>> 1000 loops, best of 3: 1.77 ms per loop

%timeit ewm(a, 0.5)
>>> 10000 loops, best of 3: 34.8 µs per loop

我们看到,手动编码的ewm功能比熊猫ewm方法快50倍。

在某些情况下,numba也可能胜过其他各种熊猫方法,具体取决于一个人如何编码其功能。但是在这里,我对在计算指数移动平均值方面numba如何胜过大熊猫感兴趣。熊猫在做什么(不做什么)会使其变慢-还是在这种情况下numba变得非常快?熊猫如何计算引擎盖下的EMA?

1 个答案:

答案 0 :(得分:1)

  

但是在这里,我对numba在计算指数移动平均值方面如何胜过熊猫感到兴趣。

您的版本似乎更快,完全是因为您要向其传递NumPy数组而不是Pandas数据结构:

>>> s = pd.Series(np.random.random(10000))

>>> %timeit ewm(s, alpha=0.5)
82 ms ± 10.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>> %timeit ewm(s.values, alpha=0.5)
26 µs ± 193 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit s.ewm(alpha=0.5).mean()
852 µs ± 5.44 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

通常,比较NumPy和Pandas操作是从苹果到橘子。后者建立在前者的基础上,并且几乎总是以速度为代价来换取灵活性。 (但是,考虑到这一点,Pandas仍然非常快,并且随着时间的推移,它越来越依赖Cython ops。)我不确定numba / jit在NumPy中的表现会更好。但是,如果您使用Pandas系列比较这两种功能,Pandas本身就会更快地出现。

  

熊猫如何计算引擎盖下的EMA?

调用df.ewm()时(尚未调用.mean().cov()之类的方法),中间结果是在{{1 }}。

EWM

无论您通过pandas/core/window.py>>> ewm = pd.DataFrame().ewm(alpha=0.1) >>> type(ewm) <class 'pandas.core.window.EWM'> com还是span,熊猫都会map this back to a com并使用它。

当您调用方法本身时,例如halflife,它映射到._apply(),在这种情况下,它用作适当的Cython函数的router

alpha

ewm.mean()的情况下,cfunc = getattr(_window, func, None) 是“ ewma”。 .mean()是Cython模块pandas/libs/window.pyx

在功能ewma()上,这带您进入事情的核心,这是大部分工作的地方:

func

如果您想进行更公平的比较,请直接使用基础的NumPy值调用此函数:

_window

(请记住,它只需要一个com;为此,您可以使用pandas.core.window._get_center_of_mass()