Python中贷款迁徙率转换矩阵设计作业答疑请求
解决贷款迁徙率转换矩阵的Python实现问题
嘿,我明白你在做这个贷款迁徙率矩阵作业时遇到的坎儿了——我之前在风控项目里也折腾过类似的东西,咱们一步步来拆解解决:
一、先理清贷款迁徙率矩阵的核心结构
首先得明确:迁徙率矩阵是用来展示不同信用等级的贷款在一段周期(比如季度/年度)内,迁徙到其他等级或状态的比例。行代表周期开始时的初始等级,列代表周期结束时的期末等级,每行的总和必须是1(或100%),因为每笔贷款最终都会处于某个确定状态(包括违约、结清)。
常见的信用等级划分参考:正常(A)、关注(B)、次级(C)、可疑(D)、损失(E,即违约)、结清(F),你可以根据作业要求调整等级数量或命名。
二、从回溯数据(Retro Data)推导迁徙率的步骤
这部分是核心,不能光靠随机数凑,得贴合真实业务逻辑:
- 第一步:整理回溯数据集:你需要的历史数据至少包含:每笔贷款的ID、初始信用等级(周期起点)、期末信用等级(周期终点)、贷款状态(是否结清/违约)。
- 第二步:分组统计迁徙数量:按初始等级分组,统计每个初始等级下,迁徙到各个期末等级的贷款笔数。比如初始等级A的贷款有1000笔,其中950笔保持A、30笔降到B、15笔结清、5笔违约。
- 第三步:计算迁徙比率:用每个迁徙方向的贷款数除以该初始等级的总贷款数,得到迁徙率。比如上面的例子里,A行的迁徙率就是
[0.95, 0.03, 0, 0, 0.005, 0.015]。 - 注意细节:要排除已经结清/违约的贷款在后续周期的统计;如果某个等级的样本量过小(比如只有几笔贷款),比率波动会很大,可以用行业均值做平滑处理。
三、贴合实际的示例比率(常识+行业数据参考)
给你一组接近真实风控场景的年度迁徙率示例,直接就能用到你的DataFrame里:
| 初始等级 | 正常(A) | 关注(B) | 次级(C) | 可疑(D) | 损失(E) | 结清(F) |
|---|---|---|---|---|---|---|
| 正常(A) | 0.92 | 0.05 | 0.01 | 0.005 | 0.005 | 0.01 |
| 关注(B) | 0.10 | 0.75 | 0.08 | 0.04 | 0.02 | 0.01 |
| 次级(C) | 0.02 | 0.15 | 0.60 | 0.15 | 0.06 | 0.02 |
| 可疑(D) | 0.00 | 0.03 | 0.12 | 0.55 | 0.25 | 0.05 |
| 损失(E) | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 |
| 结清(F) | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 |
逻辑解释:正常贷款大概率保持原有等级,小部分降级;关注贷款有一定概率回归正常,但更多还是维持或降级;次级/可疑贷款违约概率显著升高;损失、结清状态的贷款不会再发生迁徙。
四、Python实现的修正代码(替换随机数,贴合真实逻辑)
如果你之前用了纯随机数生成DataFrame,现在可以改成基于真实逻辑的代码:
直接创建标准迁徙率矩阵
import pandas as pd # 定义信用等级列表 grades = ["正常(A)", "关注(B)", "次级(C)", "可疑(D)", "损失(E)", "结清(F)"] # 填入实际迁徙率数据 transition_rates = [ [0.92, 0.05, 0.01, 0.005, 0.005, 0.01], [0.10, 0.75, 0.08, 0.04, 0.02, 0.01], [0.02, 0.15, 0.60, 0.15, 0.06, 0.02], [0.00, 0.03, 0.12, 0.55, 0.25, 0.05], [0.00, 0.00, 0.00, 0.00, 1.00, 0.00], [0.00, 0.00, 0.00, 0.00, 0.00, 1.00] ] # 创建DataFrame矩阵 transition_matrix = pd.DataFrame(transition_rates, index=grades, columns=grades) # 验证每行总和是否为1(允许微小浮点误差) print("每行总和验证:") print(transition_matrix.sum(axis=1)) # 输出最终矩阵 print("\n贷款迁徙率转换矩阵:") print(transition_matrix)
从模拟回溯数据推导迁徙率
如果需要展示“从回溯数据推导”的过程,可以用这段模拟代码:
import pandas as pd import numpy as np # 模拟10000笔贷款的回溯数据 np.random.seed(42) n_loans = 10000 grades = ["正常(A)", "关注(B)", "次级(C)", "可疑(D)", "损失(E)", "结清(F)"] initial_grades = np.random.choice(grades, size=n_loans, p=[0.7, 0.15, 0.08, 0.05, 0.01, 0.01]) # 定义迁徙概率映射(和标准矩阵一致) transition_probs = { "正常(A)": [0.92, 0.05, 0.01, 0.005, 0.005, 0.01], "关注(B)": [0.10, 0.75, 0.08, 0.04, 0.02, 0.01], "次级(C)": [0.02, 0.15, 0.60, 0.15, 0.06, 0.02], "可疑(D)": [0.00, 0.03, 0.12, 0.55, 0.25, 0.05], "损失(E)": [0.00, 0.00, 0.00, 0.00, 1.00, 0.00], "结清(F)": [0.00, 0.00, 0.00, 0.00, 0.00, 1.00] } # 生成期末等级 final_grades = [] for grade in initial_grades: final_grade = np.random.choice(grades, p=transition_probs[grade]) final_grades.append(final_grade) # 创建回溯数据集 retro_data = pd.DataFrame({ "initial_grade": initial_grades, "final_grade": final_grades }) # 从回溯数据推导迁徙率矩阵(按行归一化) transition_matrix_from_data = pd.crosstab(retro_data["initial_grade"], retro_data["final_grade"], normalize="index") # 输出推导后的矩阵 print("从回溯数据推导的迁徙率矩阵:") print(transition_matrix_from_data)
五、常见问题解决
- 随机数矩阵不符合实际逻辑:比如正常贷款迁徙到损失的概率过高,这时候要基于行业常识调整概率,或者用真实回溯数据统计,不要用纯随机数。
- 行总和不为1:可能是随机数生成时没做归一化,或者统计时遗漏了部分贷款。可以用
df.div(df.sum(axis=1), axis=0)对每行做归一化处理。 - 出现NaN值:如果某个初始等级没有迁徙到某个期末等级的贷款,会出现NaN,用
df.fillna(0)填充即可。
内容的提问来源于stack exchange,提问作者robert james
相关产品推荐
相关产品推荐

