熊猫:提高滚动窗口的速度(应用自定义功能)

时间:2019-04-22 16:24:23

标签: python performance dataframe median rolling-computation

我正在使用此代码通过滚动窗口在数据框中应用函数(funcX)。主要问题是此数据帧(data)的大小非常大,我正在寻找一种更快的方法来完成此任务。

import numpy as np

def funcX(x):
    x = np.sort(x)
    xd = np.delete(x, 25)
    med = np.median(xd)
    return (np.abs(x - med)).mean() + med

med_out = data.var1.rolling(window = 51, center = True).apply(funcX, raw = True)

使用此函数的唯一原因是,计算出的中位数是除去中间值后的中位数。因此,与在滚动窗口末尾添加.median()不同。

1 个答案:

答案 0 :(得分:5)

要有效,窗口算法必须链接两个重叠窗口的结果。

在这里,其中:med0的中位数,med的中位数,x \ med0xl之前的med元素和{{ {1}}在排序后的元素中,xg可以看成是:

med

因此,建议保留一个缓冲区,该缓冲区代表已排序的当前窗口funcX(x)<|x-med|> + med = [sum(xg) - sum(xl) - |med0-med|] / windowsize + med 。即时使用Numba进行编译,可以产生很好的性能。

首先进行缓冲区管理:

sum(xg)对第一个窗口进行排序,并计算left({sum(xl))和right(init)的总和。

xls

xgs是线性部分。它更新缓冲区,并保持其sorted。 import numpy as np import numba windowsize = 51 #odd, >1 halfsize = windowsize//2 @numba.njit def init(firstwindow): buffer = np.sort(firstwindow) xls = buffer[:halfsize].sum() xgs = buffer[-halfsize:].sum() return buffer,xls,xgs 计算shift中插入和删除的位置。由于np.searchsortedO(log(windowsize))并非对称情况,因此是技术性的。

xin<xout

xout<xin更新缓冲区和左右部分的总和。由于@numba.njit def shift(buffer,xin,xout): i_in = np.searchsorted(buffer,xin) i_out = np.searchsorted(buffer,xout) if xin <= xout : buffer[i_in+1:i_out+1] = buffer[i_in:i_out] buffer[i_in] = xin else: buffer[i_out:i_in-1] = buffer[i_out+1:i_in] buffer[i_in-1] = xin return i_in, i_out update并非对称情况,因此是技术性的。

xin<xout

xout<xin等同于缓冲区上的原始@numba.njit def update(buffer,xls,xgs,xin,xout): xl,x0,xg = buffer[halfsize-1:halfsize+2] i_in,i_out = shift(buffer,xin,xout) if i_out < halfsize: xls -= xout if i_in <= halfsize: xls += xin else: xls += x0 elif i_in < halfsize: xls += xin - xl if i_out > halfsize: xgs -= xout if i_in > halfsize: xgs += xin else: xgs += x0 elif i_in > halfsize+1: xgs += xin - xg return buffer, xls, xgs func

funcX

O(1)是全局函数。 @numba.njit def func(buffer,xls,xgs): med0 = buffer[halfsize] med = (buffer[halfsize-1] + buffer[halfsize+1])/2 if med0 > med: return (xgs-xls+med0-med) / windowsize + med else: return (xgs-xls+med-med0) / windowsize + med

med

性能:

O(data.size * windowsize)

速度快了250倍,窗口大小=51。一个小时变成15秒。