大窗口下DataFrame高斯滚动平均过慢,能否用卷积优化?
高斯窗口滚动平均的提速方案
问题背景
用滚动窗口实现高斯加权平均时,小窗口表现正常,但大窗口下运行极慢甚至崩溃,现有代码如下:
import numpy as np import pandas as pd import matplotlib.pyplot as plt def norm_factor_Gauss_window(s, dt): numer = np.arange(-3*s, 3*s+dt, dt) multiplic_fac = np.exp(-(numer)**2/(2*s**2)) norm_factor = np.sum(multiplic_fac) window = len(multiplic_fac) return window, multiplic_fac, norm_factor # 构造测试数据 aa = np.sin(np.linspace(0,2*np.pi,1000000))+0.15*np.random.rand(1000000) df = pd.DataFrame({'x':aa}) hmany = 10 dt = 1 # 单位:秒 s = hmany*dt # 平均窗口大小,单位:秒 # 计算高斯窗口参数 window, multiplic_fac, norm_factor= norm_factor_Gauss_window(s, dt) # 原滚动加权平均实现 res2 =(1/norm_factor)*df.x.rolling(window, center=True).apply(lambda x: (x * multiplic_fac).sum(), raw=True, engine='numba', engine_kwargs= {'nopython': True, 'parallel': True}) # 绘图对比 plt.plot(df.x[0:2000]) plt.plot(res2[0:2000]) plt.show()
能不能用convolve解决?
完全可以,滚动加权平均本质就是信号与加权核的卷积操作。相比rolling.apply的逐窗口循环,卷积是向量级别的运算,效率提升非常明显,尤其是大窗口场景。
用numpy.convolve实现的替代代码:
# 注意:numpy.convolve是互相关操作,需要反转核来匹配原加权逻辑 reversed_kernel = multiplic_fac[::-1] # mode='same'保证输出长度与输入一致,对应原代码的center=True convolved = np.convolve(df.x.values, reversed_kernel, mode='same') # 归一化得到最终结果 res_convolve = convolved / norm_factor
如果窗口特别大(比如超过1e4),FFT加速卷积会更快,推荐用scipy.signal.fftconvolve:
from scipy.signal import fftconvolve convolved_fft = fftconvolve(df.x.values, reversed_kernel, mode='same') res_fft = convolved_fft / norm_factor
其他大窗口提速方法
- 抛弃pandas rolling.apply:哪怕用numba加速,逐窗口计算的开销依然远高于卷积,向量运算才是大数组处理的最优解
- 预归一化高斯核:直接在
norm_factor_Gauss_window里返回multiplic_fac / norm_factor,后续卷积后无需再做除法,减少重复计算 - 选择合适的卷积模式:如果不需要边界结果,用
mode='valid'可以减少计算量;需要和原序列对齐则用mode='same' - 内存优化:精度允许的话,用
float32代替float64存储数据和核,减少内存占用,提升计算速度 - 分块处理:当序列大到内存放不下时,可分块计算,每个块保留窗口大小的重叠部分,最后拼接结果,避免内存溢出
内容的提问来源于stack exchange,提问作者Jokerp
相关产品推荐
相关产品推荐

