Pandas按匹配键用另一DataFrame中位数填充对应NaN值
Pandas按时间-行业分组中位数填充缺失值实现方案
iterrows()逐行遍历效率极低,且容易因类型转换、索引错位导致赋值异常,不要用循环方式处理这类分组匹配填充需求,以下是两种可直接运行的正确实现:
方案1:单步完成分组计算+填充(推荐,无需提前生成df2)
直接通过Pandas原生向量化的分组变换逻辑自动匹配分组,全程无手动对齐索引的成本,运行速度比逐行循环高1~2个数量级:
# 列出所有需要填充缺失值的数值指标列,排除分组键、ID、日期类非填充字段 target_cols = [ 'BookLeverage', 'Cash', 'RoE', 'ShareIss1Y', 'ShareIss5Y', 'SP', 'STreversal', 'Price', 'Size', 'ret' ] # 按yyyymm、industry_id分组,对每个指标列用同组中位数填充NaN df1[target_cols] = df1.groupby(['yyyymm', 'industry_id'])[target_cols].transform( lambda col: col.fillna(col.median()) )
如果存在某组某列全为NaN的极端情况,中位数也会返回空值,可以加一层全局中位数兜底:
df1[target_cols] = df1.groupby(['yyyymm', 'industry_id'])[target_cols].transform( lambda col: col.fillna(col.median() if not col.isna().all() else df1[col.name].median()) )
方案2:复用已提前计算好的df2中位数表填充
如果你已经生成了行索引为(yyyymm, industry_id)多层索引、列与待填充指标一一对应的df2,可以通过索引对齐的方式直接填充:
target_cols = [ 'BookLeverage', 'Cash', 'RoE', 'ShareIss1Y', 'ShareIss5Y', 'SP', 'STreversal', 'Price', 'Size', 'ret' ] # 将df1临时设置为和df2一致的多层索引,用于值对齐 df1 = df1.set_index(['yyyymm', 'industry_id']) # 用df2中对应位置的中位数填充df1的NaN值 df1[target_cols] = df1[target_cols].combine_first(df2[target_cols]) # 还原索引为普通列 df1 = df1.reset_index()
注意:使用该方案需要保证df2的多层索引层级顺序、字段数据类型和df1的
yyyymm、industry_id完全一致,且待填充列的列名和df1完全相同,否则会出现匹配失败、填充值错位的问题。
常见避坑提示
- 不要用
iterrows()/itertuples()逐行遍历做批量赋值:这类循环遍历方式会丢失字段原始数据类型,且遍历返回的是行数据的副本而非视图,直接赋值经常出现修改不生效、值错位的问题。 - 填充前先确认所有待填充列是数值类型,字符串、时间类型列计算中位数会直接报错。
- 填充完成后可以通过
df1[target_cols].isna().sum()抽查剩余空值情况,确认填充逻辑生效。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

