如何基于最近n个非空值计算列的可变区间移动平均?
问题描述
我有如下格式的DataFrame:
| 日期时间 | 数值 | 移动平均(MA) |
|---|---|---|
| 1 Jan | 1 | None |
| 2 Jan | 2 | None |
| 3 Jan | 1 | None |
| 4 Jan | N/A | None |
| 5 Jan | 2 | None |
| 6 Jan | N/A | None |
| 7 Jan | N/A | None |
| 8 Jan | 3 | None |
需要计算「数值」列基于最近3个非空值的移动平均,期望输出如下:
| 日期时间 | 数值 | 移动平均(MA) |
|---|---|---|
| 1 Jan | 1 | 1 |
| 2 Jan | 2 | 1.5 |
| 3 Jan | 1 | 1.33 |
| 4 Jan | None | 1.33 |
| 5 Jan | 2 | 1.67 |
| 6 Jan | None | 1.67 |
| 7 Jan | None | 1.67 |
| 8 Jan | 3 | 2 |
注意:常规的rolling.mean()无法满足需求(它基于窗口位置而非非空值数量),且DataFrame数据量庞大,需避免循环,寻求最优解决方案。
解决方案
通过以下向量化步骤实现高效计算:
- 统一缺失值格式,让pandas正确识别:
import pandas as pd # 将字符串N/A替换为pandas标准缺失值 df = df.replace('N/A', pd.NA)
- 针对非空值计算滚动统计量:
# 提取非空数值并保留原始索引 non_null_vals = df['数值'].dropna() # 计算最近3个非空值的滚动和(不足3个时取现有值) rolling_sum = non_null_vals.rolling(window=3, min_periods=1).sum() # 计算最近3个非空值的滚动计数 rolling_count = non_null_vals.rolling(window=3, min_periods=1).count() # 得到非空位置的移动平均值 ma_non_null = rolling_sum / rolling_count
- 将结果映射回原DataFrame并填充空值行:
# 将计算结果对齐到原索引,空值位置用前向填充 df['移动平均(MA)'] = ma_non_null.reindex(df.index).ffill() # 可选:保留两位小数匹配期望输出格式 df['移动平均(MA)'] = df['移动平均(MA)'].round(2)
全程使用pandas内置向量化操作,无循环,处理大规模数据效率极高,完全符合需求。
内容的提问来源于stack exchange,提问作者Akav
相关产品推荐
相关产品推荐

