树模型在信贷风控怎么用——从决策树到 XGBoost

导语:评分卡解释性强,但抓不住复杂交叉。想提精度,就用树模型(XGBoost/LightGBM)。代价是:黑箱。

一、它解决什么问题

捕捉"收入中等 + 多头多 + 夜间活跃"这类非线性交叉风险,把 KS/AUC 往上提几个点。

二、原理(直觉)

  • 决策树:按"哪个变量切一刀最能分开好坏"递归分裂,直到纯净或到限制。
  • 集成(GBDT/XGBoost):训很多棵弱树,每棵修正前一棵的残差,加权求和。树多→拟合强。

三、信贷里怎么做

  1. 特征工程(行为/交易/征信/设备),不用先分箱(树自己切)。
  2. 训练:调 max_depth(树深,防过拟合)、learning_rate(小一点稳)、subsample(行采样)。
  3. 评估:KS、AUC,重点看**训练集 vs 验证集 vs 时间外样本(OOT)**是否一致。
  4. 可解释:用 SHAP 看每个变量贡献,或把树提取成规则给业务用。

四、代码骨架

python 复制代码
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
import xgboost as xgb
---------- 1. 数据准备 ----------
假设 df 已包含特征列和标签列 y(0=好客户,1=坏客户)
按时间切分:观察期样本用于训练/验证,表现期之后的样本作为 OOT
df_train_val = df[df["month"] <= "2024-06"]   # 观察期
df_oot = df[df["month"] > "2024-06"]          # 时间外样本(OOT)
features = ["income", "multi_loan_cnt", "night_active_ratio", "device_risk_score"]
X = df_train_val[features]
y = df_train_val["y"]
训练集 / 验证集(按时间顺序切,避免未来信息泄漏)
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
X_oot, y_oot = df_oot[features], df_oot["y"]
---------- 2. 参数设置 ----------
params = {
"max_depth": 4,          # 树深:控制模型复杂度,防止过拟合
"learning_rate": 0.05,   # 学习率:调小一点更稳,但需要更多树
"subsample": 0.8,        # 行采样:每棵树只用 80% 样本,增强泛化
"colsample_bytree": 0.8, # 列采样:每棵树只用 80% 特征
"eval_metric": "auc",
"objective": "binary:logistic",
"n_estimators": 500,
"early_stopping_rounds": 50,  # 验证集 AUC 连续 50 轮不提升则提前停止
}
---------- 3. 训练 ----------
model = xgb.XGBClassifier(**params)
model.fit(
X_train, y_train,
eval_set=[(X_val, y_val)],
verbose=False,
)
---------- 4. KS / AUC 评估 ----------
def ks_score(y_true, y_prob):
"""计算 KS 统计量:好坏样本累计分布的最大差距"""
df_ks = pd.DataFrame({"y": y_true, "prob": y_prob})
df_ks = df_ks.sort_values("prob", ascending=False).reset_index(drop=True)
df_ks["cum_bad"] = (df_ks["y"] == 1).cumsum() / (df_ks["y"] == 1).sum()
df_ks["cum_good"] = (df_ks["y"] == 0).cumsum() / (df_ks["y"] == 0).sum()
return (df_ks["cum_bad"] - df_ks["cum_good"]).abs().max()
for name, X_eval, y_eval in [
("训练集", X_train, y_train),
("验证集", X_val, y_val),
("OOT", X_oot, y_oot),
]:
prob = model.predict_proba(X_eval)[:, 1]
auc = roc_auc_score(y_eval, prob)
ks = ks_score(y_eval, prob)
print(f"{name}: AUC={auc:.4f}, KS={ks:.4f}")
重点:训练集 / 验证集 / OOT 的 KS、AUC 应基本一致,
若 OOT 明显下滑,说明存在过拟合或特征泄漏,需回查特征与切分逻辑。

五、常见坑

  • KS 虚高:特征里混进"未来信息"(如用了表现期才有的变量)→ 线上必崩。严格按观察/表现期切。
  • 过拟合:树太深,训练 KS 高、OOT 掉。看 OOT。
  • 黑箱难解释:监管/业务要理由,务必配 SHAP 或转规则。
  • 训练/线上不一致:特征的缺失、分箱逻辑上线要对齐。

六、小结

树模型提精度,但必须配可解释和 OOT 验证。评分卡管"稳",树模型管"准",实战常并用:树模型做主模型,评分卡做可解释备份/兜底。

相关推荐
wordbaby1 小时前
BM25 是什么?手把手拆解搜索引擎的核心算法
人工智能·算法
古少侠1 小时前
AI 内容粘到 Word 就乱?用 DS随心转 把复制的内容直接变成排版好的一段
人工智能·c#·word
浅安的邂逅1 小时前
260910-DeepSeek 发布 V4.1 Flash:1M 上下文、552B MoE,KV 缓存降到上一代 1/4,同步开源
人工智能·开源·ai大模型·deepseek·ai日报
海宇服务1 小时前
零信任架构实战:基于海宇柠檬查出险-登记证构建自动化二手车直卖合规网关
运维·人工智能·架构·自动化
长谷深风1111 小时前
Agent 跑了 30 分钟宕机,如何从断点继续?
java·大数据·人工智能·ai·大模型·memory·aiagent
Mr.朱鹏1 小时前
科技周报(第2026-09-10期):模型激战量子降温
人工智能·科技·chatgpt·机器人·开源
JAVA老架构AI智能化1 小时前
如何高质量分块
人工智能·python