发布于2026-07-19 阅读(0)
扫一扫,手机访问
在数据预处理中,用每列的均值填补缺失值(NaN),是一个既常见又稳妥的做法。虽然一行代码 df.apply(lambda x: x.fillna(x.mean()), axis=0) 就能搞定,但把它封装成一个可复用、易调试、可扩展的自定义函数,才更有工程价值,特别是当数据清洗流程需要反复执行或在不同项目间迁移时。
下面直接给出推荐的规范实现方式,以及它为什么比手动写循环更靠谱。
import pandas as pd
import numpy as np
def fill_nan_with_mean(df):
"""
将 DataFrame 中所有数值列的 NaN 值替换为对应列的均值。
自动跳过非数值列(如字符串、时间序列),避免报错。
Parameters:
df (pd.DataFrame): 输入 DataFrame
Returns:
pd.DataFrame: 原地修改后的 DataFrame(若需保留原 df,请先 df.copy())
"""
# 计算每列均值(仅对数值列有效,自动忽略非数值列)
column_means = df.select_dtypes(include=[np.number]).mean()
# 使用 fillna 批量填充:支持按列广播
df.fillna(column_means, inplace=True)
return df
使用示例:
# 示例数据
df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': ['x', 'y', 'z', 'w'] # 非数值列,将被自动忽略
})
fill_nan_with_mean(df)
print(df)
# 输出:
# A B C
# 0 1.0 5.0 x
# 1 2.0 6.5 y
# 2 2.3 7.0 z
# 3 4.0 8.0 w
有时候你只想处理某一列,或者需要单独验证该列的效果,这时候一个针对单列的函数就更方便。
def fill_nan_with_mean_single_column(df, column_name):
"""
对指定列用其均值填充 NaN。
Parameters:
df (pd.DataFrame): 输入 DataFrame
column_name (str): 待处理列名
Raises:
KeyError: 若列不存在
TypeError: 若该列不可计算均值(如全为字符串)
"""
if column_name not in df.columns:
raise KeyError(f"Column '{column_name}' not found in DataFrame.")
col_series = df[column_name]
if not np.issubdtype(col_series.dtype, np.number):
raise TypeError(f"Column '{column_name}' is not numeric; mean cannot be computed.")
mean_val = col_series.mean()
df[column_name].fillna(mean_val, inplace=True)
return df
很多初学者会尝试用 if x is None 来判断 NaN,再结合 axis=1 搞一个按行循环——这其实是两个坑。
pd.isna() 或 df.isna() 检测,if x is None 永远抓不到它。apply(..., axis=1) 时,x 代表一行,计算 x.mean() 得到的是该行的均值,而不是你想要的列均值。这是方向性错误。另外,Series.mean() 默认会跳过 NaN,只计算有效值的均值,这正是我们需要的逻辑,完全不需要手动写 if/else 分支去判断每个值是不是空。
函数写好了,但真正用到生产环境,有几个地方需要特别留意:
inplace=True 会直接改掉原始 DataFrame,如果后续流程需要回滚或对比,最好默认返回新 DataFrame,或者至少加个明确的注释说明。select_dtypes(include=[np.number]) 显式只处理数值列,能避免像时间戳、字符串列跳出来捣乱,报一个奇怪的 TypeError。.mean() 返回的还是 NaN,用这个 NaN 去 fillna(NaN) 等于没做。所以建议提前检查:if pd.isna(mean_val): raise ValueError(...),或者直接跳过该列。df.pipe(fill_nan_with_mean) 这种写法,函数一定要返回 df,而不是返回 None。否则链式调用会断掉。掌握了这个模式,你不仅能精准替换缺失值,还能顺着这个思路封装出中位数填充、众数填充、插值填充等更复杂的清洗函数。整个数据预处理流程,就会变得清晰、可控、可复用。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8