缺失值处理方法:常见策略及适用场景
说到缺失值,我脑子里立马跳出几年前的一个项目——当时接手一份用户行为日志,好家伙,整整 30% 的字段都是 NaN。第一次跑模型,结果 Loss 直接飞了,你说气不气。其实缺失值处理这事儿,没有万能钥匙,关键看数据长什么样、缺失是怎么来的。
我个人习惯先把缺失情况摸清楚:缺失多少?是随机丢失还是跟某个特征强相关?然后才动手。下面我把最常见的三种策略掰开讲,里面有不少我踩过的坑。
策略一:直接删除
最简单粗暴,但也是最容易翻车的一招。直接删掉带缺失值的行或列。
- 适用场景:缺失比例很小(比如 <5%),而且数据量够大。尤其是随机缺失(MCAR)时,删掉不会引入偏差。
- 避坑指南:我曾经在客户画像项目里,一口气删了 2% 的行,结果模型上线后对某一群用户预测全偏了——因为缺失值集中在高价值用户上,根本不是随机的。所以先做缺失模式分析,别偷懒。
import pandas as pd
# 删除任何含缺失值的行
df.dropna(inplace=True)
# 删除缺失比例超过50%的列
df.dropna(thresh=len(df)*0.5, axis=1, inplace=True)
策略二:均值/中位数/众数填充
这是大家最熟悉的招数。数值型用均值或中位数,类别型用众数。简单快,跑起来没负担。
- 适用场景:缺失比例在 5%~20% 之间,并且数据分布相对对称。如果偏态严重,中位数比均值更稳。
- 我个人的经验:房价数据集里,房间数缺失用中位数填充比均值效果好,因为少数豪宅把均值拉得太高了。还有一次做欺诈检测,交易金额字段偏态极重,我直接用中位数+噪声,反而保留了异常模式。
from sklearn.impute import SimpleImputer
# 均值填充
imputer_mean = SimpleImputer(strategy='mean')
df_filled = imputer_mean.fit_transform(df)
# 中位数填充
imputer_median = SimpleImputer(strategy='median')
df_filled = imputer_median.fit_transform(df)
策略三:插值与预测填充
这个有点技术含量了。它不是简单用一个统计量填,而是利用其他特征或时间顺序来“猜”缺失值。
线性插值
适合时间序列。比如股票数据某一天缺失,用前后两天平均一下。pandas 的 interpolate() 就能搞定。
df['price'].interpolate(method='linear', inplace=True)
KNN 填充
找跟该样本最相似的 k 个样本,用它们的均值或中位数填充。对于特征间关系较强的场景效果不错。
from sklearn.impute import KNNImputer
imputer_knn = KNNImputer(n_neighbors=5)
df_filled = imputer_knn.fit_transform(df)
回归/模型预测
把缺失列当目标变量,用其他完整列训练一个模型去预测。这个方法计算量大,但效果往往最好。
- 适用场景:缺失比例高(20%~50%),但其他特征能提供较强的预测信号。
- 我曾经踩过的坑:有一次用随机森林预测缺失值,但忘了把预测样本的标签也用到训练里,导致信息泄露,模型在验证集上虚高。记住:填充和建模的样本必须严格分开。
from sklearn.ensemble import RandomForestRegressor
# 假设 'target' 列有缺失,其他列完整
train = df[df['target'].notna()]
test = df[df['target'].isna()]
model = RandomForestRegressor()
model.fit(train.drop('target', axis=1), train['target'])
df.loc[test.index, 'target'] = model.predict(test.drop('target', axis=1))
方法对比速查
| 方法 | 适用缺失比例 | 计算开销 | 保留信息量 | 典型风险 |
|---|---|---|---|---|
| 删除 | <5% | 极低 | 低 | 非随机缺失导致偏差 |
| 均值填充 | 5%~20% | 低 | 中 | 降低方差,扭曲分布 |
| 插值/预测 | 20%~50% | 中高 | 高 | 过拟合、信息泄露 |
决策流程:我一般这样选
下面这张图是我自己画的一个精简流程,每次拿到缺失数据就先问自己这几个问题。
看到这张图你可能会想:“怎么每次都要判断是不是随机缺失?” 嗯,我年轻时也嫌麻烦,但吃了教训后就知道——缺失机制决定了后续处理会不会扭曲真实分布。比如付款金额总是缺失在高风险交易里,你直接填充均值,模型就学傻了。
一点总结
缺失值处理不是技术高低的问题,而是能不能与业务对齐的问题。我曾经在一个风控项目中,用中位数填充了所有缺失,结果把坏样本的特征拉成了正常样,模型召回率掉了 12 个点。后来换成 KNN 填充,才捡回来。
所以我的建议是:别把缺失值处理当成清理垃圾的杂活,它是特征工程的第一步,也是决定模型下限的一步。多花点时间了解数据,比乱调模型参数强一百倍。