1. 项目背景与核心挑战
在金融科技领域,信贷产品的快速迭代带来了一个普遍难题:新产品上线初期缺乏足够的历史数据,导致传统风控模型难以有效运作。这种"冷启动"场景下,我们通常面临三个核心挑战:
- 样本极度稀疏与不平衡:训练集可能只有几百条样本,其中违约样本占比往往低于5%
- 数据分布偏移:训练集与真实业务环境的数据分布存在显著差异
- 强可解释性需求:信贷决策需要透明可解释,不能是"黑箱"模型
以我们实际处理的案例为例,训练集仅500条样本,违约率2%(约10个正样本),而测试集规模达到2500条。这种极端的数据条件下,常规的机器学习方法往往表现不佳。
2. 特征工程:从原始数据到有效特征
2.1 变量分类与基础处理
我们将原始22维特征分为三类,分别采用不同的处理策略:
数值型连续变量(如income、credit_limit):
- 1%-99%缩尾处理抑制极端值
- 对数变换使分布接近正态
- 标准化统一量纲
数值型离散变量(如overdue_times):
- 保留原始值
- 新增零值标识特征(如overdue_times_is_zero)
分类型变量(如housing、purpose):
- 少量类别:独热编码
- 多类别(>10):目标编码
# 特征处理核心代码示例 class CustomPreprocessor(BaseEstimator, TransformerMixin): def __init__(self, cont_features, disc_features, cat_features): self.cont_features = cont_features self.disc_features = disc_features self.cat_features = cat_features self.scaler = StandardScaler() self.encoder = OneHotEncoder() def fit(self, X, y=None): # 计算连续变量的缩尾边界 for col in self.cont_features: lower = X[col].quantile(0.01) upper = X[col].quantile(0.99) self.winsor_bounds[col] = (lower, upper) # 拟合标准化器 self.scaler.fit(np.log1p(X[self.cont_features])) return self def transform(self, X): # 应用缩尾和对数变换 X_cont = np.log1p(X[self.cont_features].clip( lower=self.winsor_bounds[col][0], upper=self.winsor_bounds[col][1] )) # 标准化 X_cont = self.scaler.transform(X_cont) # 离散变量处理 X_disc = X[self.disc_features] # 分类变量编码 X_cat = self.encoder.transform(X[self.cat_features]) return pd.concat([X_cont, X_disc, X_cat], axis=1)2.2 WOE编码与IV筛选
WOE(Weight of Evidence)编码是信用评分领域的经典技术,它将类别变量的每个取值映射为:
WOE = ln(好样本占比/坏样本占比)IV(Information Value)则量化特征的预测能力:
IV = Σ(好样本占比 - 坏样本占比) * WOE经验阈值:
- IV < 0.02:无预测力
- 0.02 ≤ IV < 0.1:弱预测力
- 0.1 ≤ IV < 0.3:中等预测力
- IV ≥ 0.3:强预测力
# WOE和IV计算实现 def calc_woe_iv(df, feature, target): total_good = df[target==0].shape[0] total_bad = df[target==1].shape[0] woe_dict = {} iv = 0 for value in df[feature].unique(): good = df[(df[feature]==value) & (df[target]==0)].shape[0] bad = df[(df[feature]==value) & (df[target]==1)].shape[0] p_good = (good + 0.5) / (total_good + 1) # 平滑处理 p_bad = (bad + 0.5) / (total_bad + 1) woe = np.log(p_good / p_bad) iv += (p_good - p_bad) * woe woe_dict[value] = woe return woe_dict, iv3. 样本不平衡处理策略
3.1 代价敏感学习
在逻辑回归中,通过class_weight参数调整类别权重:
model = LogisticRegression( class_weight={0:1, 1:10}, # 违约样本权重设为10倍 solver='liblinear' )3.2 采样方法对比
我们对比了多种采样策略:
| 方法 | 原理 | 适用场景 | 我们的测试结果 |
|---|---|---|---|
| SMOTE | 合成少数类样本 | 中等不平衡 | 验证集表现好,测试集泛化差 |
| ADASYN | 自适应合成样本 | 高度不平衡 | 同上 |
| 随机欠采样 | 减少多数类样本 | 数据量充足 | 丢失重要信息 |
| 代价敏感 | 调整损失函数权重 | 所有场景 | 最稳定可靠 |
实际经验:在极稀疏样本下(<5%正样本),代价敏感学习通常是最稳健的选择
4. 模型选择与优化
4.1 为什么选择逻辑回归
在对比了多种模型后,我们发现简单逻辑回归表现最好,原因在于:
- 样本量极小(10个正样本)时,复杂模型容易过拟合
- 逻辑回归的线性特性与信用评分的业务逻辑高度契合
- L1/L2正则化提供了天然的防过拟合机制
- 模型高度可解释,符合金融监管要求
4.2 参数调优
我们使用网格搜索优化逻辑回归参数:
param_grid = { 'penalty': ['l1', 'l2'], 'C': [0.01, 0.1, 1, 10], # 正则化强度倒数 'class_weight': [None, 'balanced'] } grid_search = GridSearchCV( LogisticRegression(solver='liblinear'), param_grid, scoring='roc_auc', cv=5 ) grid_search.fit(X_train, y_train)最佳参数组合通常是:
- penalty='l1'(稀疏特征选择)
- C=0.1(中等正则化强度)
- class_weight='balanced'(代价敏感)
5. 模型评估与业务解读
5.1 评估指标选择
在信贷风控中,我们更关注:
- 召回率(Recall):尽可能捕捉真正的违约客户
- KS统计量:模型区分好坏客户的能力
- AUC-ROC:整体排序能力
注意:精确率(Precision)在极低违约率场景下参考价值有限
5.2 阈值选择策略
通过PR曲线寻找最佳阈值:
precisions, recalls, thresholds = precision_recall_curve(y_true, y_pred_proba) f1_scores = 2 * (precisions * recalls) / (precisions + recalls) best_thresh = thresholds[np.argmax(f1_scores)]在实际业务中,我们通常会:
- 先基于业务成本确定可接受的误杀率
- 再选择能达到该误杀率下的最高召回率
6. 完整实现流程
6.1 端到端代码结构
# 1. 数据读取与探索 df = pd.read_csv('credit_data.csv') eda = EDAVisualizer() eda.plot_distributions(df) # 2. 特征工程 preprocessor = FeatureEngineer( cont_features=['income', 'credit_limit'], disc_features=['overdue_times'], cat_features=['purpose'] ) X_train_processed = preprocessor.fit_transform(X_train) # 3. WOE编码 woe_encoder = WOEEncoder() X_train_woe = woe_encoder.fit_transform(X_train_processed, y_train) # 4. 模型训练 model = LogisticRegression( penalty='l1', C=0.1, class_weight='balanced', solver='liblinear' ) model.fit(X_train_woe, y_train) # 5. 评估 evaluator = ModelEvaluator() evaluator.plot_roc_curve(y_test, model.predict_proba(X_test_woe)[:,1])6.2 实际应用建议
- 特征监控:定期检查特征分布漂移
- 模型迭代:随着数据积累逐步引入更复杂模型
- 规则引擎:结合业务规则提升决策鲁棒性
- 在线学习:对于快速变化的市场环境
7. 常见问题与解决方案
7.1 问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 模型AUC低 | 特征预测力不足 | 检查IV值,增加业务特征 |
| 召回率过低 | 样本极度不平衡 | 调整class_weight或采样策略 |
| 过拟合 | 样本量太小 | 加强正则化,简化模型 |
| 线上表现差 | 分布偏移 | 监控特征分布,定期更新模型 |
7.2 实用技巧
- 对于数值变量,先做缩尾处理再取对数,效果通常优于直接标准化
- 添加零值标识特征(如is_zero)往往能显著提升模型性能
- 在计算WOE时,加入平滑项(如+0.5)避免除零错误
- 使用分层交叉验证确保小样本场景下的可靠评估
8. 项目总结与延伸思考
这个项目展示了如何在极端数据约束下构建有效的信用风险模型。核心经验包括:
- 特征工程的质量决定模型上限
- 简单模型+精细处理 > 复杂模型+粗糙处理
- 业务理解比算法复杂度更重要
未来扩展方向:
- 增量学习:随着数据积累逐步更新模型
- 联邦学习:在保护隐私的前提下利用多方数据
- 因果推断:识别真正的风险驱动因素