halo 的技术博客

返回

你训练一个波动率预测模型,喂进去「过去 5 日已实现波动率」,让它预测「明天波动率」。线性回归给你一个数,深度学习给你一个数——但你不知道这个数靠不靠谱:在样本密集区它或许准,在从没见过的极端区间它可能差出天际,却还是一脸自信。

高斯过程(Gaussian Process, GP)回归不一样。它输出的是一个完整的后验分布:每个 x 上都有均值 μ(x) 和方差 σ²(x)。于是你拿到的不是「明天波动率 2.3%」,而是「明天波动率 2.3% ± 0.8%,而且在这个区间我特别没把握、σ 飙到了 2.1%」。这张可信度地图,是 GP 在金融风控里最值钱的东西。

结论先放这:GP 在分布内(训练覆盖范围)确实给了诚实的不确定性——名义 95% 区间实际覆盖率 0.953,几乎完美;但一旦越过训练分布的边界(分布外 / OOD),它的可信带反而「假自信」:名义 95% 区间实际只覆盖了 0.070,预测标准差才 0.51,真实误差却有 1.68——差了三倍。这正是一个平稳 RBF 核的根本局限,必须在落地时处理,否则它会用一条窄窄的带子骗你。

GP 后验拟合:分布内带子贴得准,分布外带子假自信地收住


1. GP 到底是什么:把「函数」当成一个随机变量#

线性回归假设「参数是随机的、数据是确定的」;GP 反过来——它假设整个函数 f(x) 是一个高斯过程,即在任意有限个点上采样,得到的函数值都服从联合高斯分布。

一个 GP 由两个东西完全决定:

  • 均值函数 m(x):通常取 0(不损失一般性,把信号留给协方差);
  • 协方差函数(核)k(x, x’):它决定了「两个点靠得近时,函数值多相似」。

最常用的是 RBF 核(平方指数核)

k(x,x)=σ2exp ⁣((xx)222)k(x, x') = \sigma^2 \exp\!\left(-\frac{(x - x')^2}{2\ell^2}\right)

其中 \ell长度尺度(多近算「近」),σ\sigma 是信号方差。这两个加上噪声水平 ν\nu,就是 GP 的超参数——它们不是模型权重,而是「你对世界平滑度的先验信念」。

给定训练数据 (X,y)(X, y) 和测试点 XX_*,GP 的后验是闭式的:

μ=K(X,X)K(X,X)1y\mu_* = K(X_*, X)\,K(X,X)^{-1} y Σ=K(X,X)K(X,X)K(X,X)1K(X,X)\Sigma_* = K(X_*, X_*) - K(X_*, X)\,K(X,X)^{-1}K(X, X_*)

注意:后验方差 Σ\Sigma_* 只取决于核和训练点位置,与 y 的具体取值无关。这就是 GP 的妙处——不确定性是「几何属性」,不用额外训练。


2. 纯 numpy 实现:RBF 核 + Cholesky 求解#

下面是从零的 GP 回归。核心只有三件事:组装核矩阵、Cholesky 分解求逆(数值稳)、算均值与方差。

关键点:fit 里把噪声 ν2\nu^2 加到核矩阵对角线上,然后做 Cholesky。预测时 Σ\Sigma_* 用的是 K(X,X)K(X_*,X_*)(测试点自身核)减去一项——测试点离训练点越远,减得越少,方差越大,可信带自然张开。这就是「没见过的区间该更不自信」在数学上自动成立。


3. 超参数怎么定:最大化边缘似然#

超参数 ,σ,ν\ell, \sigma, \nu 不能拍脑袋。GP 给了个漂亮的自助餐——边缘似然(marginal likelihood),可以直接优化:

logp(yX)=12yK1y12logKn2log2π\log p(y \mid X) = -\tfrac12 y^\top K^{-1} y - \tfrac12 \log|K| - \tfrac{n}{2}\log 2\pi

第一项惩罚「预测残差」,第二项惩罚「模型复杂度(核矩阵行列式)」。两者自动平衡:既想拟合好,又不想把核调得巨复杂过拟合。我们用粗网格 + 坐标下降精修:

def nll(self, X, y):
    n = len(X)
    K = self._K(X) + (self.noise ** 2 + 1e-8) * np.eye(n)
    L = np.linalg.cholesky(K)
    alpha = np.linalg.solve(L.T, np.linalg.solve(L, y))
    return 0.5 * y @ alpha + np.sum(np.log(np.diag(L))) + 0.5 * n * np.log(2 * np.pi)

# (粗网格扫描 ls/sig/noise,再用坐标下降在三个方向上微调,取 nll 最小者)
python

在我们的合成数据(见下)上,边缘似然把长度尺度稳定在 1.0\ell\approx 1.0、信号方差 σ1.5\sigma\approx 1.5 附近——平滑但不至于把噪声当结构。


4. 合成数据:滞后波动率→次日波动率,藏一段概念漂移#

我们造一条「诚实但带坑」的数据,用来检验 GP 的边界:

  • 特征 xx = 个股滞后 5 日已实现波动率(年化 %);
  • 目标 yy = 次日已实现波动率;
  • 真实关系在两区制间突变:当 x<3.5x < 3.5(区制 1,训练用)是温和线性 + 轻微正弦;当 x3.5x \ge 3.5(区制 2)斜率骤变——这就是金融里常见的概念漂移(比如波动率从「常态」跳进「危机」)。
  • 只在区制 1 上训练,测试覆盖两段——这样能干净地暴露分布外行为。
