news 2026/9/26 2:04:23

定序Probit模型实战:信用卡信用评级从建模到决策

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
定序Probit模型实战:信用卡信用评级从建模到决策

简介:这份PDF文档聚焦数据回归中的定序回归模型,面向金融风控、信用评分方向的学习者与从业者,帮助理解如何用统计建模方法解决信用卡持卡人信用评级与违约风险识别问题。资源共1个PDF文件,压缩包约447KB,内容为完整的论文式文档,涵盖信用评级对信用卡业务的重要性、数据集介绍与探索性分析、定序Probit模型建模、自变量选择及结论等章节,并附有中英文摘要与参考文献。文档以ordered probit回归为主线,系统展示了从数据探索到模型拟合、再到影响因素分析的完整流程,读者可借此掌握定序回归在信用评级场景中的建模思路与实操方法。目前已有323人学习下载,适合具备一定统计学基础、希望将回归模型应用于信用风险量化评估的读者参考。

1. 从一份 8372 条记录的信用卡数据说起:定序 Probit 到底能解决什么

手里这份《数据回归-定序回归模型在信用卡用户信用评级中的应用.pdf》,第一次翻的时候我以为是又一篇把 logistic 换个壳的论文,直到看到因变量那一列——逾期状态不是简单的“违约/不违约”,而是从“没有逾期”一路排到“逾期 180 天以上”共 8 个有序档位。这种数据你用普通线性回归去拟合,等于把“逾期 151~180 天”和“逾期 1~30 天”当成等距的数值在算,出来的系数根本没法解释。定序 Probit 模型处理的正是这类“结果有先后顺序、但档位间距没有实际数值意义”的场景,信用卡信用评级是它最典型的落地场合之一。这份资料适合两类人:一类是手头有类似有序标签数据、想找一套能跑通建模流程的从业者;另一类是想搞明白 ordered probit 和普通回归到底差在哪、参数怎么读的学生和转行者。它给的不是理论推导的炫技,而是一条从数据探索到变量筛选再到结果解读的完整链路。

2. 定序 Probit 的潜变量逻辑:为什么不能直接上线性回归

2.1 潜变量 Z 与阈值切分:模型的核心机制

这份资料里讲得最清楚的一点,是定序 Probit 引入了一个观察不到的连续变量 Z,叫潜变量。你可以把它理解成一个人的“真实信用风险分数”,它连续变化,但银行看到的只是被切分后的档位。模型写成 Z = Xβ + ε,其中 ε 服从标准正态分布。然后设定一组阈值 C₁ 到 Cₘ₋₁,把 Z 切成 m 段,每一段对应一个观察到的逾期状态。

这个设定解决了一个根本问题:因变量是“逾期 1~30 天”还是“逾期 31~60 天”,它们之间的差距不是固定的天数差,而是一种序关系。线性回归强行假设等距,定序 Probit 只假设“Z 越大,逾期档位越高”,不假设档位间距相等。

资料里举的考试成绩例子很直观:真实成绩 Z 是连续的,60 分以下记为不及格,60 到 90 记为良好,90 以上记为优秀。你观察到的只是“不及格/良好/优秀”,但背后驱动的 Z 是连续的。信用卡逾期状态完全同理。

提示:潜变量的方差必须固定为 1,否则回归系数 β 不可识别。资料里专门说明了这一点——如果 ε 方差是 σ²,你可以重新定义 β/σ 和 Z/σ,模型形式不变,所以必须约束方差。这是很多人第一次看定序 Probit 时容易卡住的地方。

2.2 极大似然估计的落地写法

模型确定后,下一步是估计参数。资料给出的思路是写出样本的联合分布,取对数得到对数似然函数,然后极大化。具体来说,给定 X 条件下 y 取第 k 个状态的概率是:

  • k=1 时:P(y=1|X) = Φ(C₁ - Xβ)
  • k=2 到 m-1 时:P(y=k|X) = Φ(Cₖ - Xβ) - Φ(Cₖ₋₁ - Xβ)
  • k=m 时:P(y=m|X) = 1 - Φ(Cₘ₋₁ - Xβ)

其中 Φ 是标准正态分布的累积分布函数。把所有样本的这些概率乘起来取对数,就是对数似然函数。极大化它,得到 β 和阈值 C 的极大似然估计。

用 Python 的 statsmodels 可以比较直接地复现这个流程。下面是一段可运行的代码框架:

