4. 数据预处理:缺失值处理、异常值处理、类别变量编码、数据标准化/归一化
在额度定价漂移检测任务中,原始数据通常包含缺失值、异常值、非数值型类别特征以及量纲差异较大的数值特征。这些“脏数据”会直接影响漂移检测模型的稳定性和准确性。本章将系统讲解数据预处理的四个核心环节,确保输入模型的数据干净、规范、可比。
4.1 缺失值处理
缺失值在信贷数据中十分常见,例如客户收入字段未填写、历史额度字段为空等。处理策略需根据缺失比例和业务含义选择。
| 缺失比例 | 推荐策略 | 适用场景 |
|---|---|---|
| < 5% | 删除缺失行 | 样本量充足,缺失随机 |
| 5% – 30% | 均值/中位数/众数填充 | 数值型用中位数(抗异常值),类别型用众数 |
| 30% – 60% | 模型预测填充(KNN/回归) | 字段与其他特征相关性较强 |
| > 60% | 删除该特征列 | 信息量过低,保留反而引入噪声 |
实践建议:在额度定价场景中,收入字段缺失常采用中位数填充,避免极端值拉高均值;而“历史逾期天数”若缺失,可视为“无逾期”用 0 填充,但需单独标记缺失指示列。
import pandas as pd
import numpy as np
# 示例:中位数填充数值列,众数填充类别列
df['income'].fillna(df['income'].median(), inplace=True)
df['education'].fillna(df['education'].mode()[0], inplace=True)
# 标记缺失指示列
df['income_missing'] = df['income'].isna().astype(int)
4.2 异常值处理
异常值会扭曲统计分布,导致漂移检测产生误报。常用检测方法包括 IQR 规则和 Z-Score 方法。
- IQR 规则:定义 Q1 – 1.5×IQR 到 Q3 + 1.5×IQR 为正常范围,超出视为异常。
- Z-Score 方法:|Z| > 3 的样本视为异常(适用于近似正态分布)。
注意:在额度定价场景中,不要直接删除异常值。例如“年收入 500 万”对普通产品是异常,但对高端客户可能是真实值。建议先做业务研判,再决定截尾、替换或保留。
# IQR 方法检测异常值
Q1 = df['loan_amount'].quantile(0.25)
Q3 = df['loan_amount'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 将异常值替换为边界值(截尾处理)
df['loan_amount'] = df['loan_amount'].clip(lower_bound, upper_bound)
4.3 类别变量编码
机器学习模型无法直接处理文本型类别变量,需要转换为数值形式。不同编码方式适用于不同数据类型。
| 编码方式 | 适用变量 | 特点 |
|---|---|---|
| Label Encoding | 有序类别(如教育等级) | 保留顺序信息,但可能引入虚假大小关系 |
| One-Hot Encoding | 无序类别(如职业、地区) | 避免顺序假设,但维度膨胀 |
| Target Encoding | 高基数类别(如城市代码) | 用目标变量均值编码,需防过拟合 |
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
# Label Encoding 用于有序变量
le = LabelEncoder()
df['education_level'] = le.fit_transform(df['education'])
# One-Hot Encoding 用于无序变量
df = pd.get_dummies(df, columns=['occupation'], drop_first=True)
漂移检测特别提示:One-Hot 编码后,每个虚拟变量都会独立参与漂移检测。如果原始类别有 50 个,编码后会产生 49 列,建议先合并低频类别(如占比 < 1% 的归为“其他”),再编码。
4.4 数据标准化与归一化
标准化和归一化用于消除量纲影响,使不同尺度的特征在漂移检测中具有可比性。两者适用场景不同。
| 方法 | 公式 | 输出范围 | 适用场景 |
|---|---|---|---|
| Z-Score 标准化 | \( z = \frac{x - \mu}{\sigma} \) | 均值 0,标准差 1 | 数据近似正态分布,或使用距离度量 |
| Min-Max 归一化 | \( x' = \frac{x - min}{max - min} \) | [0, 1] | 数据有明确边界,或使用梯度下降算法 |
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Z-Score 标准化
scaler_std = StandardScaler()
df[['income', 'loan_amount']] = scaler_std.fit_transform(df[['income', 'loan_amount']])
# Min-Max 归一化
scaler_mm = MinMaxScaler()
df[['age', 'credit_score']] = scaler_mm.fit_transform(df[['age', 'credit_score']])
漂移检测场景建议:如果后续使用基于距离的漂移检测方法(如 MMD、KS 检验),推荐使用 Z-Score 标准化;如果使用基于分箱的 PSI 方法,Min-Max 归一化更便于分箱对齐。
4.5 数据预处理完整流程
下图展示了从原始数据到建模就绪数据的完整预处理流水线,四个环节按顺序执行,每个环节的输出作为下一环节的输入。
4.6 预处理前后对比示例
以下表格展示一条样本在预处理前后的变化,直观感受数据清洗的效果。
| 字段 | 原始值 | 处理后值 | 处理方式 |
|---|---|---|---|
| income | NaN | 58000.0 | 中位数填充 |
| loan_amount | 9999999 | 250000.0 | IQR 截尾 |
| education | 本科 | 2 | Label Encoding |
| occupation | 工程师 | [0, 0, 1, 0] | One-Hot Encoding |
| age | 45 | 0.52 | Min-Max 归一化 |
| credit_score | 720 | 0.68 | Z-Score 标准化 |
关键原则:预处理参数(填充值、边界值、缩放参数)必须在训练集上拟合,然后应用到验证集和测试集,避免数据泄露。建议使用
sklearn.pipeline.Pipeline 封装整个预处理流程。