
本文介绍一种简洁高效的方法:利用 groupby().transform() 结合众数计算,按指定分组列(如 col_b)为另一列(如 col_a)的 nan 值填充其所在组内的最频繁非空值,无需手动构建映射表。
在数据清洗中,按条件填充缺失值是常见需求。例如,当 col_A 存在缺失时,我们希望依据 col_B 的取值,将其替换为「该 col_B 类别下 col_A 出现频率最高的非空值」——即分组众数(group-wise mode)。Pandas 提供了优雅的向量化方案,完全避免循环、索引列表解析或中间 DataFrame 构建等冗余步骤。
核心思路是:对 col_A 按 col_B 分组后,使用 transform() 将每个组内计算出的众数广播回原长度,并通过 fillna() 完成就地填充。注意:Series.mode() 返回 Series(即使只有一个值),需用 .iloc[0] 提取标量;且需处理众数为空(如全 NaN 组)的边界情况。
以下是完整可运行示例:
import pandas as pd
import numpy as np
# 构造示例数据
df = pd.DataFrame({
'col_A': [8, 7, 20, np.nan, 8, 9, 37, np.nan, np.nan],
'col_B': [31, 30, 83, 5, 31, 34, 158, 5, 30]
})
# 定义填充函数:返回该组内 col_A 的众数填充结果
def impute_by_mode(series):
mode_vals = series.mode()
if not mode_vals.empty:
return series.fillna(mode_vals.iloc[0])
else:
return series # 无众数时保持原缺失(也可填 np.nan 或其他默认值)
# 应用分组填充(直接赋值到原列或新列)
df['col_A_filled'] = df.groupby('col_B')['col_A'].transform(impute_by_mode)
print(df)输出中,col_B == 5 对应的两行 col_A 缺失值将被统一填充为该组唯一非空值(即 20,若实际数据中 col_B==5 时 col_A 多次出现 1,则填 1);同理,col_B == 30 组若 7 出现最多,则所有该组缺失值均填 7。
⚠️ 注意事项:
- mode() 默认忽略 NaN,行为安全;
- 若某组所有 col_A 均为 NaN,则 mode() 返回空 Series,函数会保留原 NaN —— 可根据业务需要改为填充全局众数、中位数或抛出警告;
- transform() 保证返回与原组等长的结果,天然适配填充场景,无需对齐索引;
- 性能优于 apply() + 字典映射,尤其在大数据集上优势显著。
此方法兼具可读性、健壮性与执行效率,是 Pandas 分组填充缺失值的标准实践。










