基于矩匹配的违约损失率(LGD)Beta 分布校准
LGD Beta-Distribution Calibration via Method of Moments
开始编码实现 solution(mean_lgd: float, std_lgd: float) -> list[float]。某信用风险口要把 LGD 分布校准到一组目标均值和标准差,做法是用矩匹配把 Beta 分布拟合到这两个矩。两个标量输入:目标均值 mean_lgd(严格位于 (0, 1))和目标标准差 std_lgd(非负)。返回 [alpha_param, beta_param]——匹配的 Beta 参数。
矩匹配共四步。第 1 步:把标准差平方得方差 v = std_lgd * std_lgd。第 2 步:计算 Bernoulli 上界 bound = mean_lgd * (1 - mean_lgd) 并校验 v < bound;任何 [0, 1] 上支撑的随机变量(含 Beta)方差都严格小于 bound,因此 v >= bound 时无 Beta 匹配。第 3 步:算缩放因子 s = bound / v - 1(等于 alpha + beta)。第 4 步:按均值切分 alpha_param = mean_lgd * s、beta_param = (1 - mean_lgd) * s。所得 Beta 的均值与方差正好是 (m, v)。
例
solution(0.5, 0.2) 返回 [2.625, 2.625]。逐步:方差 v = 0.04。上界 = 0.5 * 0.5 = 0.25。v=0.04 < 0.25,校验通过。缩放 s = 0.25 / 0.04 - 1 = 5.25。切分 alpha = 0.5 * 5.25 = 2.625、beta = 0.5 * 5.25 = 2.625。对称 Beta 与 m=0.5(无偏)+ 中等波动一致。
第二个例子。solution(0.4, 0.1) 返回 [9.2, 13.8]。v = 0.01、bound = 0.4 * 0.6 = 0.24、s = 0.24/0.01 - 1 = 23、alpha = 0.4*23 = 9.2、beta = 0.6*23 = 13.8。mean<0.5 时 Beta 右偏。
哨兵与陷阱
两个哨兵让规约在声明区间内闭合。其一,std_lgd == 0 时方差为 0,公式给出 s = m*(1-m)/0 = +inf,alpha = m*s 与 beta = (1-m)*s 均为 +inf。规约返回 [float('inf'), float('inf')]。无穷参数的 Beta 极限就是 mean 处的 Dirac 点质量——"无离散度"的自然退化校准。要在平方之前识别 std_lgd == 0,避免依赖 1/0 的 IEEE 行为。其二,v >= mean*(1-mean) 时矩匹配无 Beta 解:[0, 1] 上的 Beta 方差受 mean*(1-mean) 上界(Bernoulli 上界)约束。规约返回 [float('nan'), float('nan')]。要在算 s 之前识别这种情形,否则 s 变非正、公式会输出负的 Beta 参数——这不是合法解。
五个陷阱:
- 方差,不是标准差。先平方:
v = std_lgd * std_lgd。直接把std_lgd塞进m*(1-m)/std - 1会产生量纲错误的s,与矩匹配答案大相径庭。 - 有效性上界,不是仅非零。判定是
v < mean*(1-mean),不是v > 0。漏掉判定会让s在高方差输入下变负、并输出负的 alpha/beta——永远不是合法 Beta 参数。Python 容忍这种数学不代表它正确。 - **
alpha = m*s、不是(1-m)*s**。Beta(a, b) 的均值是a/(a+b),所以"均值侧"参数是alpha。把方向写反会让 alpha 与 beta 互换;得到的 Beta 均值变成1-m而不是m——一种数字仍然像样的隐性 bug(本测试套中的镜像用例会抓到)。 - 二元 list、顺序固定为 [alpha, beta]。返回 tuple、NumPy 数组、标量、或
[beta, alpha]都违约。比对器按ordered: true逐元素比。 - **
std_lgd == 0返回[+inf, +inf],不是[NaN, NaN]**。两个哨兵含义不同:+inf表"校准为均值处点质量";NaN表"该矩组合无 Beta 可匹配"。混用会让按哨兵种类分支的下游模拟器走错路径。
函数 O(1) 时间、O(1) 空间——无循环、除两元素输出外无分配。
实现细节由 stubs/stub.py 提供。
实践背景
在 IFRS 9 / Basel IRB 下,银行将 LGD 分布建模为 [0, 1] 上的 Beta,原因是:(a) 支撑区间天然契合 LGD 的取值范围;(b) 两个参数恰好够固定历史抵押与回收数据所给出的两个关键输入——均值与波动率。矩匹配从 (m, s) 直接给出闭式 Beta 参数,无需迭代优化。在工程上这是给入随机信用损失模拟前的校准步骤:(alpha, beta) 一旦定下来,模拟器就从 Beta(alpha, beta) 抽样生成逐户 LGD 情景;与 PD 情景、EAD 组合后形成蒙特卡洛损失分布,喂入经济资本与 IFRS 9 stage-2/stage-3 拨备。五个陷阱中的任何一个写错——方差/标准差、有效性上界、参数方向、输出形状、退化哨兵种类——都会直接传导到 Monte-Carlo 损失分布以及上报的监管与会计数字。
约束条件
- 0.001 <= mean_lgd <= 0.999(LGD 目标均值,严格在开单位区间内)
- 0.0 <= std_lgd <= 0.5(LGD 目标标准差,非负)
- 输出为 list[float],长度 2:[alpha_param, beta_param],可行时均为正;std_lgd==0 时均为 +inf;v >= mean*(1-mean) 时均为 NaN
- 全部按 rel_tol=1e-9、abs_tol=1e-9 比对;nan_equals_nan 为 true
- 在声明区间内的任何输入都不得抛异常
样例
Case 1 · statement-example: mean=0.5, std=0.2 symmetric Beta
输入: [0.5,0.2]
期望: [2.6249999999999996,2.6249999999999996]
v=0.04;m*(1-m)=0.25;s=0.25/0.04-1=5.25;alpha=0.5*5.25=2.625;beta=0.5*5.25=2.625;对称 Beta。
Case 2 · statement-example: mean=0.4, std=0.1 asymmetric Beta
输入: [0.4,0.1]
期望: [9.199999999999998,13.799999999999995]
v=0.01;m*(1-m)=0.24;s=0.24/0.01-1=23;alpha=0.4*23=9.2;beta=0.6*23=13.8;右偏的 LGD 形态。
Case 3 · typical: mean=0.3, std=0.1 mid-low LGD
输入: [0.3,0.1]
期望: [5.999999999999999,13.999999999999996]
v=0.01;m*(1-m)=0.21;s=20;alpha=6;beta=14;mean<0.5 时 alpha<beta。
Case 4 · typical: mean=0.7, std=0.15 high LGD bucket
输入: [0.7,0.15]
期望: [5.833333333333333,2.5000000000000004]
v=0.0225;m*(1-m)=0.21;s=0.21/0.0225-1=8.333...;alpha=0.7*s≈5.833;beta=0.3*s=2.5。
Case 5 · typical: mean=0.25, std=0.2 wide-volatility low-mean Beta
输入: [0.25,0.2]
期望: [0.9218749999999998,2.765624999999999]
v=0.04;m*(1-m)=0.1875;s=0.1875/0.04-1=3.6875;alpha=0.25*s≈0.9219;beta=0.75*s≈2.7656;s 较小 -> Beta 接近 U 形端点厚尾。
Case 6 · typical: mean=0.75, std=0.2 mirror of 0.25 case (alpha<->beta swap)
输入: [0.75,0.2]
期望: [2.765624999999999,0.9218749999999998]
镜像于 mean=0.25 的情形:alpha 与 beta 互换。验证作者没有把 alpha 写成 (1-m)*s。
Case 7 · typical: mean=0.6, std=0.25 broad LGD distribution
输入: [0.6,0.25]
期望: [1.704,1.136]
v=0.0625;m*(1-m)=0.24;s=0.24/0.0625-1=2.84;alpha=0.6*2.84=1.704;beta=0.4*2.84=1.136。
Case 8 · typical: mean=0.45, std=0.15 near-symmetric calibration
输入: [0.45,0.15]
期望: [4.500000000000001,5.500000000000002]
v=0.0225;m*(1-m)=0.2475;s=10;alpha=0.45*10=4.5;beta=0.55*10=5.5。
Case 9 · typical: mean=0.55, std=0.15 mirror near-symmetric calibration
输入: [0.55,0.15]
期望: [5.5,4.5]
镜像于 mean=0.45:alpha=5.5、beta=4.5;再次验证 alpha=m*s 的方向。
Case 10 · typical: mean=0.2, std=0.1 left-skew calibration
输入: [0.2,0.1]
期望: [3,12]
v=0.01;m*(1-m)=0.16;s=15;alpha=0.2*15=3;beta=0.8*15=12;alpha+beta=15。
Case 11 · typical: mean=0.8, std=0.1 right-skew mirror of 0.2
输入: [0.8,0.1]
期望: [11.999999999999996,2.9999999999999982]
镜像于 mean=0.2,alpha 与 beta 互换;alpha=12、beta=3。
Case 12 · typical: mean=0.5, std=0.1 tight symmetric distribution
输入: [0.5,0.1]
期望: [11.999999999999998,11.999999999999998]
v=0.01;m*(1-m)=0.25;s=24;alpha=beta=12。
Case 13 · boundary: std=0 degenerate point mass returns [+inf, +inf]
输入: [0.5,0]
期望: ["Infinity","Infinity"]
std=0 触发哨兵:方差 0 时 s = m*(1-m)/0 -> +inf;alpha=beta=+inf;表示 Beta 退化为 mean 处的 Dirac 点质量。
Case 14 · boundary: variance == m*(1-m) exactly returns [NaN, NaN]
输入: [0.5,0.5]
期望: ["NaN","NaN"]
v=0.25 等于 m*(1-m)=0.25 的边界:Beta 分布的方差严格小于 m*(1-m),无 Beta 匹配;返回 [NaN, NaN]。
Case 15 · boundary: variance > m*(1-m) returns [NaN, NaN]
输入: [0.6,0.5]
期望: ["NaN","NaN"]
v=0.25 > m*(1-m)=0.24:超过 Bernoulli 方差上界,无 Beta 匹配;返回 [NaN, NaN]。
Case 16 · boundary: variance just below m*(1-m) yields very small s
输入: [0.5,0.49]
期望: [0.020616409829237847,0.020616409829237847]
v=0.2401 接近上界 0.25:s=0.25/0.2401-1≈0.0412;alpha=beta≈0.0206;Beta 形状极度向 0/1 端点集中。
Case 17 · boundary: small variance large s mean=0.5 std=0.05
输入: [0.5,0.05]
期望: [49.49999999999999,49.49999999999999]
v=0.0025;m*(1-m)=0.25;s=99;alpha=beta=49.5;s 大 -> Beta 集中在 mean 附近。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: mean=0.5, std=0.2 symmetric Beta
输入: [0.5,0.2]
期望: [2.6249999999999996,2.6249999999999996]
v=0.04;m*(1-m)=0.25;s=0.25/0.04-1=5.25;alpha=0.5*5.25=2.625;beta=0.5*5.25=2.625;对称 Beta。
Case 2 · statement-example: mean=0.4, std=0.1 asymmetric Beta
输入: [0.4,0.1]
期望: [9.199999999999998,13.799999999999995]
v=0.01;m*(1-m)=0.24;s=0.24/0.01-1=23;alpha=0.4*23=9.2;beta=0.6*23=13.8;右偏的 LGD 形态。
Case 3 · typical: mean=0.3, std=0.1 mid-low LGD
输入: [0.3,0.1]
期望: [5.999999999999999,13.999999999999996]
v=0.01;m*(1-m)=0.21;s=20;alpha=6;beta=14;mean<0.5 时 alpha<beta。
Case 4 · typical: mean=0.7, std=0.15 high LGD bucket
输入: [0.7,0.15]
期望: [5.833333333333333,2.5000000000000004]
v=0.0225;m*(1-m)=0.21;s=0.21/0.0225-1=8.333...;alpha=0.7*s≈5.833;beta=0.3*s=2.5。
Case 5 · typical: mean=0.25, std=0.2 wide-volatility low-mean Beta
输入: [0.25,0.2]
期望: [0.9218749999999998,2.765624999999999]
v=0.04;m*(1-m)=0.1875;s=0.1875/0.04-1=3.6875;alpha=0.25*s≈0.9219;beta=0.75*s≈2.7656;s 较小 -> Beta 接近 U 形端点厚尾。
Case 6 · typical: mean=0.75, std=0.2 mirror of 0.25 case (alpha<->beta swap)
输入: [0.75,0.2]
期望: [2.765624999999999,0.9218749999999998]
镜像于 mean=0.25 的情形:alpha 与 beta 互换。验证作者没有把 alpha 写成 (1-m)*s。
Case 7 · typical: mean=0.6, std=0.25 broad LGD distribution
输入: [0.6,0.25]
期望: [1.704,1.136]
v=0.0625;m*(1-m)=0.24;s=0.24/0.0625-1=2.84;alpha=0.6*2.84=1.704;beta=0.4*2.84=1.136。
Case 8 · typical: mean=0.45, std=0.15 near-symmetric calibration
输入: [0.45,0.15]
期望: [4.500000000000001,5.500000000000002]
v=0.0225;m*(1-m)=0.2475;s=10;alpha=0.45*10=4.5;beta=0.55*10=5.5。
Case 9 · typical: mean=0.55, std=0.15 mirror near-symmetric calibration
输入: [0.55,0.15]
期望: [5.5,4.5]
镜像于 mean=0.45:alpha=5.5、beta=4.5;再次验证 alpha=m*s 的方向。
Case 10 · typical: mean=0.2, std=0.1 left-skew calibration
输入: [0.2,0.1]
期望: [3,12]
v=0.01;m*(1-m)=0.16;s=15;alpha=0.2*15=3;beta=0.8*15=12;alpha+beta=15。
Case 11 · typical: mean=0.8, std=0.1 right-skew mirror of 0.2
输入: [0.8,0.1]
期望: [11.999999999999996,2.9999999999999982]
镜像于 mean=0.2,alpha 与 beta 互换;alpha=12、beta=3。
Case 12 · typical: mean=0.5, std=0.1 tight symmetric distribution
输入: [0.5,0.1]
期望: [11.999999999999998,11.999999999999998]
v=0.01;m*(1-m)=0.25;s=24;alpha=beta=12。
Case 13 · boundary: std=0 degenerate point mass returns [+inf, +inf]
输入: [0.5,0]
期望: ["Infinity","Infinity"]
std=0 触发哨兵:方差 0 时 s = m*(1-m)/0 -> +inf;alpha=beta=+inf;表示 Beta 退化为 mean 处的 Dirac 点质量。
Case 14 · boundary: variance == m*(1-m) exactly returns [NaN, NaN]
输入: [0.5,0.5]
期望: ["NaN","NaN"]
v=0.25 等于 m*(1-m)=0.25 的边界:Beta 分布的方差严格小于 m*(1-m),无 Beta 匹配;返回 [NaN, NaN]。
Case 15 · boundary: variance > m*(1-m) returns [NaN, NaN]
输入: [0.6,0.5]
期望: ["NaN","NaN"]
v=0.25 > m*(1-m)=0.24:超过 Bernoulli 方差上界,无 Beta 匹配;返回 [NaN, NaN]。
Case 16 · boundary: variance just below m*(1-m) yields very small s
输入: [0.5,0.49]
期望: [0.020616409829237847,0.020616409829237847]
v=0.2401 接近上界 0.25:s=0.25/0.2401-1≈0.0412;alpha=beta≈0.0206;Beta 形状极度向 0/1 端点集中。
Case 17 · boundary: small variance large s mean=0.5 std=0.05
输入: [0.5,0.05]
期望: [49.49999999999999,49.49999999999999]
v=0.0025;m*(1-m)=0.25;s=99;alpha=beta=49.5;s 大 -> Beta 集中在 mean 附近。