共计 2491 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要更好的信贷风险评估方法
传统信贷风险评估常依赖逻辑回归,但它有个致命弱点——只能捕捉线性关系。现实中,收入与违约率可能是 U 型曲线(中产最稳定),而逻辑回归无法拟合这种模式。我曾见过一个案例:某银行用逻辑回归模型,结果误批了 23% 的高风险客户,就因为收入 - 年龄的交互效应没处理好。

决策树家族横向评测
信贷场景需要平衡准确性和可解释性,这是选型的关键:
- CART 决策树 :白盒模型,通过
max_depth=3就能生成业务人员能看懂的规则,适合风控评审会演示 - 随机森林:虽然准确率提升 2 -3%,但难以解释为什么拒绝某个客户,合规部门经常挑战
- XGBoost:在特征重要性评估上更精准,但部署依赖 lib 库,对有些银行的老系统不友好
实际项目中,我们先用 CART 快速验证特征有效性,再用 XGBoost 做最终模型,两者配合效果最佳。
从原始数据到可用模型
数据清洗实战技巧
# 处理缺失值:分类型特征用众数,连续型用中位数
from sklearn.impute import SimpleImputer
cat_imputer = SimpleImputer(strategy='most_frequent')
data[['education', 'job_type']] = cat_imputer.fit_transform(data[['education', 'job_type']])
num_imputer = SimpleImputer(strategy='median')
data[['income', 'debt_ratio']] = num_imputer.fit_transform(data[['income', 'debt_ratio']])
特征分箱的学问
等距分箱会害死模型!金融数据多为右偏分布,应该用分位数分箱:
# 使用 pandas 的 qcut 自动按样本量分箱
import pandas as pd
data['income_bin'] = pd.qcut(data['income'], q=5, labels=False, duplicates='drop')
WOE 编码让特征更听话
证据权重 (Weight of Evidence) 编码能把非线性关系转化为线性:
def woe_encoder(df, feature, target):
total_good = df[target].value_counts()[0]
total_bad = df[target].value_counts()[1]
woe_dict = {}
for category in df[feature].unique():
good = df[(df[feature]==category) & (df[target]==0)].shape[0]
bad = df[(df[feature]==category) & (df[target]==1)].shape[0]
# 防止除以 0
good_ratio = (good + 0.5) / (total_good + 1)
bad_ratio = (bad + 0.5) / (total_bad + 1)
woe = np.log(good_ratio / bad_ratio)
woe_dict[category] = woe
return df[feature].map(woe_dict)
调参不是玄学
决策树最关键的三个参数:
max_depth:从 3 开始尝试,每增加 1 层都要测试业务解释成本min_samples_leaf:建议设置≥总样本的 5%,防止过拟合ccp_alpha:成本复杂度剪枝参数,用下面方法找最优值:
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
params = {'ccp_alpha': [0.001, 0.01, 0.1]}
clf = GridSearchCV(DecisionTreeClassifier(), params, scoring='roc_auc')
clf.fit(X_train, y_train)
# 可视化剪枝效果
import matplotlib.pyplot as plt
plt.plot(clf.cv_results_['mean_test_score'], marker='o')
生产环境生存指南
处理类别不平衡的三板斧
- 样本层面:SMOTE 过采样(适合数据少时)
- 算法层面:class_weight=’balanced’(最省事)
- 评估层面:用 F1-score 代替准确率(业务更关注坏客户识别率)
严防特征泄露
时间穿越是最隐蔽的坑!一定要:
- 用
sklearn.pipeline封装所有预处理步骤 - 在特征工程阶段坚决不用未来信息(如用全年数据算均值)
- 部署时保存分箱边界和 WOE 映射表
可视化决策路径
用 graphviz 生成审批流程图,风控总监最爱看这个:
from sklearn.tree import export_graphviz
import graphviz
dot_data = export_graphviz(
clf,
feature_names=X.columns,
class_names=['Good', 'Bad'],
filled=True
)
graph = graphviz.Source(dot_data)
graph.render('loan_decision_tree') # 生成 PDF 文件
模型之后才是开始
当模型输出客户评分后,真正的挑战才开始:如何与业务规则联动?比如:
- 模型拒绝但人工想通过的案例怎么处理?
- 当国家突然调整 LPR 利率时,如何快速调整阈值?
- 反欺诈规则和信用评估模型谁先谁后?
建议开发一个决策引擎中间层,把模型分转化为可配置的规则链。我们现在的系统允许业务人员拖拽调整规则优先级,模型只是其中的一个决策节点。
写在最后
信贷风控没有银弹,CART 决策树的价值在于它像玻璃一样透明。当审批委员会质问 ” 为什么拒绝这个客户 ” 时,你能指着树状图说:” 看,因为这个人的收入在第三箱但负债率在第五箱,历史类似客户违约率达 67%”——这种解释力在金融行业比单纯的 AUC 值更重要。
正文完
