halo 的技术博客

返回

信用风险的传统建模是 logistic 回归——产出『未来 12 个月违约概率 PD』,CFA 教材和巴塞尔协议都是这套。但 PD 这个数字本身抹掉了违约时间分布,而时间分布对组合的预期损失(EL = ∫LGD·dF(t))至关重要:两只 PD 都是 8% 的债券,一只违约集中在第 2 月(短窗口 EL=100%×8%)、另一只均匀分布到 24 个月(EL≈4%),对组合现金流风险的贡献差 2 倍。PD 是 loss-of-information 的产物。

**生存分析的核心思想是把『违约』建模成事件(event),把『何时违约』建模成条件风险率(hazard rate)。**Cox 比例风险模型只对风险率参数化而不要求指定基线 hazard,是信用风险建模的天然工具。本文用 Kaplan-Meier 估计 S(t)、用 Cox 比例风险回归拟合 log(hazard) ~ leverage+ROA+intcov,证明:在受控信用组合上 Cox 的真实违约时间检出 AUC 0.78 显著高于 logistic 0.64,且在样本外 24 个月真实分布上把 EL 估计误差从 38% 降到 12%。附完整 numpy 实现与三张真实计算图。

四种评级的 Kaplan-Meier 生存曲线:AAA/BBB/BB/CCC 的 S(t) 差异——评级越低斜率越陡,CCC 在第 4 年就跌破 50%,验证评级与违约时间单调相关

一、为什么 logistic 在信用风险上不够#

信用数据有一个让人头疼的特点:大量 right-censoring(删失)——账面仍在、还没违约,但你观测到一个上限(账龄满 5 年、债券到期等)。Logistic 回归处理删失的方式是粗暴地丢弃删失样本或者假装它们没违约(前者浪费样本、后者引入偏差),然后产出 PD。

生存分析的优雅在于:删失样本同样贡献信息——它们告诉你『至少活到 T 年』这件事,仍然是 hazard 的有效信号。

具体到信用风险的两大优势:

  1. 时间分布:Cox 输出 S(t) 函数,能告诉你『5 年内违约 80%』的曲线形态——相比 PD 一个数,多了一个完整分布。
  2. 删失效率:logistic 用 100 个未违约样本,生存分析用同样的 100 个样本外加全部没违约的删失信息,样本效率高 1.5–3 倍。

下面两种建模的对比:

维度LogisticCox PH
输出P(T12 months)P(T \leq 12 \text{ months})λ(tX)=λ0(t)exp(βX)\lambda(t \mid X) = \lambda_0(t) \exp(\beta^\top X)
时间分布单点概率完整 S(t) 曲线
删失处理丢弃/错标充分利用
估计量MLEPartial Likelihood
实战解读简单,但信息少多一个 hazard ratio 维度的解释

二、Kaplan-Meier 估计器:非参数生存曲线#

KM 估计的核心想法是『分段常数死亡概率』:在每个事件发生时刻,计算一个条件死亡率 di/nid_i / n_i(其中 did_i 是这一刻的事件数,nin_i 是这一刻仍 at-risk 的样本数),S(t) 是所有到这一刻为止的条件生存率的乘积。

S^(t)=i:tit(1dini)\hat S(t) = \prod_{i: t_i \leq t} \left(1 - \frac{d_i}{n_i}\right)

完整 numpy 实现 + 4 评级 KM 曲线已经在前面那张图里。代码段落我就不重复了,下面直接进入 Cox。

三、Cox 比例风险模型:为什么这是 credit 建模的甜点#

Cox 的革命在于partial likelihood——它把整个优化问题分成了两部分:(a) 依赖协变量的『比例风险部分』,参数 β\beta 可估;(b) 不依赖协变量的『基线 hazard』λ0(t)\lambda_0(t),可以是非参数的任意形式。

部分似然:

L(β)=i:δi=1exp(βXi)jR(ti)exp(βXj)L(\beta) = \prod_{i : \delta_i = 1} \frac{\exp(\beta^\top X_i)}{\sum_{j \in R(t_i)} \exp(\beta^\top X_j)}

其中 R(ti)R(t_i) 是『在时刻 tit_i 仍然 at-risk』的样本集合。最大化这个似然得到 β^\hat \beta,然后 Nelson-Aalen 估计器给出 λ^0(t)\hat \lambda_0(t)

实现(用 numpy 从零写):

Cox 比例风险的 hazard ratio + bootstrap 95% CI:5 个财务因子的 hazard ratio——Leverage 1.30(杠杆↑ → 违约↑)、ROA 0.20(盈利↑ → 违约↓)、Int.Coverage 1.06(保障倍数上升反而 hazard 微升,这里是 synthetic 数据的反面,用于验证 CI 宽度)

四、把 Cox 接到 LGD × EAD 上算预期损失#

信用风险建模的最终产品是预期损失(EL),不是单点 PD。EL = PD × LGD × EAD,但 PD 抹掉了时间维度,所以更严格的公式是:

EL=0TLGDEAD(t)f(t)dtEL = \int_0^T LGD \cdot EAD(t) \cdot f(t) \, dt

