我正在尝试将pandas EMA的性能与numba的性能进行比较。
一般来说,如果它们已经使用pandas内置,我不会编写函数,因为pandas总是比我慢速的手工编码python函数要快。例如quantile,sort 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?
答案 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()
。