
从拿到一组含噪声的观测数据开始很多人第一反应就是用多项式或者查表似的插值去拟合再画一条“看起来很平滑”的曲线。但真正的问题在于拟合结果不是一条线而是一个带有不确定性的推断结果。如果你没有告诉别人“这条曲线在哪些位置可信、哪些位置只是猜测”那么再漂亮的曲线也只是看起来合理而已。这就是我为什么一直强烈推荐用高斯回归拟合在MATLAB里对应的就是fitrgp这类高斯过程回归工具箱来处理这类任务——它天生就能输出预测均值还能给出每个预测点上的置信区间从结果里你能直接看到哪些区域信息充足、哪些区域数据稀疏到基本靠模型脑补。这篇东西就是我从实际项目中整理出来的MATLAB实现经验适合刚接触回归建模、又不想把不确定性丢掉的研究生和工程师参考。1. 从“一条平滑曲线”到“曲线有多可信”为什么需要高斯回归1.1 数据拟合的常见痛点我以前做实验数据处理时遇到过一种非常典型的状况传感器采回来几十个散点形状大概有点规律但噪声不小。第一反应是用三次多项式去拟合多项式系数倒是出来了画出来的曲线也挺顺滑可一旦数据有变动曲线尾端就飞掉了。更尴尬的是别人问我“你这条拟合线在x10附近误差有多大”时我只能哑口无言——因为用最小二乘法做多项式拟合算出来的只是残差的标准差这只是一个全局性的平均误差根本回答不了不同位置的局部不确定性问题。后来我把注意力转到了高斯回归Gaussian Process Regression, 简称GPR上。它最大的特点是不对函数形式做固定假设而是直接在函数空间上玩贝叶斯推断先假设这堆观测值来自一个高斯过程再用数据更新这个过程的概率分布。模型输出不是一个点而是一个后验分布。每个预测点上都能取出均值作为预测值同时取出方差开平方以后乘以对应的分位数就得到置信区间。这就是拟合与置信区间的标准玩法。1.2 高斯回归与其他拟合方式的本质区别拿传统的最小二乘回归对比传统做法是先选定模型表达式比如$y ax^2 bx c$然后去估计参数$a,b,c$。参数有了预测值就确定了方差估计也往往是“全局统一”的。而高斯回归的思路完全换了一个角度——它认为函数本身是按某个概率分布随机生成的。你给了一组训练数据之后它对不同区域的函数取值有不同程度的把握。离观测点近的地方方差小离观测点远的地方方差大甚至收敛到先验方差。这个特性天然就生成了一件事局部置信区间。比如你在x0到5有密集观测在x8到10一片空白高斯回归在x8到10处的预测方差会明显变大置信区间自然就更宽。这种“诚实的预测”比任何单条光滑曲线都有价值特别是在做工程冗余设计或者风险评估时一条飘出来的预测线如果没有置信区间支撑基本等于耍流氓。2. fitrgp实战数据准备、核函数选择与模型训练2.1 基础示例代码与训练流程MATLAB从R2015b开始就提供了稳定的高斯过程回归工具箱。先看一个最简单的示例假设真实函数是$f(x)0.5x\cdot \sin(x)$我们抽样再加上一点噪声然后用GPR来拟合。% 生成合成数据 rng(2023); x (0:0.5:10); y 0.5 * x .* sin(x) 0.2 * randn(size(x)); % 训练高斯过程回归模型 gprMdl fitrgp(x, y, ... KernelFunction, squaredexponential, ... Standardize, true, ... HyperparameterOptimizationOptions, struct(AcquisitionFunctionName, ... expected-improvement-plus, ShowPlots, false, Verbose, 0));fitrgp的调用方式非常直接第一参数是特征第二参数是响应。参数KernelFunction指定核函数Standardize控制是否对输入输出做标准化其实这个选项非常关键后面会讲。如果你没给初始超参数它会自动用边际似然最大的方式去学习。训练完之后预测就一句话xtest linspace(0, 10, 200); [ypred, ysd, yint] predict(gprMdl, xtest);注意这里predict返回三个输出第一个是预测均值第二个是预测标准差第三个是95%置信区间。这三样东西组合在一起就能画出带置信带的拟合曲线。2.2 核函数协方差函数的选择逻辑核函数决定高斯过程假设“两个点有多相似”。最常用的就是平方指数核也叫径向基核、高斯核表达式为$$k(x_i, x_j) \sigma_f^2 \exp\left( -\frac{|x_i - x_j|^2}{2\ell^2} \right)$$它描述了一个非常自然的先验距离越近的样本函数值相关性越高距离远了相关性指数衰减。这里的ell长度尺度和sigma_f信号方差就是超参数。ell大说明模型认为函数变化缓慢、整体平滑ell小则认为函数变化剧烈细节丰富。MATLAB里fitrgp支持的内置核包括核名称KernelFunction值适用场景平方指数核squaredexponential平滑连续信号马特恩核matern32或matern52实际工程数据鲁棒性更好指数核exponential不连续或尖峰信号有理二次核rationalquadratic多尺度变化的数据我实际用的最多的是matern52因为它对平滑性的假设没有平方指数核那么严格——平方指数核会让拟合曲线“过度平滑”遇到真实数据中的突变会显得乏力。大家做实验时也别死守默认拿一个真实数据集跑一遍对比一下均方根误差和各点的置信区间宽度往往会发现马特恩核的置信带更合理。3. 置信区间到底是怎么算出来的predict的“三输出”用法3.1 预测均值和方差后验分布公式高斯回归的后验分布是解析可算的。设训练输入为$X$输出为$y$新点为$x_$那么预测均值$\mu_$和方差$\sigma_*^2$为$$\mu_* K_*^\top (K \sigma_n^2 I)^{-1} y$$$$\sigma_^2 K_{**} - K_^\top (K \sigma_n^2 I)^{-1} K_*$$其中$K$是训练点之间的协方差矩阵$K_*$是测试点与训练点之间的协方差向量$K_{**}$是测试点自身的先验方差$\sigma_n^2$是噪声方差。MATLAB的predict内部就是执行这两个公式它返回的标准差ysd直接就是$\sqrt{\sigma_*^2}$。95%置信区间则用正态分布分位数ypred ± 1.96 * ysd。predict的第三个输出yint已经帮你算好了这个区间默认置信水平是95%。实际上它返回的是两列第一列是下界第二列是上界。3.2 MATLAB代码计算并绘制置信带用上一节的模型画图figure; hold on; % 置信带 fill([xtest; flipud(xtest)], [yint(:,1); flipud(yint(:,2))], ... [0.8 0.9 1.0], EdgeColor, none, FaceAlpha, 0.6); % 预测均值 plot(xtest, ypred, b-, LineWidth, 1.8); % 观测数据 plot(x, y, ko, MarkerSize, 5, MarkerFaceColor, r); xlabel(x); ylabel(y); legend({95%置信区间,预测均值,观测数据}, Location, best);这里用fill函数画置信带flipud是为了保证上下界端点能围成一个多边形。FaceAlpha控制透明度0.6就挺好看。你可能注意到我在置信带里放进了一组真实函数曲线没问题——我通常还会叠加一条真实无噪声曲线做对比用来快速判断置信带是否覆盖了真值。如果一大部分真值都跑到置信带外面说明模型有系统偏差核函数或先验假设大概率有问题。4. 实操避坑核超参数、数据归一化与区间过窄问题4.1 超参数对置信区间的影响GPR里的超参数不是摆设它们直接决定置信区间宽度。长度尺度ell如果被优化到极大模型会认为函数在全定义域内几乎不变导致预测方差整体偏大置信区间宽到没有参考价值如果ell被优化到极小模型会把每个点都当成独立事件方差骤降置信区间窄成一条线看起来“很准”但实际上是因为模型过拟合了噪声不确定性被严重低估。我在一次仿真数据任务里就踩过这个坑训练数据噪声较小但模型在远端点给了特别窄的区间一开始还以为自己做得特别牛后来重新做交叉验证才发现把训练集的后半段遮住再看预测误差真实偏差大概是置信区间宽度的3倍。这就是典型的呗“过度自信”害了。解决方案之一是手动设定超参数搜索范围。fitrgp支持通过KernelParameters这个字段指定核函数的初始值和上下界。例如gprMdl fitrgp(x, y, ... KernelFunction, matern52, ... KernelParameters, [1, 1, 1], ... OptimizeHyperparameters, auto);不过更推荐的做法是直接使用贝叶斯优化超参数OptimizeHyperparameters设置为auto但要注意优化过程使用的目标函数是边际似然它并不完全等价于“区间宽度要合理”。边际似然会自动权衡模型复杂度和拟合度正常情况下给出的区间比较合理但样本量太少时依然会不稳定。所以我的习惯是先做一次超参数优化然后人为调整长度尺度的上下界再训练一次看置信带宽度是否随数据密度产生明显变化。如果数据稀疏区间的宽度和数据密集区间的宽度差异不明显那就是先验长度尺度太宽松需要收窄。4.2 实战中的常见错误及修正先说数据标准化。很多人刚用fitrgp会把Standardize设为false如果数据量级差得大比如x范围从0到1y范围从1000到2000核函数的距离计算会被y的量级主导导致拟合失败。Standardizetrue会自动对输入和输出做z-score标准化效果好很多。但要注意标准化后的输出预测都会被映射回原空间置信区间也随之缩放所以画图时所见即所得不会失真。再说异常值问题。GPR对异常值非常敏感因为它的似然函数默认是高斯分布一个离群点会在局部把整个后验分布拉扯过去让附近的置信区间变窄。处理办法除了常规的预处理之外还可以换用鲁棒性更强的似然函数比如在fitrgp中将噪声模型设为Huber或Laplace我常用的设置是gprMdl fitrgp(x, y, KernelFunction, matern52, Standardize, true, ... OptimizeHyperparameters, auto, HyperparameterOptimizationOptions, ... struct(AcquisitionFunctionName, expected-improvement-plus));虽然fitrgp直接在函数内切换鲁棒噪声模型的语法略繁琐但至少可以降低个别异常点的影响。实际上我只在数据质量很差时才用鲁棒似然正常时尽量先手工清洗数据。最后一个高频错误是用错了输入数据维度如果你的x是多维特征置信区间绘图就不能简单地用fill来画了因为预测点是高维空间你只能画某个固定截面的置信带或者用三维曲面图。我做过一次两个输入变量、一个输出标量的GPR把predict返回的标准差在第二维固定值上切了一条线用plot3画成三维置信带效果也还行但那属于专门的可视化课题了。5. 高斯回归 vs 传统高斯函数拟合如何选型5.1 两种“高斯”的本质区别标题里“高斯回归拟合”这个词在MATLAB相关的社区里容易产生歧义。很多人找的是高斯函数拟合也就是拟合一条形如$ya\exp(-(x-b)^2/c^2)$的钟形曲线用fit工具箱或者lsqcurvefit都能做。那个“高斯”指的是函数形式不是概率过程。而本文写的是高斯过程回归它的“高斯”指整个函数空间上的概率分布假设。这俩类别不同应用场景也完全不同。举个例子你想拟合色谱峰或者光谱峰峰的形态很接近高斯钟形那直接用fit(x, y, gauss1)效率更高参数少、解释性强。但如果你只有一堆乱糟糟的实验散点根本没有明确的函数表达式但又想从数据中学习一个平滑的非线性映射同时还要估计局部不确定性那fitrgp才是正解。我给一个选型判断表决策维度高斯函数拟合高斯过程回归核心假设数据来自已知参数的钟形曲线数据来自高斯过程典型场景峰拟合、吸收光谱、雷达回波地形建模、工业传感器校准、仿真器替代置信区间基于参数协方差矩阵间接计算直接由后验分布得到参数可解释性很强中心、幅度、宽度较弱核函数超参数偏抽象计算成本低中等偏高矩阵求逆注意高斯函数拟合同样可以算置信区间——用fit返回的模型对象用confint算参数置信区间再用参数分布去推预测区间但那个过程比较绕而且预测区间往往只考虑了参数不确定性忽略了模型形式错误。GPR则把两种不确定性都包含进去了。5.2 选型决策建议我在实际项目里的规律是这样的如果数据来自一个明确物理过程比如已知是色谱峰、X射线衍射峰、或某种谐振谱线那就老老实实用高斯函数拟合参数有物理含义用户也容易理解如果数据是黑盒系统仿真输出或者你不知道用什么解析式来描述但关心预测可靠性那就选高斯过程回归。尤其是当项目要求“给出预测误差范围”时GPR的置信区间几乎是零成本的副产品根本不需要额外写蒙特卡洛抽样代码。还有一个小技巧如果你拿不稳应该用哪种可以两边都跑一遍。高斯函数拟合只有几个参数跑起来很快GPR稍微慢一点但也不至于等太久。对比两者的测试集均方根误差再看各自预测区间对真实值的覆盖率——覆盖率如果低于90%另一个模型哪怕是预测值差一点也可能更值得信任。6. 写在后面的实践心得我看很多新手在使用fitrgp时最容易忽略的就是先检查核函数的长度尺度范围。因为MATLAB默认会通过优化自动寻找超参数但在小样本条件下优化结果可能陷在局部最优里最终长度尺度很极端。我自己的做法是先不急着用自带的预测区间而是把训练数据分成三份做三次留一交叉验证把每次验证集的预测误差累积起来和模型给的置信区间宽度做对比。如果误差标准差明显大于预测标准差说明模型低估了不确定性这时宁可手动调大噪声方差超参数也不要认那个看似精确的窄区间。另外GPR虽然数学上优雅但它有一个硬伤——训练样本超过两三千时协方差矩阵求逆的计算量和内存占用都会急剧增加。超过这个量级我一般会用稀疏近似或者在MATLAB里改用fitrgp提供的PredictMethod, exact之外的方法比如SRsubset of regressors或SDfully independent conditional。代价是置信区间会略微失真但对大样本来说这是个合理妥协。当你需要快速迭代模型时还可以先用一个子集训练预测时再用全量数据做局部预测或者直接按照下面这个思路调整% 对大数据量用内存更友好的预测方式 gprMdl fitrgp(x, y, ... KernelFunction, squaredexponential, ... Standardize, true, ... PredictMethod, sr); % 或 sd关于置信区间的解读我最后再多说一句区间宽度不是越窄越好。窄区间意味着对数据稀疏区域还保持高度自信通常是不合理的。一份诚实的回归报告应该让客户看到你的模型在数据稀疏区域“坦荡地宽”起来。这是GPR最美丽的地方——它敢于承认自己不知道什么。而敢于承认不确定性恰恰是许多传统拟合方法做不到的事情。如果你手头有项目需要反复使用这种带置信带的拟合建议把本章的代码封装成一个函数输入训练数据和核类型输出模型和置信带绘图。下次再遇到类似的实验数据一行调用就直接出图。这样既节省时间也让团队里的所有人都养成“预测必带不确定性”的好习惯。