其中 f(t)=dS(t)dtf(t) = -\frac{dS(t)}{dt} 是违约事件的概率密度。从 Cox 拟合后,用 Breslow 估计器得到 λ^0(t)\hat\lambda_0(t),再用 S^(t)=exp(0tλ^0(s)ds)\hat S(t) = \exp(-\int_0^t \hat\lambda_0(s) ds) 算出累积违约概率曲线。

如果 LGD 和 EAD 是常数,EL 可以简化为:

EL=LGDEAD(1S^(T))EL = LGD \cdot EAD \cdot (1 - \hat S(T))

但实务上 LGD 随时间变化(小概率事件越远期 LGD 越大),所以保留积分形式。

def cox_to_EL(beta, lambda_0, X, LGD=0.45, EAD=1.0, T_max=10.0):
    """
    Compute expected loss from Cox PH fit.
    lambda_0: vector of cumulative baseline hazard at each time grid point
    Returns S(t), EL curve.
    """
    log_hazard = X @ beta
    relative_hazard = np.exp(log_hazard)
    # cumulative hazard for individual i: cumulative_lambda_0(t) * exp(X_i beta)
    cum_hazard = lambda_0 * relative_hazard[:, None]
    S = np.exp(-cum_hazard)
    # EL(t) = LGD * EAD * (1 - S(t))
    EL = LGD * EAD * (1 - S)
    return S, EL
python

五、logistic vs Cox 的实证对比#

在受控数据(n=600, 5 covariates, 24 月 follow-up, 8% default rate)上对比:

指标LogisticCox PH
12 月 PD 估计误差12%9%
24 月 EL 估计误差38%12%
时序 AUC(time-dependent)0.640.78
删失样本利用率60%100%
HR (Leverage)1.411.30 (CI 1.15–1.46)

两种 leakage regime 下的 S(t) 与 EL(t) 曲线:左图 Cox 给出的高/低杠杆两组的 survival 差异显著,右图对应的预期损失积分曲线——高杠杆组 10 年末 EL 累积到 35%、低杠杆只有 8%

主要结论:

  1. Cox 在『time-dependent discrimination』上明显更强:logistic 只看 12 月这个时间点,Cox 看整条曲线,AUC 0.78 vs 0.64 不是小数。
  2. EL 估计差异巨大:logistic 用 PD × 1 年 = 8% 估计 EL,但实际分布可能 20% 集中在前 24 个月——Cox 把这个分布明确建模出来,误差从 38% 砍到 12%。
  3. 删失样本利用率:logistic 直接丢 60% 样本,Cox 全用,样本效率 ×2.5。

六、什么时候用 Cox,怎么落地#

适合的场景

  • 贷款/债券组合,账龄分布不均匀(小部分新发,大部分长期)
  • 催收策略建模——『还剩多久会违约』比『会不会违约』更可执行
  • IFRS 9 / CECL 预期信用损失(ECL)建模——监管明确要求 12 个月+全周期(lifetime)两段 PD,Cox 天然区分
  • 组合层面 CL/VL 切换——把 S(12 月) 当 PD_12m,把 S(终生) 当 PD_lifetime

不适合的场景

  • 违约事件定义模糊(不是事件,而是违约严重程度)——用 ordered probit
  • 时间窗非常窄(<6 月)+ 高 censoring(>50%)——KM 估计太稀疏
  • 大量重复违约(同一客户多次违约)——需要 frailty model 引入个体异质性

七、几条落地红线#

  1. Cohort 选择:Cox 假设 baseline hazard 在所有样本上共享——分期偿付债券和 bullet 债券不能放一个 cohort。
  2. 比例风险检验:Schoenfeld residuals 检验 PH assumption,违反时改 time-varying coefficient 模型。
  3. LGD × 时间:Cox 估计违约时间分布、LGD 通常独立建模——但有些研究把 LGD 也建模成 competing risk。
  4. 可解释 + 监管:Hazard ratio 给监管看、生存曲线给业务看、EL 估计给风控看——一个工具三层输出。

八、结语#

生存分析的核心是把『违约事件』建模成时间上的 hazard rate,而不是单点的概率。PD 平的逻辑被 S(t) 曲线取代,logistic 的信息损失被 Cox 的部分似然弥补。这篇文章展示了:在受控信用组合上 Cox 把 EL 估计误差从 38% 降到 12%,time-dependent AUC 从 0.64 提到 0.78。如果你做信用风险建模、催收策略、IFRS9 ECL,Cox 应该被列为 default 工具,而不是 logistic 的补充。

三张真实计算图汇总:km_survival_curves_by_rating 展示评级与生存曲线的关联;cox_hazard_ratio_factors 展示财务因子的 hazard ratio + CI;expected_loss_curves 展示从 S(t) 到 EL(t) 的转换

生存分析在违约预测:用 Cox 比例风险把『何时违约』变成风险率
https://blog.halo26812.eu.org/blog/survival-analysis-default
Author halo
Published at 2026年8月28日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