4、缺失值填充:fillna()方法、均值/中位数/众数填充、前向/后向填充

缺失值是数据清洗中最常见的“脏数据”之一。直接删除缺失行可能导致信息损失,而合理的填充策略能最大程度保留数据分布特征。本章系统讲解Pandas中 fillna() 的核心用法,以及三种统计填充与两种时序填充的适用场景。

核心原则:填充策略的选择取决于缺失机制(完全随机缺失、随机缺失、非随机缺失)与业务含义。数值型特征优先考虑均值/中位数;分类型特征优先考虑众数;时间序列数据优先考虑前向/后向填充。

4.1 fillna() 方法基础

fillna() 是Pandas中处理缺失值的核心方法,支持标量、字典、Series、DataFrame等多种填充方式。以下为常用参数说明:

参数 类型 说明 示例
value 标量/dict/Series/DataFrame 用于填充缺失值的值 fillna(0)
method 'ffill' / 'bfill' 前向填充或后向填充 fillna(method='ffill')
axis 0 或 1 填充方向:0=按行,1=按列 fillna(method='ffill', axis=1)
inplace bool 是否原地修改原DataFrame fillna(0, inplace=True)
limit int 连续填充的最大数量 fillna(method='ffill', limit=2)
import pandas as pd
import numpy as np

# 创建示例数据
df = pd.DataFrame({
    'A': [1, 2, np.nan, 4, 5],
    'B': [np.nan, 2, 3, np.nan, 5],
    'C': ['x', 'y', np.nan, 'y', 'z']
})

# 标量填充
df_filled = df.fillna(0)

# 按列字典填充
df_filled_dict = df.fillna({'A': df['A'].mean(), 'B': 0, 'C': 'unknown'})

print(df_filled_dict)

4.2 均值、中位数与众数填充

这三种统计填充是数值型与分类型特征最常用的策略。选择依据如下:

  • 均值填充:适用于数据近似正态分布、无极端异常值的场景。计算快,但会降低方差。
  • 中位数填充:适用于数据偏态分布或存在异常值的场景。对极端值不敏感,更稳健。
  • 众数填充:适用于分类型特征(如性别、城市)。用出现频率最高的类别填补缺失。
避坑提示:均值填充会人为拉低特征方差,可能导致后续模型(如线性回归)低估真实变异。若缺失率超过30%,建议将“是否缺失”作为独立特征加入模型,或使用更复杂的插补方法(如KNN、MICE)。
# 均值填充
df['A'] = df['A'].fillna(df['A'].mean())

# 中位数填充
df['B'] = df['B'].fillna(df['B'].median())

# 众数填充(分类型)
mode_value = df['C'].mode()[0]  # mode() 返回Series,取第一个
df['C'] = df['C'].fillna(mode_value)

print(df)
缺失值统计填充策略选择流程 统计填充策略选择流程图 检测到缺失值 特征类型判断 分类型特征 众数填充 数值型特征 分布形态判断 正态 → 均值填充 偏态 → 中位数填充

4.3 前向填充与后向填充

前向填充(Forward Fill)和后向填充(Backward Fill)是时间序列与有序数据中最常用的填充方式。它们利用相邻观测值来填补缺失,保持数据的时序连续性。

方法 Pandas参数 填充逻辑 典型场景
前向填充 method='ffill' 用上一个非缺失值填充当前缺失 传感器数据、股票价格、日志序列
后向填充 method='bfill' 用下一个非缺失值填充当前缺失 实验数据末尾缺失、反向插补
# 创建时间序列数据
ts_data = pd.Series(
    [100, np.nan, np.nan, 105, 107, np.nan, 110],
    index=pd.date_range('2024-01-01', periods=7, freq='D')
)

# 前向填充(默认)
ts_ffill = ts_data.fillna(method='ffill')
print("前向填充结果:")
print(ts_ffill)

# 后向填充
ts_bfill = ts_data.fillna(method='bfill')
print("\n后向填充结果:")
print(ts_bfill)

# 限制连续填充数量(最多填充2个连续缺失)
ts_ffill_limit = ts_data.fillna(method='ffill', limit=2)
print("\n限制连续填充2个:")
print(ts_ffill_limit)
实战建议:在金融时间序列中,前向填充通常比后向填充更合理(因为未来数据不可知)。对于连续缺失较多的序列,建议先检查缺失模式,再决定是否使用插值(interpolate())或模型预测填充。
前向填充与后向填充对比 前向填充 vs 后向填充对比 原始序列: 100 NaN NaN 105 107 NaN 110 前向填充: 100 100 100 105 107 107 110 后向填充: 100 105 105 105 107 110 110 前向填充:用上一个有效值填补缺失;后向填充:用下一个有效值填补缺失 limit参数可控制连续填充的最大步数,防止过度传播

4.4 填充策略对比与选择

不同填充策略对数据分布的影响差异显著。以下表格总结了各策略的优缺点与适用场景:

填充策略 优点 缺点 适用场景
均值填充 计算简单,保留整体均值 降低方差,扭曲分布形态 正态分布、低缺失率(<10%)
中位数填充 对异常值稳健 忽略分布尾部信息 偏态分布、存在异常值
众数填充 保持类别分布 可能引入偏差(多众数时) 分类型特征
前向填充 保持时序连续性 无法处理序列开头缺失 时间序列、有序数据
后向填充 利用未来信息填补 不适用于实时预测场景 实验数据、离线分析
进阶技巧:在实际项目中,建议对每个特征单独评估缺失模式,并采用“分组填充”策略。例如,按用户ID分组后,对组内时间序列使用前向填充;按城市分组后,对组内数值使用中位数填充。Pandas的 groupby() + transform() 可轻松实现:
df['value'] = df.groupby('city')['value'].transform(lambda x: x.fillna(x.median()))