halo 的技术博客

返回

先说结论:分开估计多条分位数曲线(不管用分位数回归、CAViaR 还是神经网络)没有任何机制保证 5% 分位数预测得比 10% 低——两条曲线可以交叉,交叉处模型在逻辑上自相矛盾:它声称”损失超过 -1.2 的概率是 5%,超过 -1.0 的概率是 10%“,但 -1.2 比 -1.0 更极端,概率不可能反过来。Chernozhukov-Fernández-Val-Galichon(2010)证明了一个几乎免费的修法:把每个点上的多条分位数预测直接排序(重排/rearrangement),排序后的预测在任何情况下都弱优于原始预测——不是平均更好,是逐点不变差。我在异方差 t(5) 模拟上实测:400 个训练样本 + 三次多项式分位数回归,4.2% 的测试点出现 τ=0.05 与 τ=0.10 曲线交叉,交叉幅度最大 0.196(约为当地分位数间距的两倍);重排后交叉清零,pinball 损失在每个 τ 上都不变差。改进幅度诚实地说很小(总损失 -0.01%),但这不是重排的卖点——卖点是它以零成本消灭了”风险报告在逻辑上自相矛盾”这类灾难

问题:分位数打架#

分位数回归(Koenker-Bassett 1978)的标准用法是对每个感兴趣的水平 τ 单独解一个 pinball 损失最小化:

