4. 特征工程基础:缺失值与异常值处理
在风控建模中,原始数据几乎不可能完美无缺。缺失值会破坏模型输入完整性,异常值则会扭曲统计分布、拉偏决策边界。本章聚焦两类最基础也最核心的特征工程操作:缺失值处理与异常值检测与处理,为后续特征分层与模型训练打下干净、可靠的数据基础。
4.1 缺失值处理
缺失值产生原因包括用户未填写、数据采集故障、字段不适用等。处理前需先区分缺失机制:
- 完全随机缺失(MCAR):缺失与数据本身无关,可直接删除或简单填充。
- 随机缺失(MAR):缺失与其他观测变量相关,适合用模型预测填充。
- 非随机缺失(MNAR):缺失与缺失值本身相关,处理最复杂,需结合业务逻辑。
4.1.1 均值/中位数/众数填充
这是最快速、最常用的填充方法,适用于不同数据分布类型:
| 填充方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 均值填充 | 数值型特征,数据近似正态分布 | 计算简单,保持整体均值不变 | 受异常值影响大,会降低方差 |
| 中位数填充 | 数值型特征,数据偏态分布或含异常值 | 稳健,不受极端值干扰 | 忽略分布形状信息 |
| 众数填充 | 分类型特征(如婚姻状况、学历) | 保留类别分布比例 | 可能引入偏差,若众数占比过高会弱化特征区分度 |
风控实践建议:对于收入、年龄等常见数值特征,优先使用中位数填充,因为风控数据通常呈右偏分布(少数高收入群体拉高均值)。对于性别、地区等分类特征,使用众数填充,但需注意若缺失率超过 30%,建议单独编码“未知”类别。
4.1.2 模型预测填充
模型预测填充利用特征间的相关性,将缺失字段作为目标变量,用其他完整特征训练回归或分类模型进行预测。常用方法包括:
- 线性回归/逻辑回归:适用于线性关系较强的场景,可解释性好。
- KNN 填充:基于相似样本的均值或众数填充,适合局部结构明显的特征。
- 随机森林/梯度提升树:能捕捉非线性关系,对异常值稳健,是风控场景的首选。
模型预测填充流程:
1. 将数据分为完整样本(无缺失)和缺失样本。
2. 以缺失特征为
3. 用训练好的模型预测缺失样本的
4. 注意:需避免数据泄露,填充过程应在训练集内交叉验证进行。
1. 将数据分为完整样本(无缺失)和缺失样本。
2. 以缺失特征为
y,其他完整特征为 X,在完整样本上训练预测模型。3. 用训练好的模型预测缺失样本的
y 值,完成填充。4. 注意:需避免数据泄露,填充过程应在训练集内交叉验证进行。
# Python 示例:使用随机森林填充缺失值
from sklearn.ensemble import RandomForestRegressor
import pandas as pd
import numpy as np
def rf_impute(df, target_col, feature_cols):
"""随机森林填充缺失值"""
# 区分完整与缺失样本
complete = df[df[target_col].notna()]
missing = df[df[target_col].isna()]
if len(missing) == 0:
return df
# 训练模型
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(complete[feature_cols], complete[target_col])
# 预测并填充
df.loc[df[target_col].isna(), target_col] = rf.predict(missing[feature_cols])
return df
# 使用示例(假设 data 包含 'income' 和 'age', 'education' 等特征)
# data = rf_impute(data, 'income', ['age', 'education', 'work_years'])
注意:模型预测填充计算成本较高,且可能引入模型偏差。在风控建模中,建议仅对缺失率在 5%~30% 且与其他特征相关性较强的字段使用。缺失率过高时,模型预测结果不可靠,应优先考虑删除或单独编码。
4.2 异常值检测与处理
异常值(Outlier)是指显著偏离数据集中趋势的观测值。在风控场景中,异常值可能代表欺诈行为、数据录入错误或极端但真实的用户特征。处理不当会严重影响模型稳定性和区分度。
4.2.1 IQR(四分位距)法
IQR 法基于数据分布的分位数,不假设数据服从特定分布,适用于偏态数据。定义如下:
- Q1:第一四分位数(25% 分位数)
- Q3:第三四分位数(75% 分位数)
- IQR = Q3 - Q1
- 下界 = Q1 - 1.5 × IQR
- 上界 = Q3 + 1.5 × IQR
超出 [下界, 上界] 范围的值被视为异常值。对于极端异常,可使用 3 × IQR 作为更严格的阈值。
# Python 示例:IQR 异常值检测
import numpy as np
import pandas as pd
def detect_outliers_iqr(data, column, multiplier=1.5):
"""使用 IQR 方法检测异常值"""
Q1 = data[column].quantile(0.25)
Q3 = data[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - multiplier * IQR
upper_bound = Q3 + multiplier * IQR
outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]
return outliers, lower_bound, upper_bound
# 使用示例
# outliers, low, up = detect_outliers_iqr(df, 'loan_amount')
# print(f"检测到 {len(outliers)} 个异常值,范围: [{low:.2f}, {up:.2f}]")
4.2.2 Z-score 法
Z-score 法基于正态分布假设,通过计算每个数据点与均值的标准差倍数来识别异常值。公式为:
Z = (x - μ) / σ
通常认为 |Z| > 3 的数据点为异常值(对应正态分布 99.7% 置信区间外)。对于风控数据,也可使用更严格的 |Z| > 2.5 或更宽松的 |Z| > 3.5,取决于业务容忍度。
IQR vs Z-score 对比:
IQR 法:不依赖正态假设,对偏态数据稳健,适合收入、负债等长尾分布特征。
Z-score 法:依赖正态假设,对异常值本身敏感(均值和标准差会被异常值拉偏),适合近似正态的特征如年龄、信用分。
IQR 法:不依赖正态假设,对偏态数据稳健,适合收入、负债等长尾分布特征。
Z-score 法:依赖正态假设,对异常值本身敏感(均值和标准差会被异常值拉偏),适合近似正态的特征如年龄、信用分。
# Python 示例:Z-score 异常值检测
from scipy import stats
import numpy as np
def detect_outliers_zscore(data, column, threshold=3):
"""使用 Z-score 方法检测异常值"""
z_scores = np.abs(stats.zscore(data[column].dropna()))
outlier_indices = np.where(z_scores > threshold)[0]
outliers = data.iloc[outlier_indices]
return outliers, z_scores
# 使用示例
# outliers, z = detect_outliers_zscore(df, 'credit_score', threshold=3)
# print(f"检测到 {len(outliers)} 个异常值")
4.2.3 异常值处理策略
检测到异常值后,需根据业务含义和建模目标选择处理方式:
| 处理方式 | 适用场景 | 操作方法 | 风控注意事项 |
|---|---|---|---|
| 删除 | 明显的数据录入错误、采样噪声 | 直接删除异常行或替换为 NaN | 删除比例不宜超过 5%,否则会损失样本代表性 |
| 截尾(Winsorize) | 极端值真实存在但需控制影响 | 将异常值替换为上下界值(如 1% 和 99% 分位数) | 风控评分卡中常用,保留极端用户的排序信息 |
| 视为缺失 | 不确定异常值是否真实,保留后续填充机会 | 将异常值标记为 NaN,再用缺失值处理方法处理 | 适合与模型预测填充结合,减少信息损失 |
| 单独编码 | 异常值本身具有业务含义(如欺诈标记) | 创建二值特征“是否为异常值” | 风控中强烈推荐,异常值可能蕴含高风险信号 |
4.3 本章小结
- 缺失值处理:根据缺失率和数据分布选择均值/中位数/众数填充或模型预测填充,注意避免数据泄露。
- 异常值检测:IQR 法适合偏态数据,Z-score 法适合正态数据,两者可结合使用。
- 异常值处理:删除、截尾、视为缺失、单独编码四种策略,风控场景中推荐截尾和单独编码。
- 工程实践:所有填充和检测操作都应在训练集上拟合参数,再应用到验证集和测试集,避免未来信息泄露。
进阶提示:在风控建模中,缺失值和异常值本身可能就是重要特征。建议创建“是否缺失”和“是否异常”的二值特征作为模型输入,往往能提升模型对风险模式的捕捉能力。