Pandas 0.20.3中如何实现自定义权重的滚动计算?
如何在Pandas 0.20.3+中实现带自定义权重的滚动计算
你说得没错,pd.rolling_window早在Pandas 0.18版本就被标记为弃用,到0.20.3的时候已经彻底从库中移除了,所以现在得换用新的方式来实现你要的自定义权重滚动计算。下面我给你两种靠谱的解决方案,完全匹配你原来的需求:
方法1:用rolling.apply()自定义加权逻辑
这种方法最直观,完美复刻你原来的代码行为:
import pandas as pd import numpy as np # 初始化你的时间序列 ser = pd.Series([1,1,1], index=pd.date_range('1/1/2000', periods=3)) weights = [2,2,2] # 你的自定义权重数组 # 实现加权求和(对应原代码mean=False的情况) def weighted_sum(window): # 窗口长度不足时返回NaN,和原方法行为一致 if len(window) != len(weights): return np.nan return np.dot(window, weights) rm1 = ser.rolling(window=len(weights)).apply(weighted_sum, raw=True) print(rm1) # 输出和原rm1一致: # 2000-01-01 NaN # 2000-01-02 NaN # 2000-01-03 6.0 # Freq: D, dtype: float64 # 实现加权均值(对应原代码mean=True的情况) def weighted_mean(window): if len(window) != len(weights): return np.nan # 加权和除以权重总和得到均值 return np.dot(window, weights) / np.sum(weights) rm2 = ser.rolling(window=len(weights)).apply(weighted_mean, raw=True) print(rm2) # 输出和原rm2一致: # 2000-01-01 NaN # 2000-01-02 NaN # 2000-01-03 1.0 # Freq: D, dtype: float64
这里的raw=True很重要,它让传入window的是NumPy数组而非Pandas Series,能大幅提升计算效率,尤其是处理大数据集的时候。
方法2:用NumPy卷积实现(更高性能)
如果你的数据量比较大,卷积的方式会比apply()快很多——毕竟是向量化操作,避免了逐窗口的循环计算:
import pandas as pd import numpy as np ser = pd.Series([1,1,1], index=pd.date_range('1/1/2000', periods=3)) weights = [2,2,2] # 计算加权求和 conv_sum = np.convolve(ser, weights[::-1], mode='valid') # 生成结果Series,前面补NaN对齐原索引 rm1_conv = pd.Series( [np.nan]*(len(ser)-len(conv_sum)) + list(conv_sum), index=ser.index ) print(rm1_conv) # 计算加权均值 conv_mean = conv_sum / np.sum(weights) rm2_conv = pd.Series( [np.nan]*(len(ser)-len(conv_mean)) + list(conv_mean), index=ser.index ) print(rm2_conv)
这里需要注意两个点:
weights[::-1]是把权重数组反转,因为卷积的计算顺序是反向匹配窗口元素的,不反转的话结果会不符合你的预期;mode='valid'表示只保留窗口完全覆盖的结果,和原rolling_window中前面窗口返回NaN的行为一致。
额外说明
- 原
pd.rolling_window传入数组作为window时,本质就是指定窗口内每个元素的权重;而新的rolling对象的window参数只能是窗口长度(整数),所以必须通过自定义函数或卷积来应用权重。 - 如果你的权重是动态变化的(比如每个窗口用不同的权重数组),那只能用方法1;如果权重固定,方法2的性能优势会非常明显。
内容的提问来源于stack exchange,提问作者Make42
相关产品推荐
相关产品推荐

