代码之家  ›  专栏  ›  技术社区  ›  PyRsquared

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

  •  1
  • PyRsquared  · 技术社区  · 7 年前

    我想比较一下 pandas EMA 性能 numba 性能。

    一般来说,如果pandas已经内置了函数,我就不会编写函数,因为pandas总是比我手工编写的python函数快;例如 quantile , sort values 我相信这是因为大部分熊猫和熊猫都是用C编码的 .apply()

    这个 EMA 我已经编码了

    S\u t=Y\u 1,t=1

    其中Y\u t是时间t的时间序列值,S\u 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

    在这种情况下,numba的性能也可能优于其他各种pandas方法,这取决于如何编写它们的函数。但在这里,我感兴趣的是,在计算指数移动平均数方面,numba的表现如何优于pandas。熊猫在做什么(不做什么)使它变慢?或者说,在这种情况下,麻木只是非常快?熊猫如何计算引擎盖下的EMA?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Brad Solomon    7 年前

    但在这里,我感兴趣的是,在计算指数移动平均数方面,numba的表现如何优于Pandas。

    您的版本似乎更快,这仅仅是因为您向它传递的是一个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的运营是小巫见大巫。后者建立在前者之上,几乎总是以速度换取灵活性(但是,考虑到这一点,熊猫的速度还是很快的,而且随着时间的推移,它越来越依赖于Cython的操作。)我不确定具体是什么原因使得numba/jit在NumPy上表现得更好。但是如果你用一个Pandas系列来比较这两个函数,Pandas本身的速度会更快。

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

    当你打电话的时候 df.ewm() .mean() 或 .cov() ),中间结果是一个真正的类 EWM pandas/core/window.py .

    >>> ewm = pd.DataFrame().ewm(alpha=0.1)
    >>> type(ewm)
    <class 'pandas.core.window.EWM'>
    

    com , span halflife ,或 alpha ,熊猫会 map this back to a com

    当您调用方法本身时,例如 ewm.mean() ,此映射到 ._apply() ,在本例中用作 router 到相应的Cython函数:

    cfunc = getattr(_window, func, None)
    

    , func _window 是Cython模块 pandas/libs/window.pyx .

    这让你进入了事情的核心,在功能上 ewma() ,这是大部分工作发生的地方:

    weighted_avg = ((old_wt * weighted_avg) +
                    (new_wt * cur)) / (old_wt + new_wt)
    

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

    >>> from pandas._libs.window import ewma                                                                                                                 
    >>> %timeit ewma(s.values, 0.4, 0, 0, 0)                                                                                                                 
    513 µs ± 10.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

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