ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

定序回归做信用卡信用评级:Probit模型原理与Python实战

定序回归做信用卡信用评级:Probit模型原理与Python实战 简介这份PDF文档聚焦数据回归中的定序回归模型面向金融风控、信用评分方向的学习者与从业者帮助理解如何用统计建模方法解决信用卡持卡人信用评级与违约风险识别问题。资源共1个PDF文件压缩包约447KB内容为完整的论文式讲解涵盖信用评级对信用卡业务的重要性、数据集介绍与探索性分析、定序Probit模型原理、模型拟合、自变量选择及结论等章节并附参考文献与致谢。文档系统梳理了ordered probit回归在信用评级中的应用路径读者可借此掌握从数据探索到建模、再到影响因素筛选的完整分析框架理解信用记录如何量化为评级score以及如何识别持卡人违约的主要因素。目前已有323人学习适合作为信用评分入门与定序回归实战的参考材料。1. 定序回归做信用卡信用评级为什么它比二分类更贴近真实业务信用卡用户的信用评级绝大多数人第一反应是「好人/坏人」的二分类。但真实业务里评分卡从来不是一刀切——银行内部通常分成 AAA、AA、A、BBB、BB、B、CCC 这样的等级序列等级之间有明确的顺序却不能简单当成连续数值来回归。这就是定序回归Ordinal Regression要解决的问题因变量是有序多分类类别之间有大小关系但相邻等级之间的「距离」并不相等。把这个问题套到信用卡场景输入是用户的征信查询次数、账龄、额度使用率、逾期次数、收入负债比等特征输出是信用等级。用普通多分类 Softmax 会丢掉顺序信息用线性回归又会把等级当成等距数值两头都不讨好。定序回归的核心思路是假设存在一个不可观测的连续潜变量它由特征线性组合决定再通过一组阈值把潜变量切成有序的等级。Probit 和 Logit 是两种最常见的连接函数前者假设误差服从正态分布后者服从逻辑分布。这篇内容面向的是手里有信用卡用户数据、想搭一套可解释评级模型的工程师和风控从业者。我会把定序 Probit 的建模逻辑、参数估计、阈值解释、以及用 Python 或 MATLAB 复现的完整路径讲清楚中间穿插小样本场景下高斯过程回归和 RVM 多输出回归能借鉴的思路。读完你应该能自己跑通一套评级模型并知道哪些参数不能乱调、哪些坑一定会踩。2. 定序 Probit 模型的数学结构与参数含义2.1 潜变量框架为什么阈值才是模型的核心定序回归的经典表述是潜变量模型。设第 i 个用户的信用潜变量为 y_i^*它满足y_i^* x_i^T β ε_iε_i ~ N(0, 1)我们观测到的信用等级 y_i 取 1 到 K 之间的整数由潜变量落在哪个区间决定y_i k当 τ_{k-1} y_i^* ≤ τ_k其中 τ_0 -∞τ_K ∞中间的 τ_1 τ_2 ... τ_{K-1} 是待估阈值。这个结构的关键在于β 决定特征对信用好坏的方向和强度阈值决定各等级的分界位置。很多人第一次做定序回归把注意力全放在 β 上结果预测出来的等级分布严重偏斜问题往往出在阈值初始化上。Probit 和 Logit 的区别只在误差分布假设。Probit 用标准正态的累积分布函数 Φ(·)Logit 用逻辑函数。两者在系数上差一个约 1.6 到 1.8 的尺度因子实际排序能力差别不大。选 Probit 的常见理由是信用评分领域很多经典模型如 Z-Score 的变体默认正态假设且 Probit 的边际效应解释更直观——系数乘以标准正态密度就是概率的边际变化。2.2 极大似然估计与阈值约束的处理定序 Probit 的似然函数是L(β, τ) Π_i [Φ(τ_{y_i} - x_i^T β) - Φ(τ_{y_i-1} - x_i^T β)]取对数后用数值优化求解。这里有个必须处理的约束τ_1 τ_2 ... τ_{K-1}。直接优化容易让阈值交叉导致似然函数无意义。常见做法有两种一是重参数化令 τ_1 γ_1τ_k τ_{k-1} exp(γ_k)保证单调递增二是用带约束的优化器比如 scipy 的 SLSQP 或 MATLAB 的 fmincon。我一般用重参数化因为它把约束优化变成了无约束优化收敛更稳。代价是 γ 的解释不如 τ 直观但预测时反变换回去就行。下面这段 Python 代码用 statsmodels 的 OrderedModel 做基准再用自定义重参数化实现一遍方便你对照理解。import numpy as np import pandas as pd from scipy.stats import norm from scipy.optimize import minimize from statsmodels.miscmodels.ordinal_model import OrderedModel # 模拟一份信用卡用户数据5 个特征4 个信用等级 np.random.seed(42) n 800 X np.random.randn(n, 5) beta_true np.array([0.8, -0.5, 0.3, -0.9, 0.4]) tau_true np.array([-1.2, 0.0, 1.5]) y_star X beta_true np.random.randn(n) y np.digitize(y_star, tau_true) # 0,1,2,3 四个等级 # 方法一statsmodels 内置 OrderedModel model OrderedModel(y, X, distrprobit) res model.fit(methodbfgs) print(statsmodels 系数:, res.params[:5]) print(statsmodels 阈值:, res.params[5:]) # 方法二重参数化自定义似然 def neg_loglike(params): beta params[:5] gamma params[5:] # 重参数化tau_1 gamma_1, tau_k tau_{k-1} exp(gamma_k) tau np.zeros(len(gamma)) tau[0] gamma[0] for k in range(1, len(gamma)): tau[k] tau[k-1] np.exp(gamma[k]) # 计算每个样本落在对应区间的概率 eta X beta cdf_upper norm.cdf(tau[y] - eta) cdf_lower np.where(y 0, norm.cdf(tau[y-1] - eta), 0.0) prob np.clip(cdf_upper - cdf_lower, 1e-12, 1.0) return -np.sum(np.log(prob)) init np.concatenate([np.zeros(5), [-1.0, 0.0, 0.0]]) res_custom minimize(neg_loglike, init, methodBFGS) print(自定义系数:, res_custom.x[:5]) print(自定义阈值:, res_custom.x[5:])这段代码的逻辑说明y_star是潜变量np.digitize按真实阈值切出观测等级。statsmodels 的OrderedModel直接估计 β 和 τ作为对照基准。自定义部分把 τ 转成 γtau[0] gamma[0]让第一个阈值自由取值后续阈值用tau[k-1] exp(gamma[k])保证严格递增exp确保增量恒正。负对数似然里cdf_upper - cdf_lower就是区间概率np.clip防止 log(0)。参数说明beta_true里正系数表示该特征越大信用等级越高负系数相反。tau_true [-1.2, 0.0, 1.5]把潜变量切成四段对应四个等级。实际数据里阈值没有先验靠优化器从数据里学。init里 γ 的初值我习惯设成[-1.0, 0.0, 0.0]第一个阈值给负值后续增量给 0这样初始阈值大致均匀分布不容易一上来就撞到边界。2.3 系数解释与边际效应别直接说「系数是 0.8 就是概率涨 0.8」定序 Probit 的系数不能直接读成概率变化。β_j 表示特征 j 每增加一个单位潜变量 y^* 平均变化 β_j。要换算成「信用等级为 k 的概率变化」需要乘上标准正态密度 φ(τ_k - x^T β) 再对 β_j 求导。对于中间等级边际效应是 φ(τ_{k-1} - η) - φ(τ_k - η) 再乘 β_j符号可能和 β_j 相反。实务里我一般报告两样东西一是 β 的符号和显著性用来判断特征方向二是对每个样本算出各等级预测概率看排序是否合理。如果某个特征的 β 为正但业务上说不通比如逾期次数越多信用越好先别急着删检查是不是共线性或者数据泄漏。信用数据里「账户数」和「查询次数」经常高度相关VIF 超过 10 就该处理。3. 用 Python 和 MATLAB 跑通信用卡评级数据、训练与验证3.1 特征工程信用卡数据里哪些字段真正进模型信用卡评级常用的特征分几类还款行为逾期次数、最大逾期天数、最近一次逾期距今月数、负债水平额度使用率、总授信额度、当前欠款、查询行为近 3/6/12 个月查询次数、账龄最早开户距今月数、平均账龄。这些字段大多偏态严重额度使用率经常有大量 0 和接近 1 的值直接标准化效果不好。我一般做三步处理先对计数类特征做 log1p 变换再对比例类特征做 WOE 分箱或分位数分箱最后统一标准化。分箱的好处是能处理非线性代价是丢失部分信息。小样本场景下比如只有几百条标注分箱容易过拟合这时候直接用原始值加样条展开更稳。from sklearn.preprocessing import StandardScaler, SplineTransformer from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline # 假设 df 有这些列 count_cols [query_3m, query_6m, overdue_times] ratio_cols [utilization, debt_income] age_cols [account_age_months] preprocess ColumnTransformer([ (log_count, Pipeline([ (log, FunctionTransformer(np.log1p)), (scale, StandardScaler()) ]), count_cols), (ratio, StandardScaler(), ratio_cols), (age_spline, Pipeline([ (spline, SplineTransformer(n_knots4, degree3)), (scale, StandardScaler()) ]), age_cols) ])逻辑说明FunctionTransformer(np.log1p)对计数特征做平滑对数变换StandardScaler统一量纲。比例特征直接标准化。账龄用SplineTransformer展开成 4 个节点的三次样条捕捉非线性。参数上n_knots4是经验值样本少于 500 时降到 3避免过拟合。3.2 训练与阈值初始化为什么你的模型总预测成同一等级定序回归训练时阈值初值对收敛影响很大。如果所有 τ 都初始化在 0 附近而数据里等级 3 占比很高优化器可能把阈值推到极端导致中间等级概率被压扁。我的做法是先跑一个简单的有序 Logit 拿初始阈值再喂给定序 Probit。statsmodels 的OrderedModel默认用等距阈值初始化多数情况够用但类别极不平衡时要手动调。MATLAB 里可以用mnrfit做有序回归指定model,ordinal和link,probit。下面是对应代码% 假设 X 是 n×p 特征矩阵y 是 1..K 的等级向量 [B, dev, stats] mnrfit(X, y, model, ordinal, link, probit); % B 的前 p 个是系数后面是阈值 beta_hat B(1:size(X,2)); tau_hat B(size(X,2)1:end); % 预测概率 pi_hat mnrval(B, X, model, ordinal, link, probit); [~, y_pred] max(pi_hat, [], 2);MATLAB 的mnrfit内部已经处理了阈值单调约束输出B里阈值按顺序排列。mnrval返回每个样本属于各等级的概率矩阵。注意 MATLAB 的等级编码从 1 开始Python 从 0 开始跨平台迁移时容易在这里翻车。3.3 验证指标AUC 不够要看有序性和校准信用评级模型的验证不能只看多分类准确率。我一般看三个层面一是相邻等级的区分度用 pairwise AUC比如等级 1 vs 2、2 vs 3 分别算 AUC二是整体排序能力用 Kendalls tau 或 Spearman 相关系数衡量预测等级和真实等级的顺序一致性三是校准画每个等级的预测概率分桶图看实际占比是否落在预测区间内。from sklearn.metrics import roc_auc_score from scipy.stats import kendalltau, spearmanr # 预测概率矩阵 proba形状 n×K y_pred_grade proba.argmax(axis1) print(Kendall tau:, kendalltau(y, y_pred_grade).correlation) print(Spearman:, spearmanr(y, y_pred_grade).correlation) # 相邻等级 pairwise AUC for k in range(K-1): mask (y k) | (y k1) auc roc_auc_score((y[mask] k1).astype(int), proba[mask, k1]) print(f等级 {k} vs {k1} AUC: {auc:.4f})Kendalls tau 低于 0.3 说明模型排序能力弱先检查特征是否漏了关键变量。Pairwise AUC 如果某一对特别低往往是这两个等级的业务定义本身模糊需要回去和风控确认标签口径。4. 避坑与排查定序回归在信用评级里的五个血泪教训4.1 阈值交叉导致似然为负无穷现象优化过程中 loss 突然变成nan或-inf参数不再更新。原因没有对阈值加单调约束优化器把 τ_2 推到比 τ_1 还小区间概率变成负数log 无定义。解决用重参数化tau[k] tau[k-1] exp(gamma[k])或者在 scipy 里加约束{type:ineq, fun: lambda p: np.diff(p[5:])}。我习惯重参数化省心。4.2 类别极不平衡时中间等级被吞掉现象真实数据里等级 2 占 5%模型预测里等级 2 的概率几乎全是 0。原因定序模型假设潜变量连续少数类落在阈值区间很窄的位置极大似然倾向于把区间压小。解决对少数类样本加权似然里乘样本权重w_i 1 / count(y_i)或者合并相邻稀有等级把 5 级并成 4 级。合并前要和业务确认等级定义不能随便动。4.3 特征共线性让系数符号反转现象单独看「逾期次数」和信用等级负相关放进模型后系数变成正。原因逾期次数和「查询次数」高度相关两者同时进模型时方差膨胀系数估计不稳定。解决算 VIF超过 10 的删一个或做 PCA。信用数据里我一般保留业务解释性强的那个比如保留逾期次数把查询次数做分箱后只保留「近 3 月查询」一个字段。4.4 训练集和测试集等级分布不一致现象训练集等级 3 占 40%测试集等级 3 占 15%模型在测试集上 pairwise AUC 暴跌。原因按时间切分数据时不同时间段客群质量变化等级分布漂移。解决用分层抽样保证切分后分布一致或者按时间做滚动验证报告每个时间窗的指标。如果漂移严重说明模型需要加时间特征或重新训练。4.5 Probit 和 Logit 混用导致概率尺度对不上现象用 Probit 训练用 Logit 的系数解释边际效应算出来的概率变化偏大。原因逻辑分布方差是 π²/3 ≈ 3.29标准正态方差是 1两者系数差约 1.6 到 1.8 倍。解决统一用同一种连接函数报告时注明。如果非要换算Logit 系数除以 1.7 近似 Probit 系数反过来乘 1.7。5. 小样本下的进阶技巧从高斯过程回归和 RVM 借思路信用卡评级经常遇到小样本问题——某家银行刚开展业务标注数据只有几百条。这时候定序 Probit 的极大似然估计方差很大阈值估计尤其不稳。我试过两条路一是给 β 加正态先验做贝叶斯定序 Probit用 MCMC 或变分推断二是借鉴高斯过程回归和 RVM 多输出回归的思路把等级之间的相关性显式建模。高斯过程回归适合小样本仿真数据预测核心是用核函数刻画样本间相似度。把定序回归的潜变量 y^* 看成高斯过程协方差矩阵 K 由 RBF 核生成观测等级通过阈值和 y^* 关联。这样预测时不仅给出等级还给出潜变量的后验分布阈值附近的不确定性一目了然。MATLAB 实现的 RVM 多输出回归则适合多个相关评级任务联合建模比如同时预测信用等级和违约概率两个输出共享基函数小样本下比单独建模更稳。具体做法先用高斯过程对潜变量做后验预测得到每个测试样本的 y^* 均值和方差再按阈值算各等级概率。核函数带宽用边际似然最大化选小样本下length_scale别设太小否则过拟合。RVM 的稀疏性在特征多、样本少时优势明显但要注意它输出的方差估计偏乐观校准时要留出验证集。我自己的习惯是样本少于 1000 条时先跑贝叶斯定序 Probit 看后验区间再用高斯过程做对照。两者结论一致才敢上线。上线后每月监控等级分布和 pairwise AUC一旦某对 AUC 掉超过 0.05就触发重新训练。这套流程跑了两年最深的教训是阈值比系数更需要定期校准因为客群分布会漂移而阈值直接决定等级切分。希望帮到你。本文还有配套的精品资源点击获取
返回列表