← 返回编程题库
coding-portfolio-expected-loss-by-bucket中等免费版2000ms未尝试

组合预期损失分桶聚合:PD x LGD x EAD 瀑布

Portfolio Expected Loss by Bucket: PD x LGD x EAD Waterfall

开始编码

实现 solution(pd: list[float], lgd: list[float], ead: list[float], bucket: list[int], num_buckets: int) -> list[float]。某企业信贷台按子组合(行业桶、评级桶、区域桶等)汇报组合预期损失(EL),便于风险官看到各子组合对全台 EL 的贡献占比。给定四条长度为 N 的平行数组:pd[i] 是债务人 i 在汇报视野内的违约概率,lgd[i] 是违约损失率(违约时损失敞口的比例),ead[i] 是违约时的美元敞口,bucket[i] 是债务人 i 所属子组合桶的整数索引;同时给定 num_buckets,即桶总数 B

[0, num_buckets) 内每个桶 b,计算 el_by_bucket[b]:所有满足 bucket[i] == b 的下标 ipd[i] * lgd[i] * ead[i] 之和。返回长度为 num_buckets、按桶 id 位置编码的 list[float]。**单笔债务人的预期损失是 PD * LGD * EAD 的乘积,不是求和**——这是 Basel II/III 内评法(IRB)框架里的基础信用风险瀑布;量纲检查:概率 * 无量纲分数 * 美元 = 美元,而 PD + LGD + EAD 把概率与美元相加,毫无意义。**空桶必须以 0.0 出现在对应索引位**、不能省略——输出始终恰好为 num_buckets 个 float。

solution([0.05, 0.10, 0.02], [0.40, 0.50, 0.60], [1000000.0, 500000.0, 2000000.0], [0, 1, 0], 3) 返回 [44000.0, 25000.0, 0.0]。逐债务人扫描:债务人 0 的 EL = 0.05 * 0.40 * 1,000,000 = $20,000、入桶 0。债务人 1 的 EL = 0.10 * 0.50 * 500,000 = $25,000、入桶 1。债务人 2 的 EL = 0.02 * 0.60 * 2,000,000 = $24,000、也入桶 0。桶 0 总额 $20,000 + $24,000 = $44,000,桶 1 总额 $25,000,桶 2 无债务人故 EL 为 $0。输出按桶 id 位置编码、得 [44000.0, 25000.0, 0.0]——空桶 2 确实在输出里、是 0.0 项。

EL 公式的正本清源:PD=0.05、LGD=0.4、EAD=$1,000,000 给出 EL = 0.05 * 0.4 * 1,000,000 = $20,000不是 0.05 + 0.4 + 1,000,000 = $1,000,000.45。EL 是三因子的乘积——写成 pd[i] + lgd[i] + ead[i] 等于把概率和美元相加,得到的数字量纲错乱、并且在典型量级算例上偏离正确值约 50 倍。

需要明确的细节:N == 0 返回 [0.0] * num_buckets——输出长度恒为 num_buckets、绝不为 0bucket[] 中从未出现的桶 id b 仍然在索引 b 位贡献一个 0.0 项。每个 PD、LGD 都是 [0, 1] 内的概率/分数(不是 [0, 100] 内的百分数);pd * lgd * ead 的量纲为美元。本函数不抛异常——调用方保证每个 bucket[i] 都在 [0, num_buckets),无需防御性边界检查。

期望算法:单遍 O(N + B)——预分配 el_by_bucket = [0.0] * num_buckets、对每个债务人 iel_by_bucket[bucket[i]] += pd[i] * lgd[i] * ead[i]、返回。循环对象是债务人、累加目标是按桶 id 索引的定长输出,所以没有 off-by-one。

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

实践背景

每个交易日,企业信贷台的信用风险口都会做一次 EL 归因:组合的总预期损失里,多少集中在哪些子组合上——按行业、按内评、按区域,或按交易台关心的任意一种风险归因切片。EL = PD * LGD * EAD 瀑布是 Basel II/III 内评法(IRB)框架的基础公式:PD 是债务人在视野内的违约概率,LGD 是回收调整后的违约损失分数,EAD 是违约瞬时的美元敞口。三者相乘即单笔债务人的期望美元损失,桶内求和即得到该子组合的 EL 贡献。solution(...) 的输出喂入信贷台的每日信用风险归因面板,风险官在面板上识别哪些子组合主导了机构的 EL 数字、在哪里需要追加资本、做对冲、或收紧限额。空桶以 0.0 出现,让面板可以在每日报表上稳定渲染所有桶的车道、即便当下无债务人映射进去。

约束条件

  • 0 <= N <= 1500,其中 N == len(pd) == len(lgd) == len(ead) == len(bucket)
  • 1 <= num_buckets <= 50
  • 0.0 <= pd[i] <= 1.0(违约概率——是概率而不是百分数)
  • 0.0 <= lgd[i] <= 1.0(违约损失率——无量纲分数)
  • 0.0 <= ead[i] <= 1e9(违约时敞口、美元、非负)
  • 0 <= bucket[i] < num_buckets(调用方前置条件,无需防御性检查)
  • 输出为长度 num_buckets 的 list[float];每项非负;按 rel_tol=1e-9、abs_tol=1e-9 比对

样例

Case 1 · statement-example: 3-obligor PD x LGD x EAD waterfall with one empty bucket

输入: [[0.05,0.1,0.02],[0.4,0.5,0.6],[1000000,500000,2000000],[0,1,0],3]

期望: [44000,25000,0]

债务人 0: 0.05*0.4*1e6=20000 入桶 0;债务人 1: 0.1*0.5*5e5=25000 入桶 1;债务人 2: 0.02*0.6*2e6=24000 入桶 0。桶 0=44000,桶 1=25000,桶 2 无债务人=0。

Case 2 · visible: N=0 returns list of B zeros (length B, not empty list)

输入: [[],[],[],[],3]

期望: [0,0,0]

N=0 时输出长度仍为 num_buckets=3,全部为 0.0。

Case 3 · visible: single obligor formula sanity check (product not sum)

输入: [[0.5],[0.5],[100],[0],1]

期望: [25]

单债务人: EL = 0.5*0.5*100 = 25.0 (不是 0.5+0.5+100=101)。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · statement-example: 3-obligor PD x LGD x EAD waterfall with one empty bucket

输入: [[0.05,0.1,0.02],[0.4,0.5,0.6],[1000000,500000,2000000],[0,1,0],3]

期望: [44000,25000,0]

债务人 0: 0.05*0.4*1e6=20000 入桶 0;债务人 1: 0.1*0.5*5e5=25000 入桶 1;债务人 2: 0.02*0.6*2e6=24000 入桶 0。桶 0=44000,桶 1=25000,桶 2 无债务人=0。

Case 2 · visible: N=0 returns list of B zeros (length B, not empty list)

输入: [[],[],[],[],3]

期望: [0,0,0]

N=0 时输出长度仍为 num_buckets=3,全部为 0.0。

Case 3 · visible: single obligor formula sanity check (product not sum)

输入: [[0.5],[0.5],[100],[0],1]

期望: [25]

单债务人: EL = 0.5*0.5*100 = 25.0 (不是 0.5+0.5+100=101)。