如何在Pandas中按列分组生成滚动均值并递推填充NaN
按分组实现带NaN递推填充的滚动均值计算
原生的groupby().rolling(2).mean()无法满足需求——它只会用原始数据中的非NaN值计算均值,遇到NaN时不会用之前算出的滚动均值递推填充并继续计算。这种场景下,循环逐行处理每个分组是可行的解决方案。
示例实现
首先构造示例输入DataFrame:
import pandas as pd import numpy as np df = pd.DataFrame({ 'col2': ['A', 'A', 'A', 'A', 'B', 'B', 'B'], 'col3': [10, 20, np.nan, np.nan, 30, np.nan, 50] })
然后用循环实现递推逻辑:
# 初始化滚动均值列 df['rolling_mean'] = np.nan # 按col2分组遍历处理 for group_name, group_data in df.groupby('col2'): group_indices = group_data.index group_size = len(group_data) # 分组行数不足2,无法计算窗口2的均值,直接跳过 if group_size < 2: continue # 初始化分组第一个行的有效值 prev_value = group_data['col3'].iloc[0] # 处理分组第二个行 curr_value = group_data['col3'].iloc[1] # 若当前值为NaN,用分组第一个行的原始值填充(此时无历史均值) if pd.isna(curr_value): curr_value = prev_value # 计算第一个滚动均值 first_mean = (prev_value + curr_value) / 2 df.loc[group_indices[1], 'rolling_mean'] = first_mean # 维护递推所需的变量 prev_mean = first_mean prev_value = curr_value # 处理分组从第三个行开始的所有行 for i in range(2, group_size): curr_value = group_data['col3'].iloc[i] # 若当前值为NaN,用上一次的滚动均值填充 if pd.isna(curr_value): curr_value = prev_mean # 计算当前滚动均值 current_mean = (prev_value + curr_value) / 2 df.loc[group_indices[i], 'rolling_mean'] = current_mean # 更新变量,用于下一行递推 prev_value = curr_value prev_mean = current_mean
运行结果
| col2 | col3 | rolling_mean |
|---|---|---|
| A | 10.0 | NaN |
| A | 20.0 | 15.0 |
| A | NaN | 17.5 |
| A | NaN | 16.25 |
| B | 30.0 | NaN |
| B | NaN | 30.0 |
| B | 50.0 | 40.0 |
核心逻辑
- 对每个分组逐行处理,确保NaN值被**上一次计算出的滚动均值(或初始原始值)**填充后,再计算新的滚动均值
- 通过
prev_value和prev_mean两个变量,分别记录上一行的有效值(原始或填充后)和上一次的滚动均值,实现递推计算
内容的提问来源于stack exchange,提问作者AK91
相关产品推荐
相关产品推荐