import pandas as pd import numpy as np from statsmodels.miscmodels.ordinal_model import OrderedModel # 假设数据已经读入,列名对应资料中的变量 # y: 逾期状态,0到7共8个有序档位 # X1: 性别(0/1),X2: 信用卡使用率,X3: 信用卡额度 # X4: 住房贷款月供,X5: 历史逾期次数,X6: 信用卡开户数 df = pd.read_csv('credit_data.csv') # 因变量和自变量 y = df['y'] X = df[['X1', 'X2', 'X3', 'X4', 'X5', 'X6']] # 拟合定序Probit模型,distr参数指定用probit链接 model = OrderedModel(y, X, distr='probit') result = model.fit(method='bfgs', maxiter=1000) # 输出系数估计和显著性 print(result.summary()) # 查看阈值参数 print("阈值:", result.params[-7:])

这段代码的逻辑是:OrderedModel 自动处理了潜变量切分的部分,你只需要指定因变量是有序的、链接函数用 probit。fit 方法用 BFGS 优化算法去极大化对数似然。result.params 前面是回归系数 β,后面几个是阈值 C。

参数说明上,β 的符号告诉你该变量对“更高逾期档位”的影响方向。比如历史逾期次数 X5 的系数如果为正且显著,说明历史逾期越多,当前逾期档位越高的概率越大。阈值 C 本身没有太强的单独解释意义,它们只是切分点,但阈值之间的间距可以反映各档位的分布密度。

注意:statsmodels 的 OrderedModel 默认把第一个类别作为基准,阈值个数是类别数减一。如果你发现输出的阈值数量和预期对不上,先检查因变量的编码是不是从 0 开始的连续整数。

3. 数据探索与变量筛选:从列联表到似然比检验

3.1 分层描述:均值和标准差透露的相关性

资料在建模之前做了一轮探索性分析,方法不复杂但很实用。对于性别这个二值变量,做列联表看行百分比;对于信用卡使用率、历史逾期次数等计数型变量,按逾期状态分层算均值和标准差。

分层均值的结果很说明问题:信用卡使用率、历史逾期次数、信用卡开户数这三个变量,随着逾期档位升高,均值呈上升趋势,说明正相关;而信用卡额度和住房贷款月供,随着逾期档位升高,均值反而下降,说明负相关。标准差在各层之间比较一致,说明这种相关性不是某一层数据波动造成的。

这一步的意义在于,它给你一个初步判断:哪些变量值得放进模型,哪些可能没什么用。资料里信用卡额度和住房贷款月供虽然显示出负相关,但后续建模发现它们并不显著,说明探索性分析只是粗筛,不能替代正式建模。

用 pandas 复现这个分层统计很快:

# 按逾期状态分组,计算各变量的均值和标准差 grouped_mean = df.groupby('y')[['X2', 'X3', 'X4', 'X5', 'X6']].mean() grouped_std = df.groupby('y')[['X2', 'X3', 'X4', 'X5', 'X6']].std() print("分层均值:") print(grouped_mean) print("\n分层标准差:") print(grouped_std) # 性别与逾期状态的列联表,看行百分比 cross_tab = pd.crosstab(df['X1'], df['y'], normalize='index') print("\n性别与逾期状态列联表(行百分比):") print(cross_tab)

groupby 后直接算 mean 和 std,就能得到资料里表 2.4 和表 2.5 的效果。列联表用 normalize='index' 得到行百分比,对应资料里分析男性是否更容易违约的那张表。

3.2 模型选择:似然比检验和 AIC/BIC 的取舍

全变量模型跑出来之后,资料发现信用卡额度和住房贷款月供这两个变量的系数估计值接近 0,p 值也不显著。于是构建了两个模型做对比:

  • Model I:只保留性别、信用卡使用率、历史逾期次数、信用卡开户数
  • Model II:保留全部六个变量

然后用了四种方法做选择:似然比检验、AIC、校正 AIC、BIC。结果有意思——AIC 和 BIC 倾向于选 Model II(变量多的那个),但似然比检验支持 Model I。资料最终选了似然比检验的结果,理由是 AIC/BIC 只是准则不是检验,不能绝对地判断哪个模型更好。

这个取舍在实际工作中很常见。AIC/BIC 惩罚的是模型复杂度,样本量大的时候它们倾向于保留更多变量;似然比检验直接检验“去掉这两个变量是否显著降低了拟合优度”。当两者矛盾时,你得根据业务目标来定:如果目的是找出关键影响因素,简约模型更好解释;如果目的是预测精度,多变量模型可能更稳。

似然比检验的统计量算法是 D = 2ln(L_ModelII) - 2ln(L_ModelI),服从自由度为 2 的卡方分布(因为少了两个参数)。资料给出的结果是卡方统计量 160.4,p 值小于 1E-10,强烈拒绝原假设,支持去掉那两个变量。

