← 返回编程题库
coding-rating-transition-multistep-distribution中等免费版2000ms未尝试

多步评级分布传播:Markov 转移矩阵前推 H 步

Multi-Step Rating Distribution Propagation: Markov Transition Forward H Steps

开始编码

实现 solution(distribution: list[float], transition_matrix: list[list[float]], horizon_steps: int) -> list[float]。某信用风险条线维护一张由历史评级迁移数据估计得到的一期转移矩阵:transition_matrix[i][j] 表示当前位于评级桶 i 的债务人在一期之后位于评级桶 j 的概率。该矩阵是行随机的——每一行之和为 1.0,因为债务人在一步之后总会落在某个评级桶里。要把当前评级分布前推 H 期,将其与转移矩阵相乘 H 次:dist_after_H = distribution @ transition_matrix^H。返回恰好执行 horizon_steps 步一期传播之后的长度为 K 的分布。

每一步的传播公式为

new_dist[j] = sum_{i in [0, K)} dist[i] * transition_matrix[i][j]

i评级(质量从哪里来),j目标评级(质量落在哪里)。由于 transition_matrix[i][j] 是 FROM-i-TO-j 的概率、每一(不是每一列)之和为 1.0,把 ij 调换是真正的 bug,会把分布沿时间反向传播;非对称矩阵上结果一律错。

solution([0.6, 0.3, 0.1], [[0.85, 0.10, 0.05], [0.10, 0.80, 0.10], [0.0, 0.0, 1.0]], 2) 返回 [0.489, 0.294, 0.217]。该转移矩阵是行随机的——第 0 行 [0.85, 0.10, 0.05] 之和 = 1.0、第 1 行 [0.10, 0.80, 0.10] 之和 = 1.0、第 2 行 [0.0, 0.0, 1.0] 是吸收的违约态(行和 = 1.0)。第 1 步:new_dist[0] = 0.6*0.85 + 0.3*0.10 + 0.1*0.0 = 0.54new_dist[1] = 0.6*0.10 + 0.3*0.80 + 0.1*0.0 = 0.30new_dist[2] = 0.6*0.05 + 0.3*0.10 + 0.1*1.0 = 0.16,所以 1 步后的分布是 [0.54, 0.30, 0.16](之和 = 1.0)。第 2 步从 [0.54, 0.30, 0.16] 出发:new_dist[0] = 0.54*0.85 + 0.30*0.10 + 0.16*0.0 = 0.489new_dist[1] = 0.54*0.10 + 0.30*0.80 + 0.16*0.0 = 0.294new_dist[2] = 0.54*0.05 + 0.30*0.10 + 0.16*1.0 = 0.217。最终输出 [0.489, 0.294, 0.217](之和 = 1.0)。

行 vs 列约定的索引校验:行随机的前向公式取 tm[i][j](FROM i TO j)、对 i 求和。如果作者误写成 new_dist[j] = sum_i dist[i] * tm[j][i](这种索引互换在列随机矩阵——列和为 1.0——下才是对的),那么本例第 1 步 new_dist[0] 会算出 0.6*0.85 + 0.3*0.10 + 0.1*0.05 = 0.575(不是正确的 0.54)。两种索引只有在对称矩阵上才碰巧吻合;非对称矩阵上必然分叉。契约毫不含糊:行和为 1.0,索引为 tm[i][j] = P(i -> j)

需要明确的细节:horizon_steps == 0 返回原样输入分布(空乘积 transition_matrix^0 = I)。K == 1 时矩阵必然是 [[1.0]]、分布对任意 H 都不动。违约吸收态 d 编码为 transition_matrix[d] = [0, 0, ..., 1.0, ..., 0, 0](对角线第 d 位是 1.0、其余为 0);循环里无需特判——吸收行就是正确的数学模型,所谓防御性的"跳过吸收态"会把传播弄坏。本函数不抛异常;调用方保证矩阵的行随机性以及输入是合法的概率分布。

期望算法是简单的 O(H * K^2) 三层嵌套循环:每一步先 new_dist = [0.0] * K,遍历 (i, j) 累加 new_dist[j] += dist[i] * tm[i][j],步末 dist = new_dist。由于 K <= 10H <= 24,总运算量约为 2400,朴素三层循环远远满足 2000 ms 上限。**每一步必须新开 new_dist**——一边读 dist[i] 一边原地写 dist[j] 会污染本轮累加。重复平方法(矩阵幂 O(K^3 log H))只在 H 很大时才更快;本题 H <= 24,朴素迭代就是正确选择。

实现细节由 stubs/stub.py 提供。

实践背景

