4. 特征工程基础:数值型特征标准化、类别型特征编码、时间特征提取
在构建坏账率预警模型前,原始数据通常包含数值、类别、时间三种异构字段。特征工程的目标是将这些原始字段转换为 LightGBM 能够高效处理的数值矩阵。本章聚焦三类核心变换:数值型标准化、类别型编码、时间特征提取,并给出在风控场景下的选型建议。
💡 核心原则:LightGBM 对数值尺度不敏感(基于决策树),但标准化有助于梯度收敛与特征重要性排序;类别特征必须编码为数值;时间特征需拆解为周期性、趋势性与事件性分量。
4.1 数值型特征标准化
风控特征如“近6个月平均负债率”“历史最大逾期天数”等,量纲差异极大。标准化可消除量纲影响,提升模型训练稳定性。
| 方法 | 公式 | 适用场景 | 风控案例 |
|---|---|---|---|
| Z-score 标准化 | \( x' = \frac{x - \mu}{\sigma} \) | 数据近似正态分布,无极端离群点 | 收入、负债率、信用分 |
| Min-Max 归一化 | \( x' = \frac{x - x_{min}}{x_{max} - x_{min}} \) | 数据有明确上下界,需映射到 [0,1] | 年龄、授信额度占比 |
| Robust 标准化 | \( x' = \frac{x - median}{IQR} \) | 数据含离群点,需降低异常值影响 | 逾期金额、交易频次(长尾分布) |
| 分位数变换 | 映射到均匀分布或正态分布 | 分布严重偏态,需强制正态化 | 历史最大逾期天数(幂律分布) |
⚠️ 风控避坑:切勿在训练集与测试集上分别计算均值和标准差。必须使用训练集的统计量(μ, σ, min, max)对测试集进行变换,否则会造成数据泄露。
# 使用训练集统计量标准化测试集
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # 仅 transform,不 fit
4.2 类别型特征编码
风控数据中常见的类别特征包括:职业类型、学历、婚姻状况、地区编码、产品类型等。LightGBM 原生支持类别特征(需指定 categorical_feature 参数),但预处理阶段仍需将字符串映射为整数。
4.2.1 编码方法对比
| 编码方法 | 原理 | 维度变化 | 风控适用性 |
|---|---|---|---|
| Label Encoding | 将类别映射为 0,1,2,… | 1 列 | 有序类别(如学历:小学→0,中学→1,大学→2) |
| One-Hot Encoding | 每个类别生成一个二元列 | K 列(K 为类别数) | 无序类别且类别数较少(< 20) |
| Target Encoding | 用目标变量(坏账率)的均值替换类别 | 1 列 | 高基数类别(如地区编码、商户ID),需配合交叉验证防过拟合 |
| Count Encoding | 用类别出现频次替换 | 1 列 | 低频类别可能携带噪声,需平滑处理 |
📌 实战建议:对于 LightGBM,优先使用 Label Encoding + 指定
categorical_feature。LightGBM 内部会对整数类别做最优分箱,效果通常优于 One-Hot。高基数特征(如 1000+ 类)建议使用 Target Encoding 或 CatBoost 有序编码。
# LightGBM 原生类别特征处理
import lightgbm as lgb
# 假设 'occupation' 和 'region' 是类别特征
cat_cols = ['occupation', 'region']
# 先做 Label Encoding
from sklearn.preprocessing import LabelEncoder
for col in cat_cols:
le = LabelEncoder()
X_train[col] = le.fit_transform(X_train[col])
X_test[col] = le.transform(X_test[col])
# 训练时指定类别特征
train_data = lgb.Dataset(X_train, label=y_train, categorical_feature=cat_cols)
4.3 时间特征提取
风控数据中的时间字段(如申请日期、逾期发生日期、最近还款日期)不能直接作为数值输入,必须拆解为有业务含义的特征。
4.3.1 时间特征拆解框架
下图展示了从原始时间戳到三类特征(周期性、趋势性、事件性)的提取流程:
4.3.2 关键时间特征构造示例
import pandas as pd
import numpy as np
# 假设 df 包含 'apply_date' 列(申请日期)
df['apply_date'] = pd.to_datetime(df['apply_date'])
# 周期性特征
df['apply_month'] = df['apply_date'].dt.month
df['apply_weekday'] = df['apply_date'].dt.weekday
df['apply_day'] = df['apply_date'].dt.day
df['apply_quarter'] = df['apply_date'].dt.quarter
# 趋势性特征(以 '2025-01-01' 为参考日期)
ref_date = pd.Timestamp('2025-01-01')
df['days_since_ref'] = (ref_date - df['apply_date']).dt.days
# 事件性特征:是否在发薪日(假设每月10日、25日)
df['is_payday'] = df['apply_date'].dt.day.isin([10, 25]).astype(int)
# 距上次逾期天数(需先按用户排序)
df = df.sort_values(['user_id', 'apply_date'])
df['days_since_last_overdue'] = df.groupby('user_id')['overdue_flag'] \
.transform(lambda x: (x == 1).cumsum().shift(1)) # 简化示例
4.4 特征工程流水线整合
在实际项目中,建议将上述三类变换封装为统一的 Pipeline,确保训练与线上推理的一致性。
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, LabelEncoder
# 定义列类型
num_cols = ['income', 'debt_ratio', 'credit_score']
cat_cols = ['occupation', 'region']
time_cols = ['apply_date']
# 数值型标准化
num_transformer = Pipeline(steps=[
('scaler', StandardScaler())
])
# 类别型编码(Label Encoding + 指定 categorical_feature)
# 注意:LabelEncoder 需在 Pipeline 外先 fit,或使用自定义 Transformer
# 此处仅展示结构,实际需配合 FunctionTransformer
preprocessor = ColumnTransformer(
transformers=[
('num', num_transformer, num_cols),
# 类别和时间特征在外部预处理后直接传入
])
# 最终特征矩阵:数值标准化 + 类别整数编码 + 时间衍生特征
✅ 本章小结:数值型特征推荐 Robust 标准化(抗离群点);类别型特征优先 Label Encoding + LightGBM 原生支持;时间特征必须拆解为周期性、趋势性、事件性三类。下一章将基于处理后的特征矩阵,构建 LightGBM 坏账率预警基线模型。