商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 如何用自定义函数将 DataFrame 中每列的 NaN 替换为该列均值

如何用自定义函数将 DataFrame 中每列的 NaN 替换为该列均值

  发布于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 搞一个按行循环——这其实是两个坑。

  • NaN 不等于 None:pandas 里的空值 NaN 用 pd.isna()df.isna() 检测,if x is None 永远抓不到它。
  • axis=1 按行走,均值却要按列算:用 apply(..., axis=1) 时,x 代表一行,计算 x.mean() 得到的是该行的均值,而不是你想要的列均值。这是方向性错误。

另外,Series.mean() 默认会跳过 NaN,只计算有效值的均值,这正是我们需要的逻辑,完全不需要手动写 if/else 分支去判断每个值是不是空。


⚠️ 注意事项与最佳实践

函数写好了,但真正用到生产环境,有几个地方需要特别留意:

  • 原地修改风险inplace=True 会直接改掉原始 DataFrame,如果后续流程需要回滚或对比,最好默认返回新 DataFrame,或者至少加个明确的注释说明。
  • 类型安全:用 select_dtypes(include=[np.number]) 显式只处理数值列,能避免像时间戳、字符串列跳出来捣乱,报一个奇怪的 TypeError。
  • 小心空列:如果某一列全部是 NaN,.mean() 返回的还是 NaN,用这个 NaN 去 fillna(NaN) 等于没做。所以建议提前检查:if pd.isna(mean_val): raise ValueError(...),或者直接跳过该列。
  • 链式调用兼容性:如果你的清洗流程喜欢用 df.pipe(fill_nan_with_mean) 这种写法,函数一定要返回 df,而不是返回 None。否则链式调用会断掉。

掌握了这个模式,你不仅能精准替换缺失值,还能顺着这个思路封装出中位数填充、众数填充、插值填充等更复杂的清洗函数。整个数据预处理流程,就会变得清晰、可控、可复用。

本文转载于:https://www.php.cn/faq/2318006.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注