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 时间特征拆解框架

下图展示了从原始时间戳到三类特征(周期性、趋势性、事件性)的提取流程:

时间特征提取框架 原始时间戳 周期性特征 • 月份(1-12) • 星期几(0-6) • 日(1-31) • 季度(Q1-Q4) 趋势性特征 • 距今天数 • 距上次逾期天数 • 距最近还款天数 • 账户存续月数 事件性特征 • 是否节假日 • 是否月初/月末 • 是否发薪日前后 • 是否财报季 特征矩阵(输入模型)

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 坏账率预警基线模型。