缺失值处理方法:常见策略及适用场景

说到缺失值,我脑子里立马跳出几年前的一个项目——当时接手一份用户行为日志,好家伙,整整 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% 中高 高 过拟合、信息泄露

决策流程:我一般这样选

下面这张图是我自己画的一个精简流程,每次拿到缺失数据就先问自己这几个问题。

缺失值处理决策流程 检查缺失比例与模式 是否随机缺失? 比例<5% → 删除 比例大 → 填充 均值/中位数填充 插值/模型预测 评估填充效果 💡 提示: 对时间序列优先插值, 对关系型数据用模型预测。

看到这张图你可能会想:“怎么每次都要判断是不是随机缺失?” 嗯,我年轻时也嫌麻烦,但吃了教训后就知道——缺失机制决定了后续处理会不会扭曲真实分布。比如付款金额总是缺失在高风险交易里,你直接填充均值,模型就学傻了。

一点总结

缺失值处理不是技术高低的问题,而是能不能与业务对齐的问题。我曾经在一个风控项目中,用中位数填充了所有缺失,结果把坏样本的特征拉成了正常样,模型召回率掉了 12 个点。后来换成 KNN 填充,才捡回来。

所以我的建议是:别把缺失值处理当成清理垃圾的杂活,它是特征工程的第一步,也是决定模型下限的一步。多花点时间了解数据,比乱调模型参数强一百倍。