def true_fn(x):
    f1 = 0.62 * x + 0.15 * np.sin(x)
    f2 = (0.62 * 3.5 + 0.15 * np.sin(3.5)) + 1.25 * (x - 3.5)
    return np.where(x < 3.5, f1, f2)

x_all = np.linspace(0.5, 5.0, 600)
y_all = true_fn(x_all) + rng.normal(0, 0.12, len(x_all))
train_mask = x_all < 3.5
gp = GP1D(ls=1.0, sig=1.5, noise=0.12)
gp.fit(x_all[train_mask], y_all[train_mask])
python

5. 校准检验:分布内诚实、分布外假自信#

光看带子「长得对」不够,要测覆盖率。这里有个极易踩的坑——95% 区间必须用观测带 = 函数方差+噪声方差\sqrt{\text{函数方差} + \text{噪声方差}},否则你只覆盖了「潜在函数」而没覆盖「带噪声的观测」。

我们同时画了两种:正确的观测带 vs 只看函数方差的「错误带」。

95% 区间覆盖率:分布内几乎贴住名义 95%,分布外(OOD)塌到 7%

实测(观测带):

区段名义覆盖率实际覆盖率预测 std 均值真实误差均值
分布内(区制1,已训练)95%0.9530.54
分布外 OOD(区制2,漂移段)95%0.0700.511.68

而用「只看函数方差」的错误带,覆盖率更是只有 0.163 / 0.020——连分布内都崩。

这个对照本身就是一条金科玉律:GP 后验方差是「潜在函数」的不确定性,不含观测噪声。如果你的 95% 区间要包住带噪声的 y,必须显式把 ν\nu 加回去。很多论文和库默认给的是函数带,直接用会系统性低估风险。

更刺眼的是 OOD 段:预测 std 才 0.51,真实误差却有 1.68。GP 在没见过的区间,带子是收住的、窄的、一脸「我很懂」——但它完全错了。原因在下一节。


6. 计算代价:O(n³) 是把双刃剑#

GP 每次预测要解一个 n×nn\times n 线性系统,复杂度 O(n³)。我们把 Cholesky 求解单独拎出来计时:

GP 拟合耗时随 n 增长,大样本段实测斜率≈1.93,逼近理论的 n³

大样本段 log-log 斜率≈1.93(理论 3.0,小样本段被常数开销摊平)。这意味着:样本量翻 10 倍,耗时翻约 101.938510^{1.93}\approx 85 倍。几千个样本还能跑,几万、几十万就别想朴素 GP 了——要么上稀疏 GP(Sparse GP / 诱导点)、要么老老实实换树模型。这是 GP 在「大 A 股全市场面板」上落不了地的硬约束。


7. 五类真实陷阱(不拆穿就是自欺)#

陷阱 1:分布外过度自信(最致命)。 如上,平稳 RBF 核在训练边界外会错误地收缩方差。金融里「极端波动率 / 危机区间」恰恰是最该被宽待的区间,GP 却最自信。对策:用 GP 的 σ 当异常检测器——σ 突然变小却预测偏离,就是「模型在瞎猜」的红旗;或换有界核 / 加 OOD 正则

陷阱 2:观测带 vs 函数带(覆盖率踩坑)。 直接拿后验方差画 95% 带,覆盖率会塌到 0.16。记住:包 y 要加噪声项。本文所有图都用的观测带。

陷阱 3:超参数对似然敏感,网格要够密。 训练点太密时核矩阵近奇异,边缘似然会把长度尺度推到极端值骗分。对策:训练集适当子采样 + 加 (noise²+1e-8) 对角项 + 网格扫描。

陷阱 4:O(n³) 撑不住大样本。 几千样本是舒适区,几十万就爆。落地选稀疏 GP、随机特征近似、或只在「小样本高价值」场景用(如单个标的的波动率曲面点、少数宏观状态的过渡概率)。

陷阱 5:平稳核假设「近者相像」——但金融不总是。 RBF 假设相似输入给相似输出。可波动率有跳跃、机制切换:x 只差一点,y 可能天差地别。这时 GP 的均值会「被平滑」掉尖峰。对策:加跳跃项、用非平稳核、或对 y 先做变换(如 log)。


8. 小结:GP 该用在哪#

GP 回归不是「又一个预测器」,它是少数能端到端输出可信度地图的方法。它最适合:

  • 小样本 + 你需要知道「我有多不确信」:期权隐含波动曲面插值、少数宏观状态转移、单标的波动率预测;
  • 主动的不确定性量化:用 σ 当风控开关、当异常检测、当「该不该相信这个预测」的旋钮。

它最不适合:

  • 大样本全市场面板(O(n³) 直接劝退);
  • 分布外区间决策(平稳核会假自信,必须配 OOD 处理);
  • 指望它预测金融里的尖峰跳跃(平滑核天生削峰)。

一句话:GP 给你一张地图,但地图上的「未知区」它画得比已知区还自信——你得自己记得,没标的地方才是最危险的。

代码与数据完全可复现:本文所有图由 gen_gp_finance.py 生成(纯 numpy,无 sklearn/torch 依赖)。分布内覆盖率 0.953、OOD 覆盖率 0.070、OOD 真实误差 1.68 vs 预测 std 0.51、复杂度斜率≈1.93,均直接打印在脚本输出里。95% 带统一用观测带(函数方差 + 噪声方差)。

高斯过程回归在金融预测中的应用:不仅给点预测,还给你一张可信度地图
https://blog.halo26812.eu.org/blog/gaussian-process-finance
Author halo
Published at 2026年7月22日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