You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.920.050.010.0050.0050.01
关注(B)0.100.750.080.040.020.01
次级(C)0.020.150.600.150.060.02
可疑(D)0.000.030.120.550.250.05
损失(E)0.000.000.000.001.000.00
结清(F)0.000.000.000.000.001.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. 随机数矩阵不符合实际逻辑:比如正常贷款迁徙到损失的概率过高,这时候要基于行业常识调整概率,或者用真实回溯数据统计,不要用纯随机数。
  2. 行总和不为1:可能是随机数生成时没做归一化,或者统计时遗漏了部分贷款。可以用df.div(df.sum(axis=1), axis=0)对每行做归一化处理。
  3. 出现NaN值:如果某个初始等级没有迁徙到某个期末等级的贷款,会出现NaN,用df.fillna(0)填充即可。

内容的提问来源于stack exchange,提问作者robert james

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:23:01