Pandas的rolling接口能否实现带边缘处理的动态移动平均、std、max等函数
Pandas 原生 rolling 没有内置边缘填充参数,你可以通过以下两种方案实现符合要求的动态滑动计算:
方案1:手动填充+原生rolling实现(支持自定义所有滑动计算逻辑)
通过numpy提前对数据做边缘反射填充,配合rolling的center=True参数即可实现无偏移、全范围覆盖的计算,同时支持mean、std、max等所有滑动统计函数:
import pandas as pd import numpy as np def dynamic_rolling(series: pd.Series, window: int, func: str = "mean", pad_mode: str = "reflect") -> pd.Series: # 计算前后需要填充的长度 pad_len = window // 2 # 对原始数据做边缘填充 padded_vals = np.pad(series.values, pad_width=pad_len, mode=pad_mode) # 滑动计算,center=True保证结果无偏移 rolling_result = getattr(pd.Series(padded_vals).rolling(window=window, min_periods=window), func)() # 截取和原始数据长度一致的部分,保留原始索引 return pd.Series( rolling_result.values[pad_len : pad_len + len(series)], index=series.index, name=series.name )
使用示例:
# 动态移动平均 dynamic_avg = dynamic_rolling(pd_y, 200, func="mean") # 动态滑动标准差 dynamic_std = dynamic_rolling(pd_y, 200, func="std") # 动态滑动最大值 dynamic_max = dynamic_rolling(pd_y, 200, func="max")
方案2:封装scipy已实现逻辑(性能更高,适合大数据量)
scipy.ndimage的相关滤波函数已经优化了边缘处理逻辑,你可以直接封装为适配Pandas Series的函数,保留原始索引和名称:
from scipy.ndimage import filters def scipy_dynamic_avg(series: pd.Series, window: int) -> pd.Series: result = filters.uniform_filter1d(series.values, window, mode="reflect") return pd.Series(result, index=series.index, name=series.name)
替换你原代码中的moving_avg函数后,输出的结果就会和uniform_filter1d完全一致,不会出现偏移,也不会出现数据裁剪。
内容的提问来源于stack exchange,提问作者Drachen
相关产品推荐
相关产品推荐

