4. 缺失值处理:缺失值产生原因、统计缺失比例、常见填充策略
在坏样本归因任务中,缺失值不仅是数据质量问题,更可能隐藏着业务逻辑的断裂点。例如,用户“收入”字段缺失可能意味着该用户为无业或高风险群体。本章系统梳理缺失值的产生机制、量化评估方法以及三种主流填充策略,帮助你在 LightGBM 实战前完成高质量的数据清洗。
4.1 缺失值产生原因
理解缺失值的来源是选择填充策略的前提。根据缺失机制与业务场景,可将缺失原因归纳为以下四类:
| 类别 | 典型场景 | 示例 |
|---|---|---|
| 完全随机缺失(MCAR) | 系统故障、传输丢包、人为误删 | 某批次传感器数据因网络波动全部丢失 |
| 随机缺失(MAR) | 缺失概率与其他观测变量相关 | 女性用户更倾向于不填写“年龄”字段 |
| 非随机缺失(MNAR) | 缺失值本身与缺失原因直接相关 | 高逾期用户故意隐藏“负债率”数据 |
| 业务逻辑缺失 | 字段在特定条件下无意义 | 未婚用户无“配偶收入”字段 |
实战提示:在坏样本归因中,非随机缺失(MNAR)往往是最需要警惕的信号。例如,缺失“最近一次还款日期”的用户,其坏账率可能显著高于有记录的用户。建议在填充前先对缺失模式做分组统计,验证缺失是否与目标变量(坏样本标签)存在关联。
4.2 统计缺失比例
在决定填充策略前,必须量化每个特征的缺失严重程度。以下代码展示了如何快速计算缺失比例并可视化:
import pandas as pd
import numpy as np
def missing_stats(df):
"""计算缺失比例并排序"""
missing = df.isnull().sum()
missing_pct = (missing / len(df)) * 100
stats = pd.DataFrame({
'缺失数量': missing,
'缺失比例(%)': missing_pct
}).sort_values('缺失比例(%)', ascending=False)
return stats[stats['缺失数量'] > 0]
# 示例:假设 df 为原始数据集
stats_df = missing_stats(df)
print(stats_df.head(10))
根据缺失比例,通常将特征分为三个等级:
- 低缺失(< 5%):可直接删除或简单填充,对模型影响极小。
- 中缺失(5% - 30%):需要谨慎选择填充策略,建议尝试多种方法并交叉验证。
- 高缺失(> 30%):填充风险较高,优先考虑删除特征或构造“是否缺失”的指示变量。
避坑指南:不要仅依赖缺失比例做决策。一个缺失比例仅 2% 但与非随机缺失强相关的特征,其信息价值可能远高于一个缺失 20% 但完全随机的特征。务必结合业务含义和缺失机制综合判断。
4.3 常见填充策略
以下从简单到复杂,介绍三种最常用的填充策略,并给出适用场景与代码实现。
4.3.1 均值/中位数填充
这是最基础的填充方法,适用于数值型特征且数据分布相对对称的场景。
- 均值填充:适用于数据近似正态分布,无极端异常值。
- 中位数填充:适用于数据偏态分布或存在明显异常值。
# 均值填充
df['age_filled'] = df['age'].fillna(df['age'].mean())
# 中位数填充
df['income_filled'] = df['income'].fillna(df['income'].median())
效果对比:在坏样本数据中,“负债率”通常呈右偏分布(少数人负债极高),此时使用中位数填充比均值填充更能保持整体分布形态,避免引入偏差。
4.3.2 模型预测填充
利用其他特征作为输入,训练模型预测缺失值。这种方法能捕捉特征间的复杂关系,但计算成本较高,且需要避免数据泄露。
常用模型包括:
- 线性回归:适用于线性关系较强的数值特征。
- KNN:基于相似样本的加权平均,适合局部结构明显的场景。
- LightGBM:能处理非线性关系和类别特征,是实战中的首选。
from lightgbm import LGBMRegressor
from sklearn.model_selection import train_test_split
# 假设 'target_feature' 存在缺失,其他特征完整
train_data = df[df['target_feature'].notna()]
test_data = df[df['target_feature'].isna()]
X_train = train_data.drop(columns=['target_feature'])
y_train = train_data['target_feature']
X_test = test_data.drop(columns=['target_feature'])
model = LGBMRegressor(n_estimators=100, learning_rate=0.1)
model.fit(X_train, y_train)
# 预测并填充
predicted_values = model.predict(X_test)
df.loc[df['target_feature'].isna(), 'target_feature'] = predicted_values
关键注意:模型预测填充时,绝对不能将目标变量(坏样本标签)作为预测缺失值的输入特征,否则会造成严重的数据泄露,导致模型过拟合和评估结果虚高。
4.3.3 策略对比与选择
| 策略 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| 均值/中位数 | 简单快速,可解释性强 | 忽略特征间关系,可能引入偏差 | 低缺失比例、数据分布稳定 |
| 模型预测 | 利用多特征信息,精度高 | 计算成本高,需防数据泄露 | 中高缺失比例、特征间关联强 |
| 删除缺失行/列 | 完全避免填充误差 | 丢失样本或特征信息 | 缺失比例极低或极高(> 50%) |
实战建议:在 LightGBM 建模前,建议对每个缺失特征同时尝试均值填充和模型预测填充,并对比两种方案在验证集上的 AUC 或 KS 指标。LightGBM 原生支持缺失值处理(默认将缺失值分到增益最大的方向),但在坏样本归因场景中,主动填充往往比依赖模型内部处理更能保留业务语义。