某信用风险条线根据历史评级迁移数据(例如机构内部企业信贷池逐月观察到的内评迁移)估计出一张一期转移矩阵。要把组合的评级分布前推 H 个汇报期(年度压力测试取 12 个月、多年资本规划取 36 个月),将当前分布与转移矩阵连乘 H 次即可。输出驱动多期信用压力投影——"如果继续持有 12 个月,违约和投资级各自的期望概率质量是多少?"——并喂入 Basel 内评法(IRB)下的预期损失归因、IFRS 9 下的存续期预期损失计提、CECL 下的当前预期信用损失准备金。违约吸收的约定至关重要:债务人一旦违约、评级迁移模型对其后续轨迹就此止步,所有从其他评级流入违约态的概率质量都留在违约态——这恰好就是"对应行除对角线 1.0 之外全 0"所编码的内容。行随机索引是条线下游所有数据管道和存续期损失库默认的约定;列随机的实现会把概率质量沿时间反向传播,把风险面板上每一个多期压力数字都弄错。

约束条件

  • 1 <= K <= 10,其中 K == len(distribution) == len(transition_matrix)
  • 0 <= horizon_steps <= 24
  • 每个 distribution[i] 在 [0.0, 1.0];sum(distribution) == 1.0(在 rel_tol=1e-9 内)
  • 每个 transition_matrix[i] 是长度为 K 的列表;每个 transition_matrix[i][j] 在 [0.0, 1.0];每**行** i 之和为 1.0(在 rel_tol=1e-9 内)
  • 输出为长度 K 的 list[float];每项非负;之和为 1.0(在 rel_tol=1e-9 内);按 rel_tol=1e-9、abs_tol=1e-9 比对

样例

Case 1 · statement-example: 3-state row-stochastic, H=2 forward propagation

输入: [[0.6,0.3,0.1],[[0.85,0.1,0.05],[0.1,0.8,0.1],[0,0,1]],2]

期望: [0.489,0.294,0.217]

三状态行随机矩阵,H=2 步前向传播;矩阵行和为 1.0,第三行 [0,0,1] 表示违约状态吸收。

Case 2 · visible: H=0 returns input distribution unchanged

输入: [[0.2,0.5,0.3],[[0.7,0.2,0.1],[0.1,0.8,0.1],[0,0,1]],0]

期望: [0.2,0.5,0.3]

H=0 不做任何传播,输出等于输入分布。

Case 3 · visible: K=1 trivial single-state with H=5

输入: [[1],[[1]],5]

期望: [1]

K=1 时唯一状态,转移矩阵为 [[1.0]],分布永不变化。

Case 4 · visible: identity transition_matrix preserves distribution for any H

输入: [[0.4,0.35,0.25],[[1,0,0],[0,1,0],[0,0,1]],7]

期望: [0.4,0.35,0.25]

单位转移矩阵:每个评级以概率 1.0 留在原地,分布对任意 H 都不变。

Case 5 · visible: deterministic start [1,0,0] gives 0-th row of TM^H

输入: [[1,0,0],[[0.7,0.2,0.1],[0,0.9,0.1],[0,0,1]],3]

期望: [0.3429999999999999,0.386,0.271]

起始全部位于评级 0 时,输出等于 TM^H 的第 0 行。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: 3-state row-stochastic, H=2 forward propagation

输入: [[0.6,0.3,0.1],[[0.85,0.1,0.05],[0.1,0.8,0.1],[0,0,1]],2]

期望: [0.489,0.294,0.217]

三状态行随机矩阵,H=2 步前向传播;矩阵行和为 1.0,第三行 [0,0,1] 表示违约状态吸收。

Case 2 · visible: H=0 returns input distribution unchanged

输入: [[0.2,0.5,0.3],[[0.7,0.2,0.1],[0.1,0.8,0.1],[0,0,1]],0]

期望: [0.2,0.5,0.3]

H=0 不做任何传播,输出等于输入分布。

Case 3 · visible: K=1 trivial single-state with H=5

输入: [[1],[[1]],5]

期望: [1]

K=1 时唯一状态,转移矩阵为 [[1.0]],分布永不变化。

Case 4 · visible: identity transition_matrix preserves distribution for any H

输入: [[0.4,0.35,0.25],[[1,0,0],[0,1,0],[0,0,1]],7]

期望: [0.4,0.35,0.25]

单位转移矩阵:每个评级以概率 1.0 留在原地,分布对任意 H 都不变。

Case 5 · visible: deterministic start [1,0,0] gives 0-th row of TM^H

输入: [[1,0,0],[[0.7,0.2,0.1],[0,0.9,0.1],[0,0,1]],3]

期望: [0.3429999999999999,0.386,0.271]

起始全部位于评级 0 时,输出等于 TM^H 的第 0 行。