from scipy import stats # 假设已经拟合了两个模型 # model_full 是包含全部变量的模型 # model_reduced 是去掉X3和X4的模型 ll_full = model_full.llf ll_reduced = model_reduced.llf # 似然比检验统计量 lr_stat = 2 * (ll_full - ll_reduced) df_diff = 2 # 去掉两个变量,自由度差为2 p_value = 1 - stats.chi2.cdf(lr_stat, df_diff) print(f"似然比统计量: {lr_stat:.2f}") print(f"p值: {p_value:.2e}")

llf 是拟合后的对数似然值,直接相减乘 2 就是检验统计量。自由度差等于去掉的参数个数。p 值小于 0.05 就拒绝原假设,认为去掉的变量联合显著。

3.3 最终模型的参数解读

去掉信用卡额度和住房贷款月供后,最终模型的变量是:性别、信用卡使用率、历史逾期次数、信用卡开户数。资料里表 3.4 给出了估计结果,所有变量的 p 值都显著。

性别变量在 SAS 输出里有一个水平被设为 0 作为基准,另一个水平的系数反映的是相对于基准的差异。信用卡使用率和历史逾期次数的系数为正且显著,说明这两个指标越高,逾期档位越高的概率越大。信用卡开户数的系数虽然显著但置信区间离 0 较近,解释时要谨慎。

这里有个容易翻车的地方:定序 Probit 的系数不能直接读成“边际效应”。因为模型是非线性的,某个变量对“从没有逾期变成逾期 1~30 天”的概率影响,和对“从逾期 151~180 天变成逾期 180 天以上”的概率影响是不一样的。如果你要给业务方解释,最好算出具体某个样本在各个档位上的预测概率,而不是只报系数。

# 预测某个新客户属于各逾期档位的概率 new_customer = pd.DataFrame({ 'X1': [1], # 性别 'X2': [0.6], # 信用卡使用率 'X5': [3], # 历史逾期次数 'X6': [2] # 信用卡开户数 }) # 预测概率 pred_probs = result.predict(new_customer) print("各逾期档位的预测概率:") for i, prob in enumerate(pred_probs[0]): print(f"档位 {i}: {prob:.4f}")

predict 方法返回的是每个样本属于各个档位的概率向量。业务上可以设定一个阈值,比如“逾期 61 天以上的概率超过 0.3 就拒绝发卡”,这样就把模型输出转化成了决策规则。

4. 避坑与排查:定序 Probit 建模中最容易翻车的五个地方

4.1 把有序变量当连续变量直接跑线性回归

现象:用 OLS 拟合逾期状态,R² 看起来还行,但残差图呈现明显的规律性,预测值出现负数或超出档位范围。

原因:线性回归假设因变量连续且等距,但逾期档位只是序关系,1 和 2 之间的差距不等于 2 和 3 之间的差距。强行当连续变量处理,系数估计有偏。

解决:确认因变量是有序类别后,改用定序 Probit 或定序 Logit。判断标准很简单——如果类别之间有明确的先后顺序但不能做加减运算,就该用定序模型。

4.2 忽略潜变量方差固定为 1 的约束

现象:换一个软件或库跑同样的数据,系数估计值差了好几倍,显著性也变了。

原因:定序 Probit 的潜变量方差必须固定为 1 才能识别参数。不同软件默认的约束可能不同,有的固定方差,有的固定某个阈值。

解决:跑之前先确认软件的默认约束方式。statsmodels 的 OrderedModel 默认固定方差为 1,SAS 的 PROC LOGISTIC 也是。如果你从别的渠道拿到代码,先检查这一点。

4.3 阈值数量与类别数对不上

现象:因变量有 8 个档位,但模型只输出了 6 个阈值,或者报错说类别数不匹配。

原因:定序 Probit 的阈值数量是类别数减一。8 个档位对应 7 个阈值。如果因变量编码不连续(比如跳过了某个值),软件可能按实际出现的唯一值数量来算。

解决:建模前先检查因变量的唯一值,确保是从 0 或 1 开始的连续整数。用df['y'].unique()看一眼,如果有跳号,先重新编码。

4.4 用 AIC/BIC 替代似然比检验做最终决策

现象:AIC 说选复杂模型,似然比检验说选简单模型,不知道该信哪个。

原因:AIC/BIC 是模型选择准则,不是假设检验。它们在不同样本量下的表现不一样,样本量大时倾向于保留更多变量。

解决:如果两个模型是嵌套关系(简单模型是复杂模型的子集),优先用似然比检验。如果不是嵌套关系,再用 AIC/BIC。资料里最终选了似然比检验的结果,这个判断是合理的。

4.5 直接解释系数为边际效应

