当前位置:首页>python>真正读懂高斯过程:从直觉到完整代码,附Python实现

真正读懂高斯过程:从直觉到完整代码,附Python实现

  • 2026-10-11 05:45:54
真正读懂高斯过程:从直觉到完整代码,附Python实现
在许多机器学习场景中,我们不仅希望模型给出一个预测值,更希望知道预测的可靠性。高斯过程(Gaussian Process, GP)就是这样一种天生带有不确定性刻画的非参数贝叶斯方法。

01 什么是高斯过程?

一句话:高斯过程是函数的分布。

通常我们学概率,随机变量是标量(如身高);高斯过程则把“整条函数”看作随机变量。从高斯过程中采样一次,就得到一条完整的函数曲线。

形式化地,高斯过程由均值函数m(x)和协方差函数(核函数)k(x,x′)定义:

任意有限个输入点对应的函数值都服从联合高斯分布。

通常我们取m(x)=0让数据自己说话。而核函数决定了函数的形状和平滑度。

02 核函数:函数的灵魂

核函数 k(x,x′)衡量两个输入点的相似程度,它决定了函数的特性。最常用的是径向基核(RBF,也叫高斯核):

  • 长度尺度 l:控制函数起伏快慢。l 越大,函数越平滑。

  • 信号方差σ2:控制函数的振幅。

通过选择不同的核,我们可以把对函数的先验信念(平滑、周期性等)编码进模型。

03 高斯过程回归:从先验到后验

先验分布:在没有观测数据时,GP 给出的是“先验函数分布”。比如零均值 + RBF 核,会生成一堆平滑波动的曲线。

后验分布:当我们有了训练数据 (X,y),就能利用高斯分布的条件分布公式,推导出在测试点 X∗上的预测后验:

其中 K是训练点间的核矩阵,K∗是训练与测试点之间的核矩阵,K ∗∗是测试点自身的核矩阵。这组公式直接给出了预测均值和协方差——即每个预测点的置信区间。

04 完整 Python 实现

下面这段代码,将用 GaussianProcessRegressor 拟合一个带噪声的正弦函数,并输出三张图:先验函数采样;后验预测均值与 95% 置信区间;不同长度尺度下的对比。

import numpy as npimport matplotlib.pyplot as pltfrom sklearn.gaussian_process import GaussianProcessRegressorfrom sklearn.gaussian_process.kernels import RBF, WhiteKernelplt.rcParams['font.sans-serif'] = ['SimHei', 'Arial']plt.rcParams['axes.unicode_minus'] = False# -------------------------------# 1. 生成模拟数据# -------------------------------np.random.seed(42)X_train = np.array([1, 3, 5, 6, 7, 8, 9]).reshape(-1, 1)y_train = np.sin(X_train.ravel()) + 0.2 * np.random.randn(len(X_train))X_test = np.linspace(0, 10, 200).reshape(-1, 1)# -------------------------------# 2. 定义核函数 (RBF + 白噪声)# -------------------------------kernel = 1.0 * RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2)) + \         WhiteKernel(noise_level=0.1, noise_level_bounds=(1e-5, 1e1))# -------------------------------# 3. 训练高斯过程回归模型# -------------------------------gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10)gp.fit(X_train, y_train)# -------------------------------# 4. 预测 & 获取不确定性# -------------------------------y_pred, y_std = gp.predict(X_test, return_std=True)# -------------------------------# 5. 绘制先验函数采样(训练前)# -------------------------------fig, axes = plt.subplots(1, 3, figsize=(18, 5))# 子图1:从先验GP采样几条函数曲线gp_prior = GaussianProcessRegressor(kernel=kernel)  # 未拟合X_prior = np.linspace(0, 10, 100).reshape(-1, 1)# 从先验中抽取5条函数y_prior_samples = gp_prior.sample_y(X_prior, n_samples=5, random_state=42)ax = axes[0]ax.plot(X_prior, y_prior_samples, linewidth=1.5)ax.set_title("先验函数采样 (未观测数据)", fontsize=14)ax.set_xlabel("x")ax.set_ylabel("f(x)")ax.grid(True, alpha=0.3)# 子图2:后验预测均值 + 95%置信区间ax = axes[1]ax.fill_between(X_test.ravel(),                y_pred - 1.96 * y_std,                y_pred + 1.96 * y_std,                alpha=0.2, color='coral', label='95% 置信区间')ax.plot(X_test, y_pred, 'darkblue', linewidth=2, label='预测均值')ax.scatter(X_train, y_train, c='red', s=50, zorder=10, label='训练数据')ax.set_title("后验预测与不确定性", fontsize=14)ax.set_xlabel("x")ax.set_ylabel("f(x)")ax.legend()ax.grid(True, alpha=0.3)# 子图3:不同长度尺度下的核函数形状ax = axes[2]x_kernel = np.zeros((1, 1))  # 中心点xp = np.linspace(-3, 3, 300).reshape(-1, 1)for length_scale in [0.3, 0.6, 1.2]:    k = RBF(length_scale=length_scale)    cov = k(x_kernel, xp)    ax.plot(xp, cov[0], label=f'l={length_scale}')ax.set_title("RBF核函数不同长度尺度", fontsize=14)ax.set_xlabel("x - x'")ax.set_ylabel("k(x, x')")ax.legend()ax.grid(True, alpha=0.3)plt.tight_layout()plt.savefig('gaussian_process_demo.png', dpi=200, bbox_inches='tight')plt.show()print(f"优化后的核函数: {gp.kernel_}")

05 图形解读

运行上述代码将得到这样一张组合图(你跑出来就是下面这样):

  1. 左图——先验函数采样在没有看到任何训练数据时,GP 根据核函数生成许多平滑的随机曲线,这就是我们对函数形态的初始假设。

  2. 中图——后验预测与不确定性蓝色实线为预测均值,红色散点为训练数据。珊瑚色区域为 95% 置信区间。在有训练点的区域,不确定性很小;在远离数据的区域,置信区间变宽——这正是 GP 对“知道自己不知道”的诚实表达。

  3. 右图——不同长度尺度的核函数可以直观看到:长度尺度越小,核函数越“瘦”,两个点只有非常靠近才会高度相关(函数波动剧烈);长度尺度越大,核函数越“胖”,远距离点也相关(函数更平滑)。

最新文章

随机文章