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

Python 熊猫如何计算引擎盖下的指数移动平均数?,python,arrays,pandas,time,numba,Python,Arrays,Pandas,Time,Numba,我正在试着比较性能和性能 一般来说,如果函数已经内置了pandas,我就不会编写函数,因为pandas总是比我缓慢的手工编写的python函数快;例如,我相信这是因为很多pandas都是用C编写的,而且pandas.apply()方法由于矢量化的原因比显式python的循环速度快得多(但如果这不是真的,我愿意接受解释)。但在这里,为了计算EMA,我发现使用numba远远优于pandas 我所编码的代码定义为 S_t=Y_1,t=1 S_t=alpha*Y_t+(1-alpha)*S_{t-1},

我正在试着比较性能和性能

一般来说,如果函数已经内置了pandas,我就不会编写函数,因为pandas总是比我缓慢的手工编写的python函数快;例如,我相信这是因为很多pandas都是用C编写的,而且pandas
.apply()
方法由于矢量化的原因比显式python的循环速度快得多(但如果这不是真的,我愿意接受解释)。但在这里,为了计算EMA,我发现使用numba远远优于pandas

我所编码的代码定义为

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
函数的速度大约是pandas ewm方法的50倍

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

但在这里,我感兴趣的是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 ops。)我不确定numba/jit在NumPy中表现更好的具体原因是什么。但是如果你用Pandas系列比较这两个函数,Pandas本身的速度会更快

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

当您调用
df.ewm()
(尚未调用
.mean()
.cov()
等方法)时,中间结果是一个真正的类
ewm
,它位于
pandas/core/window.py

>>> ewm = pd.DataFrame().ewm(alpha=0.1)
>>> type(ewm)
<class 'pandas.core.window.EWM'>
.mean()
的情况下,
func
是“ewma”<代码>\u窗口是Cython模块

这就把你带到了活动的中心,也就是大部分工作发生的地方:

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
one不同。不确定这是否是速度差异的原因,但这是需要研究的。它们确实与
.ewm(半衰期=1…)匹配。)
而您的速度更快。总体答案可能是,对于这个问题,numba的速度更快,这对于将来的性能敏感问题是很好的。
>>> 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)