现象:给业务方汇报时说“信用卡使用率每增加 1 个单位,逾期概率增加 0.15”,被质疑这个数字怎么来的。

原因:定序 Probit 是非线性模型,系数反映的是潜变量 Z 的变化,不是观察到的概率变化。概率的边际效应取决于当前所处的档位和所有变量的取值。

解决:要汇报边际效应,就针对具体样本算出各档位的预测概率,然后看某个变量变化时概率怎么变。或者计算平均边际效应(AME),但要在报告里注明计算方法。

5. 从模型到决策:把预测概率转成发卡规则的一个实用技巧

模型跑通、变量筛完、参数解读清楚之后,最后一步是把它变成能用的东西。资料里提到,信用卡发卡公司可以把申请人的资料输入模型,得到该申请人所属的逾期状态类,从而决策是否发卡。但实际操作中,直接输出一个档位太粗糙了,更有用的是输出概率然后设阈值。

我一般会这么做:先用最终模型对历史数据做预测,得到每个样本属于各个档位的概率。然后定义一个“高风险”规则,比如“逾期 61 天以上的概率超过 0.25”就标记为高风险。接着用历史数据回测这个规则——看被标记为高风险的客户里,实际发生逾期 61 天以上的比例是多少,没被标记的客户里有多少漏网之鱼。根据回测结果调整阈值,在通过率和风险之间找平衡。

# 对全量数据预测各档位概率 all_probs = result.predict(X) # 计算“逾期61天以上”的累积概率(档位3及以上) # 假设档位编码:0=无逾期,1=1-30天,2=31-60天,3=61-90天,... high_risk_prob = all_probs[:, 3:].sum(axis=1) # 设定阈值,标记高风险客户 threshold = 0.25 df['high_risk'] = (high_risk_prob > threshold).astype(int) # 回测:看高风险客户中实际逾期61天以上的比例 actual_high_risk = (df['y'] >= 3).astype(int) hit_rate = actual_high_risk[df['high_risk'] == 1].mean() coverage = df['high_risk'].mean() print(f"高风险客户中实际逾期61天以上的比例: {hit_rate:.2%}") print(f"被标记为高风险的客户占比: {coverage:.2%}")

这段代码的关键是 all_probs[:, 3:].sum(axis=1),把档位 3 及以上的概率加起来,得到“逾期超过 60 天”的累积概率。然后设阈值做二分类。回测的两个指标——命中率(高风险客户中实际高风险的比例)和覆盖率(被标记为高风险的客户占比)——是调阈值的依据。阈值调高,命中率上升但覆盖率下降,通过率降低;阈值调低则相反。

还有一个细节:定序 Probit 假设各档位之间的切分是平行的,也就是说不管客户的其他特征如何,从“无逾期”到“逾期 1~30 天”的阈值 C₁ 是固定的。这个假设叫“平行线假设”,如果数据不满足,可以考虑广义定序模型。但在信用卡场景下,这个假设通常还能接受,因为逾期状态的序关系比较稳定。

从那以后我每次做完定序模型,都会强制走一遍“预测概率→设阈值→回测命中率和覆盖率”的流程,不直接拿系数去汇报。模型参数是给建模的人看的,业务方要的是“按这个规则,我们会拒绝多少人、其中多少人确实是高风险的”。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 2:01:10

Open Code Review:可审计、可验证的开源代码审查范式

1. 这不是又一个“AI代码审查工具”,而是一套可审计、可验证、可嵌入CI的开源协作范式 你有没有遇到过这样的场景:团队里新来一位 junior 开发者,提交了一段看似逻辑通顺的 Python 脚本——它能跑通单元测试,也能在本地环境输出预…

作者头像 李华
网站建设 2026/9/26 2:00:27

Oracle EBS AP预付款管理:从创建到核销的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 2:00:27

【亲测免费】 Pyxel - 一个复古风格的游戏开发框架

Pyxel - 一个复古风格的游戏开发框架 【免费下载链接】pyxel A retro game engine for Python 项目地址: https://gitcode.com/GitHub_Trending/py/pyxel 是一个由 Kitao 制作的 Python 库,它旨在简化2D游戏的开发过程,并提供了一种独特的复古视觉…

作者头像 李华
网站建设 2026/9/26 1:59:36

C语言-----程序控制结构和语句(2)

目录 1、循环结构与语句 1.1 循环结构 1.2 当型循环语句----- for 语句 1.3 当型循环语句----- while 语句 1.4 直到型循环语句----- do-while 语句 1.5 循环的嵌套 2、转向语句 2.1 goto 语句 2.2 break 语句 2.3 continue 语句 本章博客是对程序控制结构和…

作者头像 李华