Pandas:如何按组填充NaN,仅当指定列含NaN时执行
解决Pandas分组填充缺失值的特定需求
初始DataFrame
| Account | Value | OtherColumn | Another Column | |
|---|---|---|---|---|
| 0 | A | 1.0 | 1.0 | 1.0 |
| 1 | A | NaN | NaN | NaN |
| 2 | A | NaN | NaN | NaN |
| 3 | A | 6.0 | NaN | NaN |
| 4 | A | NaN | NaN | NaN |
| 5 | B | 3.0 | 2.0 | NaN |
| 6 | B | NaN | NaN | NaN |
| 7 | B | 4.0 | NaN | NaN |
| 8 | B | NaN | NaN | NaN |
| 9 | C | NaN | NaN | NaN |
| 10 | C | 5.0 | 5.0 | NaN |
目标DataFrame
| Account | Value | OtherColumn | Another Column | |
|---|---|---|---|---|
| 0 | A | 1.0 | 1.0 | 1.0 |
| 1 | A | 1.0 | 1.0 | 1.0 |
| 2 | A | 1.0 | 1.0 | 1.0 |
| 3 | A | 6.0 | NaN | NaN |
| 4 | A | 6.0 | NaN | NaN |
| 5 | B | 3.0 | 2.0 | NaN |
| 6 | B | 3.0 | 2.0 | NaN |
| 7 | B | 4.0 | NaN | NaN |
| 8 | B | 4.0 | NaN | NaN |
| 9 | C | 5.0 | 5.0 | NaN |
| 10 | C | 5.0 | 5.0 | NaN |
需求说明
- 按
Account分组后结合ffill()和bfill()填充缺失值 - 条件1:若
Value列不为NaN,该行所有列保持原样,不填充 - 条件2:若
Value列为NaN,使用组内上方最近的Value非NaN行的值填充,同时反向填充处理前置NaN的情况
尝试的代码(不符合预期)
import numpy as np import pandas as pd data = {'Account': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C'], 'Value': [1.0, np.nan, np.nan, 6.0, np.nan, 3.0, np.nan, 4.0, np.nan, np.nan, 5.0], 'OtherColumn': [1.0, np.nan, np.nan, np.nan, np.nan, 2.0, np.nan, np.nan, np.nan, np.nan, 5.0], 'Another Column': [1.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]} df = pd.DataFrame(data) df_filled = df.groupby('Account').ffill().bfill() print(df_filled)
问题:部分非NaN行的其他列被误填充(如第3、4行的OtherColumn和Another Column被填充为1.0),不符合需求。
解决方案
核心思路是先标记出需要填充的行(Value为NaN的行),然后仅对这些行执行分组填充,最后将填充结果与原DataFrame合并。
import numpy as np import pandas as pd data = {'Account': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C'], 'Value': [1.0, np.nan, np.nan, 6.0, np.nan, 3.0, np.nan, 4.0, np.nan, np.nan, 5.0], 'OtherColumn': [1.0, np.nan, np.nan, np.nan, np.nan, 2.0, np.nan, np.nan, np.nan, np.nan, 5.0], 'Another Column': [1.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]} df = pd.DataFrame(data) # 1. 标记需要填充的行:Value为NaN的行 mask = df['Value'].isna() # 2. 对需要填充的行,按Account分组后先ffill再bfill filled_part = df[mask].groupby('Account').ffill().bfill() # 3. 合并原数据和填充后的数据:不需要填充的行保留原数据,需要填充的行用填充后的数据 df_result = df.copy() df_result.loc[mask] = filled_part # 验证结果 print(df_result)
代码解释
- 标记需要填充的行:用
mask筛选出Value为NaN的行,这些行是唯一需要填充的对象 - 分组填充:仅对筛选后的行执行分组
ffill()+bfill(),这样不会影响到Value非NaN的行的原始数据 - 合并数据:将填充后的部分替换回原DataFrame的对应行,保证非填充行的数据完全保留
运行后得到的结果与目标DataFrame一致,既满足了填充需求,又不会误修改Value非NaN行的其他列。
内容的提问来源于stack exchange,提问作者AlexR
相关产品推荐
相关产品推荐

