缺失值有哪些处理方法?怎么选?
简化版
处理缺失值前,先判断缺失机制(完全随机 MCAR、随机 MAR、非随机 MNAR),再选方法。常见做法:删除(整行或整列,缺失少且随机时用,缺失多会丢信息);填充(数值用均值/中位数、类别用众数,简单但会低估方差、破坏相关性);模型预测填充(用其他特征建模预测缺失值,如 KNN、回归、MICE 多重插补,更准但更慢);当作一类(给缺失单独加一个「缺失标志」特征,因为缺失本身可能就是信号)。工业界常用组合:中位数/众数填充 + 加一个 is_missing 标志列。
详细版
主流方法及取舍:
| 方法 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 删除行 | 丢掉含缺失的样本 | 简单、不引偏差(若 MCAR) | 缺失多时大量丢样本 |
| 删除列 | 丢掉缺失率过高的特征 | 去掉几乎没信息的列 | 可能丢有用特征 |
| 均值/中位数填充 | 数值列用统计量填 | 快、稳定 | 低估方差、扭曲分布 |
| 众数填充 | 类别列用最频繁值填 | 简单 | 加剧类别不平衡 |
| 模型/KNN/MICE 填充 | 用其他特征预测缺失值 | 更准、保留关系 | 慢、复杂、可能泄露 |
| 缺失标志 + 填充 | 填充同时加 is_missing 列 | 保留「缺失即信号」 | 增维 |
| 让模型自己处理 | XGBoost/LightGBM 内建缺失方向 | 无需额外处理 | 仅部分模型支持 |
关键原则:
- 先看缺失机制:随机缺失可安全删除/填充;非随机缺失(缺失和目标相关)必须保留缺失信息。
- 填充统计量只能在训练集上算,套到测试集,防数据泄露。
- 缺失本身可能是特征:如「收入未填」的人可能有共性,加 is_missing 列往往涨点。
完整版教学
一、第一步永远是「先搞清为什么缺」——三种缺失机制
盲目填充是新手最大的错。要先判断缺失的机制,因为它决定了「删除/填充会不会引入偏差」:
- MCAR(完全随机缺失):缺不缺和任何变量都无关,纯随机(如仪器偶发故障丢数据)。此时删除或简单填充不会引入系统性偏差,最好处理。
- MAR(随机缺失):缺失概率和其他已观测特征有关,但和缺失值本身无关(如老年人更少填「收入」,但同龄同群体里填不填是随机的)。可以用其他特征来预测/填充,是模型填充的理论依据。
- MNAR(非随机缺失):缺失和缺失值本身有关(如高收入者故意不填收入)。这时缺失携带信息,简单删除或填充都会引入偏差,必须保留「是否缺失」这个信号。
面试高频追问「怎么处理缺失值」,答出「先判断缺失机制再决定方法」立刻和只会背「填均值」的人拉开档次。
二、删除法:简单但可能很贵
- 删行(listwise deletion):丢掉任何含缺失的样本。只有在缺失比例很小(如 <5%)且近似 MCAR 时才安全;否则会大量损失样本、甚至引入偏差(若删掉的样本有共性)。
- 删列:当某特征缺失率极高(如 >70%~80%)、几乎没有可用信息时,整列删掉更干脆。但要先确认这列不是关键特征——有时缺失率高的列,其「是否缺失」反而是强信号。
三、简单填充:快,但会悄悄扭曲数据
- 数值列:用均值或中位数填。有离群点或偏态时用中位数(更稳健),近似对称无离群点用均值。
- 类别列:用众数(最频繁类别)填。
代价(必须知道):
- 低估方差:把一堆缺失都填成同一个均值,人为制造了一个尖峰,数据方差被压小,后续基于方差的分析(如 PCA、置信区间)会失真。
- 破坏特征间相关性:填的值和其他特征无关,削弱了变量间的真实关系。
- 加剧类别不平衡:众数填充会让本就最多的类别更多。
所以简单填充是「快而糙」的方案,适合缺失少、要求不高的场景。
四、模型预测填充:更准,但更重
把「缺失值」当成要预测的目标,用其他特征来建模预测:
- KNN 填充:用特征空间里最近的 K 个邻居的值(均值/众数)填。
- 回归填充:用其他特征训练回归/分类模型预测缺失列。
- MICE(多重插补,Multiple Imputation by Chained Equations):迭代地用「其他所有特征」轮流预测每一个有缺失的特征,多轮收敛,还能生成多个插补数据集来反映填充的不确定性——统计上最严谨的方案之一。
优点:保留了特征间关系,填得更准。代价:慢、实现复杂、要小心数据泄露(填充模型不能用到测试集/目标变量),交叉验证时要放进 Pipeline 每折单独 fit。
五、把「缺失」当成信息——最实用的一招
很多真实场景里,「缺失」本身就是强信号(MNAR)。例子:贷款申请中「未填工资流水」的人违约率可能显著更高。这时如果你只是把它填成中位数,就抹掉了这个信号。
正确做法:填充的同时,额外加一个二值标志列 is_missing。
原始: income = [5000, NaN, 8000, NaN]
处理后:
income = [5000, 中位数, 8000, 中位数] ← 保证数值可用
income_missing= [0, 1, 0, 1] ← 保留「缺失」这个信号
这样模型既能用填充值,又能通过标志列学到「缺失与否」和目标的关系。工业界最常用的组合就是「中位数/众数填充 + is_missing 标志列」,简单且往往有效。
六、让模型自己处理缺失——树模型的特权
部分模型内建了缺失值处理,无需你手工填:
- XGBoost / LightGBM:训练时为每个分裂学习一个默认方向——遇到缺失值就走这个默认分支,相当于让模型自己学「缺失该归到哪边」。
- 因此用这类模型时,有时保留 NaN 交给模型比手工填充效果更好,还省事。
而线性模型、SVM、神经网络、KNN 不能直接吃 NaN,必须先填。
七、工程红线与常见坑
- 统计量只在训练集上算:均值/中位数/众数、KNN/回归填充模型,全部只用训练集拟合,再套到验证/测试集,否则数据泄露。
- 别在划分数据集之前全局填充——那是最隐蔽的泄露。
- 时间序列别用未来填过去:应前向填充(用之前的值)或插值,不能用整列均值(含未来信息)。
- 缺失值别用 0 乱填:0 在很多特征里是有意义的真实值(如「消费金额=0」),用 0 填 NaN 会污染语义。
八、用数字和工程流程校验理解
某列 1000 条记录缺失 20 条和缺失 800 条,处理策略不会相同。若收入缺失本身代表“用户拒绝填写”,仅用中位数填充会抹掉行为信号;常见做法是中位数填充再增加 income_missing 指示变量。
| 对象/方案 | 核心机制 | 选择或风险 |
|---|---|---|
| MCAR | 缺失与已观测/未观测值均无关 | 删除可能近似无偏但损失样本 |
| MAR | 缺失依赖已观测变量 | 条件建模或多重插补 |
| MNAR | 缺失依赖未观测值本身 | 需机制假设与敏感性分析 |
把面试题落到可执行流程:
audit missing pattern and timing
split data
fit imputer on training fold
transform + add indicator + monitor online
“模型能处理 NaN”不等于无需治理;训练与线上缺失语义、比例和默认分支必须一致。
九、常见误区与追问
- 误区:均值填充不会改变数据分布。 它压低方差、改变相关关系,并在大量缺失时制造人工峰值。
- 误区:缺失率高的特征一定要删除。 高缺失特征仍可能有强信号,需结合机制、稳定性和采集成本判断。
- 追问:为什么插补器只能在训练集 fit? 全量统计量包含验证和测试信息,会造成评估泄露。
- 追问:多重插补解决什么? 它生成多份合理插补以反映缺失不确定性,而不是把填充值当成确定事实。
- 追问:时间序列能直接前向填充吗? 只能使用预测时点之前的值,并限制间隔;反向填充通常会引入未来信息。
十、加强记忆
记忆时抓住这条主线:处理缺失值的正确顺序是先判机制、再选方法:MCAR(完全随机)可放心删/填;MAR(随机、和其他特征相关)适合模型/KNN/MICE 预测填充;MNAR(和缺失值本身相关,缺失即信号)必须保留 is_missing 标志。方法谱系:删除(缺失少且随机)、均值/中位数/众数填充(快但低估方差、破坏相关)、模型填充(准但慢、防泄露)、填充+缺失标志列(工业最常用)、XGBoost/LightGBM 自己处理缺失。三条红线:统计量只在训练集算防泄露、时序不用未来填过去、别拿 0 乱填。