β^(τ)=argminβtρτ(ytxtβ)\hat\beta(\tau) = \arg\min_\beta \sum_t \rho_\tau(y_t - x_t'\beta)

τ=0.05 的回归和 τ=0.10 的回归是两个完全独立的优化问题,各自看到的是同一批数据的不同侧面,各自带各自的估计噪声。真实的条件分位数函数 Qτ(yx)Q_\tau(y|x) 对 τ 单调递增是数学必然,但两个独立估计的差 Q^0.10Q^0.05\hat Q_{0.10} - \hat Q_{0.05} 是一个随机变量——只要它的标准误超过真实间距,就有实打实的概率翻负。

什么时候容易翻负:

  • 尾部:τ=0.05 和 τ=0.10 的真实间距本来就窄,而尾部分位数的估计方差恰恰最大;
  • 协变量边缘:x 的取值稀疏区(我的实验里交叉全部发生在 x<0.05 的边缘带),回归外推最不稳的地方;
  • 模型越灵活越糟:多项式、样条、梯度提升、神经网络,自由度越高,各条曲线各自乱抖的空间越大;
  • 样本越小越糟:这是下面功效实验的主角。

对量化场景这不是美学问题。VaR 台账上 99% VaR 比 97.5% VaR 还浅,监管直接打回;用多分位数预测构造的区间 [Q^0.05,Q^0.95][\hat Q_{0.05}, \hat Q_{0.95}] 可能出现负宽度;把分位数曲线当逆 CDF 反演生成情景样本时,非单调的”逆 CDF”根本不是一个合法的分布。

CFG 重排:排序就是修复#

Chernozhukov, Fernández-Val 和 Galichon(2010, Econometrica)的方案简单到令人怀疑:在每个 x 处,把 K 条分位数预测从小到大排序,把排序后的值重新按 τ 从小到大分配

(Q^τ1(x),,Q^τK(x))=sort(Q^τ1(x),,Q^τK(x))\big(\hat Q^*_{\tau_1}(x), \dots, \hat Q^*_{\tau_K}(x)\big) = \text{sort}\big(\hat Q_{\tau_1}(x), \dots, \hat Q_{\tau_K}(x)\big)

排序后的序列天然单调,交叉被定义消灭。真正不平凡的是他们证明的性质:

定理(CFG 2010):对任何真实分位数函数 Qτ(x)Q_\tau(x) 和任何 p ≥ 1,重排后的估计到真值的 LpL^p 距离弱小于原始估计:

Q^QpQ^Qp\big\| \hat Q^* - Q \big\|_p \le \big\| \hat Q - Q \big\|_p

且只要原始估计确实有交叉,不等式严格成立。

直觉:真值是单调的,估计不单调,说明估计里有一部分”非单调噪声”。排序恰好只砍掉这部分噪声——它不动没有交叉的地方,只在打架的地方把值重新分配到正确的次序上,而正确的次序正是真值所在的次序。这是一个投影:把估计投影到单调函数锥上,而真值就在锥里,投影只会拉近距离

import numpy as np

def rearrange(Q):
    """Q: (K, N) 数组,K 个分位数水平 × N 个预测点。
    逐列排序 = CFG 重排。就这一行。"""
    return np.sort(Q, axis=0)
python

值得强调它的三个”免费”属性:不需要重新训练、不依赖底层模型(对 quantile regression / CAViaR / LightGBM quantile / 神经网络一视同仁)、计算量 O(NK log K)。

实验:异方差 t(5) 收益 + 三次多项式分位数回归#

数据生成过程模仿”波动率信号 → 收益”的场景:y=0.1x+(0.5+0.9x)εy = 0.1x + (0.5 + 0.9x)\,\varepsilonε\varepsilon 为标准化 t(5),x∈[0,1] 是可观测的条件变量(可以想象成 VIX 的归一化)。真实条件分位数解析可知,方便验尸。

训练 400 个样本,用带三次项的分位数回归拟合 τ ∈ {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95} 七条曲线,测试 4000 个点:

import statsmodels.formula.api as smf

taus = [0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95]
params = {}
for tau in taus:
    mod = smf.quantreg("y ~ x + x2 + x3", df_train).fit(q=tau)
    params[tau] = mod.params.values     # 每个 τ 独立估计

Q_raw = np.vstack([predict(params[t], x_test) for t in taus])  # (7, 4000)
crossed = (np.diff(Q_raw, axis=0) < 0).any(axis=0)
print(f"交叉比例: {crossed.mean():.1%}")   # → 4.2%

Q_fixed = np.sort(Q_raw, axis=0)            # CFG 重排
python

结果:168/4000 = 4.2% 的测试点出现交叉,全部发生在 τ=0.05 与 τ=0.10 这一对之间(其余六对相邻曲线零交叉),且全部集中在 x < 0.05 的左边缘——数据稀疏 + 尾部 + 多项式外推,三个风险因子同时命中。交叉幅度不小:q05 最多高出 q10 达 0.196,交叉点平均violation 0.103,大约是当地真实分位数间距的一到两倍。

七条分位数曲线:独立拟合打架,重排后恢复单调

在交叉最严重的 x 处把”分位数作为 τ 的函数”切出来看,非单调一目了然:

单个 x 处的分位数函数:τ 增大预测反而变小

重排的收益:小但严格不亏#

逐 τ 对比样本外 pinball 损失:

τ原始重排后变化
0.050.111210.11118-0.03%
0.100.172340.17216-0.10%
0.25~0.95完全不变

每个 τ 上 pinball 都不变差

两个观察:

第一,改进只出现在交叉发生的那两条曲线上,其他五条纹丝不动——重排是外科手术,不碰健康组织。这正是 CFG 定理”弱优于”的实测形态。

第二,精度改进量级很小(总 pinball -0.01%)。如果你指望重排提升预测精度排行榜名次,会失望。它的真实价值在别处:4.2% 的预测点从”逻辑上不可能的分布”变成了合法分布。风险报告里一次”99% VaR 比 95% 还浅”的事故成本,远大于 pinball 第四位小数的得失。重排买的是合法性,精度改进是搭赠的

交叉率与样本量:小样本才是重灾区#

固定测试集,把训练样本从 200 扫到 3200,每档 40 次蒙特卡洛:

训练样本测试点交叉率重排 pinball 改进
2003.96%0.014%
4000.60%0.001%
8000.16%~0
16000.03%~0
32000.00%0

样本越少交叉越严重

交叉是有限样本现象:分位数回归估计量是一致的,样本无穷大时各条曲线都收敛到真值,真值单调,交叉自然消失。但量化研究恰恰长期生活在小样本区:一年日频数据 250 个点,按月重估的滚动窗口经常只有几百个观测——正好落在交叉率百分之几的重灾区。样本越小,重排越不是可选项

(细心的读者会注意到主实验的 400 样本交叉率 4.2%、蒙特卡洛平均却只有 0.6%——因为主实验那颗种子恰好抽到了一个边缘数据特别稀疏的训练集。交叉率本身方差很大,这也是它讨厌的地方:多数日子没事,出事的那天你的报表正好不合法。)

重排之外的选择#

重排是事后修复,还有几类事前方案,各有代价:

  1. 同时估计 + 单调约束:把所有 τ 放进一个优化问题,加 fτk+1(x)fτk(x)f_{\tau_{k+1}}(x) \ge f_{\tau_k}(x) 约束(如 Bondell et al. 2010)。优点是估计阶段就消灭交叉且可能借力相邻分位数共享信息;代价是优化问题变大变难,且对每类模型要单独推导;
  2. 分布式建模:不估 K 条分位数,直接估一个单调参数化的条件分布(如正态混合、样条 CDF),分位数从分布反解,天然单调。代价是绕回了”要假设分布形状”的老路——CAViaR 们当初逃离的正是这里;
  3. 增量参数化:神经网络里常用的技巧,输出 qτ1q_{\tau_1} 和 K-1 个非负增量 Δk=softplus()\Delta_k = \text{softplus}(\cdot),累加得到单调序列。干净,但只适用于你能改架构的模型;
  4. 保序回归(isotonic regression):对有限个 τ 的场景,逐点保序回归的解就是排序,与重排等价;当 τ 是连续统时保序回归是更一般的投影。

实务排序建议:能改模型架构就用增量参数化(方案 3);用现成库的多分位数模型(LightGBM、statsmodels、CAViaR 逐层估计)就在预测后无脑接一行 np.sort没有任何理由裸奔——重排的成本是零,而 CFG 定理保证它永不反噬。

工程清单#

  1. 交叉检测要进单元测试:任何多分位数预测管道,输出前断言 (np.diff(Q, axis=0) >= 0).all(),违背就报警并记录发生位置——交叉集中出现的区域就是模型最不可信的区域,这个信息本身有诊断价值;
  2. 重排放在最后一步,在所有模型输出汇合之后、进入下游(区间构造、情景生成、VaR 报表)之前;
  3. 别用重排掩盖模型问题:交叉率如果高到 10% 以上,说明模型方差失控(特征太多/样本太少/外推太远),重排只是止血带,该做的是正则化或简化模型;
  4. 监控交叉率的时间序列:滚动重估的系统里,交叉率突然飙升往往意味着新窗口里出现了异常数据或市场进入了训练集没见过的状态。

诚实边界#

  • 重排不改进”没有交叉的地方”:它对模型的系统性偏差(比如整体低估尾部)完全无能为力——那是 Kupiec/DQ 检验负责发现、换模型负责修复的问题;
  • CFG 定理比较的是”到真值的距离”,需要真值单调这个前提。条件分位数对 τ 单调是数学事实所以前提永真,但如果你的”多条曲线”不是同一个分布的分位数(比如不同资产各一条),排序毫无意义;
  • 重排后的曲线可能不平滑:排序在交叉边界处引入折角,对需要对 τ 求导的应用(密度反演)要配平滑化;
  • 本文实验是模拟数据 + 已知真值,真实市场里你看不到真实分位数,只能通过样本外 pinball 和交叉率间接监控——好在 CFG 保证重排在看不见真值时依然不亏。

参考文献#

  • Chernozhukov, V., Fernández-Val, I., & Galichon, A. (2010). Quantile and Probability Curves Without Crossing. Econometrica, 78(3), 1093-1125.
  • Bondell, H. D., Reich, B. J., & Wang, H. (2010). Noncrossing Quantile Regression Curve Estimation. Biometrika, 97(4), 825-838.
  • Koenker, R., & Bassett, G. (1978). Regression Quantiles. Econometrica, 46(1), 33-50.
分位数交叉与重排:修复多分位预测的次序违背
https://blog.halo26812.eu.org/blog/quantile-crossing-rearrangement
Author halo
Published at 2026年7月27日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