ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

高斯过程回归(GPR)实现时间序列区间预测的完整指南

高斯过程回归(GPR)实现时间序列区间预测的完整指南 1. 项目概述1.1 核心需求解析基于高斯过程回归的时间序列区间预测这个题目第一眼看上去是个典型的学术型项目但实际拆开来说它解决的是一个很现实的问题——你手头有一堆按时间排列的数据但你不仅想知道未来那个点的值大概是多少还想知道这个预测到底准不准、波动范围有多大。这个准不准、波动范围有多大就是区间预测干的事。很多做预测的朋友一开始接触的都是点预测比如用LSTM预测明天的销量是100件用ARIMA预测下个月的流量是8000。但实际业务里决策者需要的往往不是一个数而是一个范围——比如库存备货你告诉他明天卖100件他敢按100件备吗不敢。你要告诉他明天大概率在85到115件之间他才能根据风险偏好做决策。这就是区间预测在实际业务里真正的价值。高斯过程回归Gaussian Process Regression简称GPR在区间预测这个领域有个天然的优势它是一个概率模型输出天生就是分布。38.2±2.1这种形式而不是LSTM那种直接吐出一个数值。这意味着你不需要像用深度学习那样再去跑一堆复杂的区间构造算法比如分位数回归、蒙特卡洛dropoutGPR本身就把不确定性给你算好了。适合看这篇文章的人我大致分三类做工业预测的工程师比如设备剩余寿命预测、刀具磨损预测这类场景往往样本量不大但好在数据质量高、信噪比高GPR非常好用。做能源负荷预测的同学电力负荷、风功率预测这类领域区间预测几乎是硬性要求而且数据通常非线性强、噪声大GPR配合理核函数能处理得不错。学术入门选手刚接触GPR想知道这玩意到底怎么用、怎么调、坑在哪里。说到这儿我得先泼一盆冷水GPR最被人诟病的就是计算复杂度训练是O(n³)预测是O(n²)。也就是说样本量超过一万条普通机器基本就要等哭了。所以这个模型更适合小样本、中高维、非线性强的数据场景。如果数据量大通常的套路是稀疏近似比如SGPR、或者分块处理。这个细节后面在实操部分我再展开。1.2 为什么是高斯过程回归先把高斯过程这个东西讲透。很多初学者听到过程两个字就虚其实可以换个角度理解高斯过程是对函数的分布的一种描述。你有一个函数f(x)但你不确定它长什么样高斯过程就是一堆可能函数的分布你通过观测数据不断修正这个分布。这个说法还是太抽象打个比方。你想猜一个人的年龄只看他的照片你可能猜28岁但你不确定你会说大概28岁误差可能在正负4岁。这里的28岁就是均值函数正负4岁就是方差。高斯过程干的事情完全类似对于每一个输入点x它都给出一个预测值均值和一个不确定性范围方差而且相邻输入点的预测值之间是有相关性的——这是高斯过程比一堆独立分布强得多的地方因为它用协方差函数也就是核函数刻画了相近的输入应该有相近的输出这个先验知识。为什么在时间序列里特别好用因为时间序列有个天然的属性相邻时刻的值通常是相关的。今天的温度和明天的温度不会差太多这个小时的负荷和下一个小时的负荷变化是连续的。GPR通过核函数把这种时间连续性隐式地建模进去不需要像RNN那样显式地维护隐藏状态。跟深度学习模型比GPR还有一个很迷人的特点——它是贝叶斯风格的非参数模型。非参数的意思是模型复杂度可以自动随着数据量增长而增长而不是固定死几十层网络。这意味着在小样本场景下它的表现往往优于那些动辄需要几万条数据才能训练的深度模型。我遇到过很多朋友问我这个仿真数据总共就200条LSTM根本训不动怎么办这种场景GPR就是非常合适的选择因为贝叶斯方法天然不容易过拟合而且能给出漂亮的不确定性区间。这也是为什么会有人把GPR称作小样本预测神器。2. GPR的核心原理与关键参数2.1 高斯过程回归的三层理解要真正用好GPR不是简单调个库就完事你得从三个层次理解它。第一层先验。在没看到任何数据之前我们假设函数f(x)服从一个高斯过程先验由均值函数m(x)和核函数k(x, x)完全决定。默认情况下均值函数取0这通常没问题因为GPR的强大之处在于它能够通过数据修正先验即使均值函数为0也能拟合出非零的复杂函数。核函数则定义了函数的平滑程度、周期性和各向异性。第二层后验。给出一堆训练数据后我们利用贝叶斯公式将先验和观测数据结合起来得到后验分布。对于一个新的测试点x*后验分布是高斯分布其均值就是点预测值方差就是不确定性区间。这个过程涉及对核矩阵求逆也就是O(n³)复杂度的来源。第三层边缘似然与超参数优化。这是绝大多数人忽略但极度关键的一层。核函数里的参数比如长度尺度lengthscale、信号方差signal variance并不是拍脑袋定的是通过最大化对数边缘似然来优化的。你可以把边缘似然理解为在所有可能的函数中产生当前观测数据的总概率。通过梯度上升法模型会自动调整lengthscale等参数以最合理地解释训练数据。这里有个矛盾点最大化边缘似然并不总是等于得到最好的预测效果有时会过拟合到噪声上。所以在实际项目中我一般会做交叉验证来辅助判断核函数的超参数是否合理而不是完全信任优化结果。2.2 核函数的选择对区间质量的影响核函数是GPR的灵魂。我见过太多人用GPR就默认拿一个RBF径向基函数核跑到底其实这往往不是最优解。核函数的选择直接决定了协方差结构也就是直接决定了区间预测的形态。下表是几种常用核函数在时间序列场景下的表现核函数适用场景区间特点注意事项RBF平方指数核平滑、连续变化的数据区间光滑但容易过于自信区间偏窄对突变数据适应差Matérnν3/2或5/2噪声较大、非光滑数据区间更合理不确定度略大比RBF更稳健推荐优先尝试Periodicexp有明显周期波动的数据日负荷、周流量区间呈现周期性可靠性高需要知道周期的先验长度RBF RBF加法核多个时间尺度叠加的序列能分解不同尺度不确定性参数多调参成本高Rational Quadratic多尺度平滑变化的数据区间宽度动态调整适应性强适合变化幅度不一致的时间序列以风功率预测为例这个数据有很强的非线性、非平稳特征如果只用RBF核你经常能看到预测区间窄得离谱——跟数据本身的波动性完全不匹配。这时候用Matérn核或者Rational Quadratic核情况会好很多因为它们的尾部更重在数据变化剧烈的区间给出的不确定性更大。实操建议不要单核走天下多试试组合核。比如长期趋势用RBF、短期波动用Matérn、周期性用Periodic做加法组合效果往往会好很多。但注意每加一个核超参数数量和计算复杂度都会增加也别过度设计。2.3 噪声模型的设定同方差还是异方差GPR的一个隐含假设是噪声服从高斯分布且通常是同方差的——也就是说不管数据在什么位置噪声水平都一样。但实际时间序列往往不满足这一点。比如电力负荷数据白天高峰时段波动大夜间低谷时段波动小风功率数据大风时段波动剧烈小风时段相对平稳。这种噪声水平不一致的情况叫异方差。异方差情况下如果强行用普通GPR得到的不确定性区间很可能在波动大的区域严重低估在波动小的区域高估。解决思路有两个方向数据变换对原始序列做Box-Cox变换、对数变换或方差稳定化变换让变换后的数据噪声更接近同方差。这是最简单、最实用的做法我强烈建议先试这个。异方差GPR模型用两个GP一个建模均值一个建模噪声的对数方差。这个方法效果好但实现复杂且训练更容易陷入局部最优。拿我实际做过的一个风电功率预测项目来说原始功率数据的波动范围从0到额定功率0附近噪声很小中间区域噪声巨大。直接把原始数据丢进GPR得到的90%置信区间简直不忍直视。后来我对功率做了个对数变换先加一个小常数防止对数取到0预测完再反变换回去区间质量好了非常多。这个技巧在论文里不太起眼但实战中救命。3. 区间预测的构造方法与评价指标3.1 从后验方差到置信区间GPR给测试点的输出是高斯分布有均值和方差构造区间看似简单但实际上有很多细节需要注意。对于一个测试点x*GPR给出的后验是 [ y_* | X, y, x_* \sim \mathcal{N}(\mu_, \sigma_^2) ] 如果你要90%的预测区间那就是(\mu_* \pm 1.645 \times \sigma_)。95%就用1.9680%就用1.28。这个太简单了但坑在于**这个(\sigma_^2)是模型认为的不确定性它不一定等于真实的不确定性**。为什么因为(\sigma_*^2)里面包含了噪声方差(\sigma_n^2)而噪声方差的估计本身是有偏的。此外如果模型超参数拟合不当方差会系统性地偏大或偏小。更隐蔽的问题是GPR假设函数本身是平滑的如果你的数据实际上存在突变那么模型在突变点附近会给出非常窄的区间——因为核函数觉得它不知道这里会有突变但真实数据恰恰就在这里发生了跳跃。这是GPR的先天局限做区间预测时一定要注意。我建议在建模前做两件事残差分析训练完模型后在训练集上算残差看残差是否均值为0、方差是否稳定。如果残差方差明显异方差说明模型设定有问题需要回到噪声模型的选择上调整。校准曲线把预测区间按置信水平划分比如10%、20%...90%统计真实值落在区间内的比例画一条覆盖率-置信水平曲线。如果覆盖率普遍低于置信水平说明区间过于乐观就是太窄了如果覆盖率普遍高于置信水平说明区间过于保守。3.2 区间预测的三大类评价指标区间预测的评价不能只盯着点预测的RMSE要专门看区间质量。学术界和工业界常用的指标有三类我分别说下它们的脾气第一类覆盖类指标。最核心的是预测区间覆盖概率PICP就是真实值落在预测区间内的比例。比如你构建90%的预测区间那PICP应该接近90%。如果PICP只有60%说明区间太窄模型过于自信如果PICP高达99%说明区间太宽虽然覆盖率高但没什么实用价值。PICP的问题是它只看覆盖率不惩罚区间过宽的代价。第二类宽度类指标。最常用的是预测区间平均宽度PINAW或者归一化宽度PINAW。区间越窄越好但不能以牺牲覆盖率为代价。所以实际评价时要把PICP和PINAW放在一起看有个综合指标叫区间得分Interval Score它同时惩罚覆盖率不足和区间过宽两种错误公式是 [ Score \frac{1}{N}\sum_{i1}^N [(U_i - L_i) \frac{2}{\alpha}(L_i - y_i) \mathbb{1}{y_i L_i} \frac{2}{\alpha}(y_i - U_i) \mathbb{1}{y_i U_i}] ] 这个公式看着吓人其实逻辑很简单你每预测一个区间就会付出等于区间宽度的代价如果真实值落在区间外面还要额外付出更大的代价。置信水平(1-α)越高落在外面的惩罚倍数越大。区间得分越低说明质量越好。第三类综合类指标。比如连续排名概率得分CRPS它把点预测和区间预测统一在一个框架里评价是概率预测的标准指标之一。CRPS同时衡量预测分布和真实观测的差距很适合全面评价GPR的结果。对于一个实际项目我建议至少同时报告PICP和区间得分只看覆盖率容易被区间过宽骗过去只看宽度又容易忽视覆盖率。指标缩写评价侧重理想情况区间覆盖率PICP真实值落在区间内的比例无限接近目标置信水平区间平均宽度PINAW区间的实用价值越小越好在保证覆盖率前提下区间得分Interval Score覆盖率和宽度的综合惩罚越小越好连续排名概率得分CRPS整个预测分布的质量越小越好3.3 与LSTM区间预测的对比视角说实话现在做时间序列预测绕不开LSTM。很多人会问GPR和LSTM到底选哪个我的观点是这样的这两个模型根本不是竞争关系而是不同场景下的两种工具。LSTM适合大数据量的场景比如你有十万条数据、特征维度很高、还有外部变量这种量级的数据GPR基本跑不动矩阵求逆O(n³)LSTM反而能大显身手。但LSTM要做区间预测很费劲常见方案有分位数回归在LSTM的输出层换成多个分位损失函数比如同时预测5%、50%、95%三个分位数。这个方案实现简单但分位数之间没有一致性约束可能出现95%分位数比5%分位数还低的尴尬情况。蒙特卡洛Dropout在预测时保留Dropout随机性多次前向传播得到多个预测值用它们的方差近似不确定性。这个方案快但方差估计有偏且需要对模型重新调参。贝叶斯LSTM对权重施加先验分布用变分推断近似后验。这个理论最漂亮但训练极其不稳定我实际试下来感觉性价比不高。GPR走的是另一条路它天生就是概率模型一次训练直接给出均值方差这种开箱即用的区间预测能力是LSTM不具备的。但GPR也有天生的短板——样本量大的时候计算代价受不了、自动特征提取能力弱、非线性建模能力受限于核函数的选择。以下是两个模型的优缺点对照维度GPRLSTM样本量要求小样本几百~几千条最佳大样本几万条以上效果好区间预测天然输出无需额外构造需要专门设计分位数/dropout非线性建模依赖核函数能力强自动特征提取计算代价训练O(n³)无法上大数据训练可扩展GPU友好可解释性超参数有意义可解释性强黑箱难以理解内部机制处理高维输入较弱核函数设计困难强适合多变量输入所以我的经验法则是数据少于5000条先用GPR试一把数据超过50000条选深度学习路线更靠谱数据介于两者之间可以都试试对比一下点预测和区间质量再做决定。4. 实操用Python完整实现GPR区间预测4.1 环境准备与数据说明我假设你用的是Python主要有两个库scikit-learn自带GaussianProcessRegressor或者GPyGPy是一个专门的高斯过程库。scikit-learn更主流API更简单GPy功能更全但文档相对晦涩。这篇文章我用scikit-learn为例因为它的接口干净、自带优化器、且足够应对大多数场景。环境依赖如下pip install numpy pandas scikit-learn matplotlib我用一个仿真数据集来演示。构造一个带趋势、带周期、带噪声的非平稳时间序列import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.gaussian_process import GaussianProcessRegressor from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C, Matern, WhiteKernel np.random.seed(42) # 构造仿真数据趋势项 周期项 异方差噪声 n 300 t np.linspace(0, 10, n).reshape(-1, 1) trend 0.3 * t / 10 season 0.8 * np.sin(2 * np.pi * t / 2.0) noise np.random.normal(0, 0.05 * (1 0.5 * t / 10), size(n, 1)) y (trend season noise).ravel()这个数据集有300个点含线性趋势、周期为2的正弦波、以及随时间增大的异方差噪声。很适合演示GPR在区间预测上的表现。注意这里我直接用了连续时间作为输入特征。实际时间序列中你可能需要额外的特征工程比如滞后特征、日历特征等。但对于GPR一个重要的经验是特征维度不宜过高。GPR的核函数在高维空间里很难有效捕捉相似性特征的引入要克制两三个充分描述数据内在规律的特征远好过二十个噪声特征。这和深度学习的特征越多越好风格不同一开始容易踩坑。4.2 训练GPR模型的完整步骤首先划分训练集和测试集。一般时间序列预测按时间顺序划分不用随机划分避免数据泄露train_x, test_x t[:240], t[240:] train_y, test_y y[:240], y[240:]关键在于核函数的设计。前面提到单RBF核往往不够这里我用一个组合核——RBF捕捉整体平滑趋势加上一个Matern核捕捉局部细微变化再用WhiteKernel告诉我们观测中存在噪声kernel 1.0 * RBF(length_scale1.0, length_scale_bounds(0.1, 100.0)) \ 1.0 * Matern(length_scale1.0, length_scale_bounds(0.1, 100.0), nu1.5) \ WhiteKernel(noise_level0.1, noise_level_bounds(1e-5, 10.0))这里的含义是RBF负责整体平滑趋势、Matern负责细节变化、WhiteKernel负责观测噪声。三个核相加相当于把三种作用线性叠加是组合核的经典写法。长度尺度的bounds范围设成0.1到100给它足够的搜索空间但不过度扩大搜索范围以免优化不稳定。然后实例化模型并训练gp GaussianProcessRegressor( kernelkernel, normalize_yTrue, # 对目标值做标准化防止数值不稳 n_restarts_optimizer5, # 多起点优化避免局部最优 random_state42, alpha1e-8 # 额外的小数数值稳定性项 ) gp.fit(train_x, train_y)这里有两个关键参数值得展开normalize_yTrue。这个参数会在建模前对y做标准化减去均值除以标准差建模后再把预测值变换回原始尺度。如果不做标准化当y的数值量级很大时核矩阵的条件数会非常糟糕数值不稳定容易导致模型崩溃或预测爆炸。我建议这个参数一律设成True几乎没有任何坏处。n_restarts_optimizer5。超参数优化的目标函数对数边缘似然是非凸的只有一个起始点很容易陷入局部最优。5到10个随机起点是实践中最常用的区间。起点太多会拖慢训练速度太少又容易错过优化解。如果数据量小、训练快我一般设成10如果样本大、训练慢可以适当降到3。训练完成后查看模型学到的超参数print(gp.kernel_)训练完毕可以直接输出预测均值和标准差mean_pred, std_pred gp.predict(test_x, return_stdTrue) # 构造90%置信区间 lower mean_pred - 1.645 * std_pred upper mean_pred 1.645 * std_pred注意这里用的90%区间对应的是约1.645倍标准差。如果你要用不同置信水平查标准正态分布分位数即可80%对应1.2895%对应1.9699%对应2.576。如果你想更严谨还可以用 t 分布的临界值尤其在小样本情况下t分布的分位数比正态分布分位数更靠谱。4.3 区间质量的可视化与评估数据有了区间有了必须直观的画出来看一下情况plt.figure(figsize(12, 6)) plt.plot(train_x, train_y, b., alpha0.4, label训练集) plt.plot(test_x, test_y, r., alpha0.8, label测试集真实值) plt.plot(test_x, mean_pred, g-, label预测均值) plt.fill_between(test_x.ravel(), lower, upper, colorgreen, alpha0.2, label90%区间) plt.legend() plt.title(GPR 时间序列区间预测结果) plt.xlabel(时间) plt.ylabel(目标值) plt.show()然后计算区间评价指标。PICP和区间宽度的代码实现也不复杂# PICP真实值落在区间内的比例 coverage np.mean((test_y lower) (test_y upper)) # 平均区间宽度原始目标值尺度 avg_width np.mean(upper - lower) print(f90%置信区间覆盖率 (PICP): {coverage:.4f}) print(f平均区间宽度: {avg_width:.4f})如果PICP低于0.85说明区间过窄模型过于自信。原因可能是核函数选择不当比如忽略了数据中的突变成分、噪声估计偏低、或者超参数优化陷入局部最优。如果PICP高于0.95说明区间偏保守可以通过调整置信水平或改变核函数的噪声项让区间收窄一些。我实测下来比较棘手的现象是训练集残差很小、拟合非常好但预测区间的覆盖率却低得离谱。这种情况通常是数据在测试集时段里发生了分布漂移——训练时没见过的模式在测试时出现了。比如设备退化数据训练时设备正常测试时设备开始劣化模型没见过这种趋势区间自然跟不上。这类问题没有灵丹妙药只能在建模时保留一些模型不确定性的空间比如给核函数增加一个较大的WhiteKernel噪声下限或者用集成多核的方式对冲单一模型的过度自信。4.4 交叉验证评价与比较GPR的区间预测质量在实际项目中如果只在一个训练/测试划分上评价结果可能不够让人放心。我强烈建议在样本不太多、训练不慢的前提下做时间序列交叉验证来评价GPR区间预测的稳定性。所谓时间序列交叉验证就是Rosenblatt和Roll等人用的那种滚动原点验证策略每次把训练集末端向后推一步重新训练、重新预测逐步前进。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) errors [] for fold, (train_index, val_index) in enumerate(tscv.split(t)): X_train, X_val t[train_index], t[val_index] y_train, y_val y[train_index], y[val_index] gp.fit(X_train, y_train) pred_mean, pred_std gp.predict(X_val, return_stdTrue) # 计算区间得分 alpha 0.1 lower pred_mean - 1.645 * pred_std upper pred_mean 1.645 * pred_std width_cost np.mean(upper - lower) violation_cost np.mean(np.where((y_val lower) | (y_val upper), (lower - y_val) / alpha if y_val lower else (y_val - upper) / alpha, 0)) errors.append(width_cost violation_cost) print(fFold {fold 1}: PICP {np.mean((y_val lower) (y_val upper)):.4f}, fInterval Score {errors[-1]:.4f}) print(f平均 Interval Score: {np.mean(errors):.4f})滚动验证的价值在于它能告诉你模型在整个时间轴上的表现是否稳定而不是只在某一段测试集上碰运气。实际项目里模型可能在某个时段特别准、区间特别窄但换一个时段就崩了。只做一次划分很容易给你虚假的安全感。4.5 超参数优化与核函数搜索实践GPR的调参和神经网络不太一样它不是调学习率、调层数而是调核函数的结构和核函数内部的超参数。这两者中结构的影响远大于参数。我在实际项目里总结了一套比较实用的步骤第一步先快速用默认核训练一个baseline得到RMSE和区间覆盖率。主要目的是看数据的基本特性是平滑的还是抖动的有没有明显周期性第二步根据baseline的表现决定核函数的方向。如果baseline区间过窄尝试加WhiteKernel的噪声水平上限或者换成Matern核如果baseline拟合不充分尝试RBF核和Matern核的组合也可以加一个Rational Quadratic核。第三步用网格或随机搜索来优化核函数的超参数bounds。scikit-learn的GaussianProcessRegressor对核函数的bounds是可以在初始化时指定的但如果你想做系统搜索可以这样from sklearn.model_selection import ParameterGrid param_grid { kernel__k1__k2__length_scale: [0.3, 1.0, 3.0], kernel__k2__k2__length_scale: [0.5, 1.5, 5.0], kernel__k3__noise_level: [0.01, 0.1, 1.0] }这种方法是把核函数组合结构固定住、只对超参数做网格搜索虽然不保证全局最优但胜在简单稳定能给你提供一个合理的参考范围。这里我必须提醒一个常被忽视的坑GPR的超参数优化不是万能的。有时模型自己优化出来的超参数会让预测区间非常窄——原因是边缘似然最大化的目标更倾向于完美拟合训练数据但它没有直接优化预测区间的覆盖质量。所以当你在交叉验证中发现区间覆盖率太低不要迷信模型给出的超参数试试把核函数的length_scale_bounds范围放宽一点或者手动把WhiteKernel的noise_level_bounds下限提到0.05以上给模型一个必须考虑噪声的强制约束。5. 常见问题与排查技巧实录5.1 训练时间过长怎么办GPR的O(n³)计算复杂度是硬伤。如果你的训练数据到了几千甚至上万条等待时间会变得不可接受。我的经验方案有三个第一个方案是减少训练样本量。如果时间序列本身是高频采集的比如每秒钟采一个点你完全可以用重采样降低频率比如每分钟采一个点。GPR的优势在于小样本下就能学到非常好的模式牺牲一点时间分辨率换取训练速度是划算的。如果数据是全日负荷数据一天288个点你甚至可以只取每天的96个点或48个点先验证可行性。第二个方案是稀疏高斯过程。scikit-learn的basic版本不含稀疏近似但可以用GPy中的SVGP、或者GPFlow中的SVGP核心思想是用一组诱导点来代替全部训练数据做近似推断把复杂度从O(n³)降到O(m²n)m是诱导点数量。实测下来诱导点选到300~500个时精度和全量GPR已经很接近但速度快了一个量级不止。第三个方案是分块预测。把长时间序列分段每段单独训练GPR边界处做重叠拼接。这个方法简单粗暴也不存在理论上的复杂性适合对预测精度要求不算极致的工业场景。5.2 区间预测为什么总是过窄这是GPR区间预测里最能拉开经验差距的地方。区间过窄的本质问题是模型对噪声的估计偏小或者对函数本身的不确定性估计偏小。排查思路按优先级排序检查核函数是否包含WhiteKernel。如果没有赶紧加上。WhiteKernel的noise_level_bounds要宽容一点不要设成固定的0.01这种最好让模型自己学。观察训练集上的残差。如果残差的标准差明显大于模型输出的std在训练集上预测说明模型把一部分噪声当成了信号导致噪声被低估。检查是否出现预测漂移——测试集的分布和训练集差异过大。这种情况加再多的噪声项也难以挽回只能考虑更换模型或者增加对分布变化的建模比如加一个趋势项。5.3 预测区间出现负值怎么办如果你的目标变量是物理上的正数比如负荷、功率、销量那预测区间的下限出现负数会显得很怪。虽然这在统计上不一定是错的因为区间是概率意义上的但从业务接受度上来说就很难看了。处理方法有两种一种是在建模前对目标变量做对数变换预测完再反变换。另一种是在预测后对区间做截断小于0的下限直接设成0。后者虽然不符合严格概率意义但业务端更友好。我个人更推荐先试对数变换因为对数变换还能改善模型的异方差问题一石二鸟。5.4 超参数优化不收敛或不稳定怎么办超参数优化不稳定通常有三个原因数据量太少导致边缘似然函数太平坦核函数结构太复杂导致参数多、相互作用强或者初始值设置不当。实操中比较有效的做法是固定n_restarts_optimizer在5~10之间不要太多也不要太少。给每个超参数设置合理的bounds避免过于宽泛的搜索空间。比如length_scale的bounds0.01, 10000这种没有意义除非你真的完全不知道数据的时间尺度。如果优化不收敛尝试先只优化一个超参数比如固定length_scale只优化noise_level然后再放开更多超参数。一步步来比一次性优化所有参数更稳健。5.5 和LSTM对比测试时需要注意的公平性问题如果你做的是比较实验有几个坑特别容易踩第一划分方式要一致。GPR对数据量的要求低LSTM对数据要求高如果大家共用一个测试集但训练集长度不同比较结果就不公平。我的做法是先确定一个最小的训练集长度比如LSTM需要至少2000条数据然后保证GPR也在同等长度的训练数据上训练否则你只是验证了样本充足时深度学习更好或者样本不足时GPR更好这两个已知结论没有什么信息量。第二区间构造方法要一致。GPR天然输出区间而LSTM需要额外构造如果你用分位数回归给LSTM构造区间就要保证两者的置信水平一致否则比较PICP没有意义。第三评价指标要一致。前面提到的那几个区间评价指标要在两个模型上统一计算不能一个用区间宽度、另一个用RMSE混着比那样得不出有效结论。5.6 常见问题速查表问题现象可能原因优先级排查动作训练太慢样本量过大重采样降频、稀疏近似、分块训练区间过窄噪声估计不足加WhiteKernel、放宽噪声bounds区间过宽噪声高估或核函数太柔性收窄noise bounds、衰减核函数刚度PICP远低于设定置信水平分布漂移或模型过于自信交叉验证确认、换核函数、增加噪声约束超参数优化不稳定数据量少/核函数复杂增加重启次数、先优化单参数、限制bounds预测区间负值目标变量约束问题对数变换、截断下限残差异方差明显噪声水平不一致对数变换、Box-Cox变换、异方差GPR6. 工程落地中的几点经验6.1 数据标准化与去趋势时间序列进入GPR之前数据预处理比模型选择更重要。以一个工业设备振动信号为例原始数据既有缓慢的退化趋势又有剧烈的局部抖动还有周期性波动。如果直接丢给GPR核函数会被搞懵——它不知道该用大尺度去匹配趋势还是用小尺度去匹配抖动。我的建议是先用一个简单的移动平均或局部回归把大趋势剥离出来趋势部分用简单的线性回归或多项式拟合可预测性很强。剩余的残差部分再用GPR建模和预测。GPR专注偏差部分的预测区间质量通常会大幅提升。最后把趋势预测和残差预测相加区间宽度也是两者方差叠加。这个两阶段预测的思路在工程里非常好用因为GPR的优势是灵活性高而不是处理大趋势的效率高。把简单的事情交给简单模型把复杂的事情交给GPR配合起来效果往往很稳。6.2 与业务指标的衔接区间预测的最终目的是辅助决策。在工程落地时我建议把所有区间指标换算成业务口径。比如库存备货场景你可以计算在保证95%覆盖率的前提下区间宽度带来的平均备货成本作为和现有方案对比的核心指标。这样业务方看到的不是一个抽象的PICP而是少缺货几次、少积压多少货这种可以直接评估的价值推动落地会容易很多。6.3 关于模型选型的选型建议回看整个项目我对模型选型的建议是不要神化GPR也不要神话深度学习一切以数据量级和业务需求为准。如果数据量小、需要概率性输出、并且你愿意接受调参带来的前期成本GPR是当之无愧的第一选择它的区间预测质量在小样本场景下几乎无敌。如果数据量大得惊人特征多、场景复杂那GPR的O(n³)会让人抓狂这时候深度学习路线更现实但要额外付出构造区间预测机制的成本。最后再分享一个我觉得很有用的小技巧如果你不确定场景适合不适合用GPR先用一个最简单的RBF核 1000条随机采样的数据跑一轮快速测试。如果测试集上预测均值已经有模有样说明数据规律性强值得深入研究如果连均值都是一条平线那问题多半不在模型而在数据特征构造上先把特征搞对再回来优化模型不迟。
返回列表