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