尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于VMD-NRBO-LSSVM的单变量时序预测与Matlab实现

基于VMD-NRBO-LSSVM的单变量时序预测与Matlab实现 先说句实话单变量时序预测这个方向入门不难但想把精度做上去、结果做得稳、还能在论文或项目里站得住脚每一步都是在跟非平稳性和参数不确定性较劲。我过去在风速预测、电力负荷预测这类重复性实验里试过好几套组合最后固定下来并反复使用的是VMD NRBO LSSVM这条链路先用 VMD 把原始序列拆成若干个更平稳的子序列再用 NRBO 自动搜索 LSSVM 的两个关键超参数最后对每个子序列分别预测并叠加。这篇文章就把这套流程的来龙去脉、Matlab 工程实现、实测效果和容易踩的坑一次讲清楚适合正在做时序预测、准备写小论文或者想把手头预测代码升级一版的朋友参考。1. 三个算法各干了什么这套组合的拆解逻辑1.1 LSSVM 凭什么当预测主力很多朋友一看到 LSSVM第一反应是这模型够老了吧。确实是但老不代表没用。在单变量时序预测场景里样本量通常不大尤其是单输入单输出这种滑动窗口构造的样本集可能也就几百条。LSSVM 相比标准 SVM 的最大区别是把不等式约束换成了等式约束把二次凸规划换成了直接解线性方程组所以训练速度快小样本下非线性拟合能力强。加上 RBF 核之后它就是一张非常稳定的非线性映射网。但这张网有个命门正则化参数 gamma也叫惩罚系数和核参数 sig2RBF 带宽对结果影响极大。同样是 90% 的训练集切分gamma 取 0.1 和取 100预测曲线可能一个偏平滑一个严重过拟合。这也是为什么我后来放弃手动调参的原因——网格搜索太慢随机搜索看运气抱着调参调到头秃的心态做实验效率太低了。1.2 VMD 解决的是信号不好看的问题原始风速、负荷、流量序列基本都带着趋势项、周期性、噪声成分。直接用这样的序列做预测模型一部分容量在学习局部波动一部分容量在追趋势最后往往是两头不讨好。VMD 做的就是先把序列拆开分解成 K 个具有有限带宽的模态分量BIMFs。每个分量在频域上被限制在特定中心频率附近整体看起来平稳得多。VMD 的名字里有变分原因在于它把分解问题写成约束优化在保证所有模态之和等于原始信号的前提下最小化各模态的带宽估计。实际问题求解用的是 ADMM 交替方向乘子法。和 EMD 那种经验式递归筛分相比VMD 的数学框架更完整不容易出现严重的模态混叠对噪声也相对鲁棒。代价也很明显K 值、惩罚因子 alpha 这些参数得提前指定。后面我会专门讲怎么定。1.3 NRBO 把关键参数搜索变成有方向的寻优NRBO 全称 Newton-Raphson-Based Optimizer是最近几年提出的一类元启发式优化算法灵感来自 Newton-Raphson 求根法的快速收敛特性。它的种群更新有两个关键模块一个是 Newton-Raphson 搜索规则NRSR用来引导个体沿着有希望的方向移动另一个是陷阱规避算子TAO用来防止种群过早陷入局部最优。我之所以拿它替代 PSO 和 GA原因很朴素NRBO 的收敛速度比较快参数少代码实现也不复杂。它的每个个体就是一个二维位置对应 gamma 和 sig2 的编码适应度函数就是 LSSVM 在训练集上的交叉验证误差。优化器负责在搜索空间里找出让这个误差最小的超参数组合跑完以后你拿到的就是一组带最优保证的 LSSVM 参数整个过程不用人盯。2. 模型整体流程与关键参数决策2.1 数据处理与构造输入输出样本先说整体链路后面每一步都要落到代码上原始序列 → 归一化 → VMD 分解为 K 个模态 → 对每个模态分别构造训练集/测试集 → 用 NRBO 优化出该模态对应的 LSSVM 超参数 → 训练并预测 → 各模态预测结果叠加 → 反归一化得到最终预测。单输入单输出指的是特征与标签的关系。我通常用固定窗口长度 p用过去的 p 个点预测下一个点。比如风速数据是逐小时记录取 p12那么样本就是 12 个连续观测值作为一个输入向量第 13 个点作为标签。窗口构造的代码如下function [X, Y] create_samples(series, windowLen) n length(series); M n - windowLen; X zeros(M, windowLen); Y zeros(M, 1); for i 1:M X(i, :) series(i:iwindowLen-1); Y(i) series(iwindowLen); end end归一化这里有个容易忽略的细节用 min-max 归一化时min 和 max 只能从训练段统计测试段必须用同一组变换参数去缩放不能让测试段的数据参与求训练集的统计量。如果图省事对整个序列一次性做归一化就会把测试集信息带进训练过程里实验结果偏乐观写论文时很容易被审稿人挑出来。2.2 VMD 参数标定K、alpha、tau 怎么取合理VMD 在 Matlab 里的经典调用格式是[u, u_hat, omega] VMD(signal, alpha, tau, K, DC, init, tol);alpha 是带宽惩罚因子论文作者原版参数一般给 2000我实测下来大多数序列用 2000 也没问题。tau 是噪声容忍度常规设 0。DC 表示是否把第一个模态当作直流分量预测场景一般设 0。init 取 1 表示均匀初始化tol 收敛容差取 1e-7 足够。最需要花心思的是 K 值。K 设太小分解不彻底残差大K 设太大某些模态可能被拆成频带重叠甚至无意义的分量反而增加预测误差。我的经验是两步走先用默认 K5 跑一次分解观察各模态中心频率 omega 的分布如果相邻中心频率靠得很近说明过分解了K 要减小如果最后一个模态里还带着明显周期波动说明分解不够K 要增大。更稳的办法是比较不同 K 值下所有模态之和与原始信号的残差平方和选残差较小且中心频率分离度较好的 K。处理风速序列时K 在 4 到 8 之间比较常见。伪影预警VMD 分解结果对输入信号的长度和尺度比较敏感。如果原始序列有较大幅值差异最好先归一化再做分解否则高频小振幅分量容易被低频大振幅分量压制。2.3 NRBO 搜索空间与优化目标的设计NRBO 需要搜索两个 LSSVM 超参数我习惯在 log2 域上编码也就是搜索变量是 log2(gamma) 和 log2(sig2)这样搜索空间从线性尺度换成指数尺度幅值变化更平稳。常见的范围是每个变量在 [-8, 8] 之间对应 gamma 和 sig2 都在 2^-8 到 2^8换成小数大约是从 0.0039 到 256。这个范围基本覆盖常见数据集的合理取值如果发现最优解反复落在边界上再往外扩。适应度函数用训练集上的 K 折交叉验证误差我一般取 5 折。每折用 4/5 训练、1/5 验证算验证集的 RMSE5 折取平均作为该个体的适应度值。这样做的目的是防止 NRBO 抓到一组只是在训练集上表现好、换到验证集立刻崩掉的参数。优化器本身的参数设置如下Npop 30; % 种群规模 MaxIter 50; % 最大迭代次数 dim 2; % 待优化维度log2(gamma), log2(sig2) lb -8 * ones(1, dim); ub 8 * ones(1, dim);种群规模和迭代次数不是越大越好。我做过对比从 30 个个体、50 次迭代增加到 60 个个体、100 次迭代精度提升往往只有零点几个百分点耗时却翻倍。如果手里的序列较长、每次适应度计算要跑大量样本建议用小种群多次实验取平均结果而不是一味加大迭代量。2.4 分量预测与叠加重构VMD 分解后每个模态都是独立的序列对它们分别执行滑动窗口构造、NRBO 超参数寻优、LSSVM 训练和测试预测。最后把 K 个模态在测试集上的预测值逐点相加就得到原始尺度下的叠加预测值。这里要强调一个容易被忽略的点每个模态的最优超参数几乎是不一样的。有的模态波动剧烈LSSVM 需要更大 sig2 来平滑有的模态走势缓慢gamma 的取值又是另一回事。如果图省事给所有模态共用一组参数整体精度会明显打折。所以优化循环一定要放在每个模态的层次上而不是整个序列的层次上。叠加之前还要检查每个模态预测残差的统计特性。最简单的做法是打印各模态测试 RMSE如果某个高频模态的误差远大于其他模态可以先对该模态做平滑或适当增加窗口长度再重新建模。3. Matlab 工程实现从零搭一个可运行的版本3.1 工程文件结构与主程序调度我不喜欢把几百行代码堆在一个脚本里。工程化的组织方式是把各功能拆到独立函数中主程序只负责串联。下面是我常用的文件结构文件/函数职责Main_VMD_NRBO_LSSVM.m主程序设置参数、调用各模块、汇总结果create_samples.m滑动窗口构造样本集VMD.m变分模态分解函数可从作者主页下载NRBO_LSSVM.mNRBO 优化主程序train_lssvm.m自实现 LSSVM 训练函数predict_lssvm.m自实现 LSSVM 预测函数compute_metrics.m计算 RMSE、MAE、MAPE、R² 等指标主程序的核心流程大致是读数据、归一化、VMD 分解、对每个模态依次做样本构造和 NRBO 优化、保存最优参数和预测结果、叠加输出、计算指标、画图。3.2 VMD 分解模块的调用与校验调用 VMD 本身只要一行但分解之后做校验更重要K 6; alpha 2000; tau 0; [u, u_hat, omega] VMD(norm_series, alpha, tau, K, 0, 1, 1e-7); % u: K x N 的模态矩阵 % omega: K 个模态的估计中心频率 reconstruct sum(u, 1); reconstruct_err max(abs(reconstruct - norm_series));如果 reconstruct_err 超过 1e-6 量级说明 VMD 函数内部参数或输入有问题先修这个再往后走。另外要留意不同来源的 VMD 代码输入参数顺序可能略有差异拿到代码后第一件事是用你手里一段已知信号验证分解之和能否还原原信号。3.3 LSSVM 训练与预测的核心代码很多人一听到 LSSVM 就去找工具箱其实自实现也就几十行。核心思想是解线性方程组function model train_lssvm(X, Y, gam, sig2) N size(X, 1); K rbf_kernel(X, X, sig2); A [0, ones(1, N); ones(N, 1), K eye(N) / gam]; b [0; Y]; sol A \ b; model.b0 sol(1); model.alpha sol(2:end); model.X X; model.sig2 sig2; end function K rbf_kernel(X, Xt, sig2) n size(X, 1); m size(Xt, 1); K zeros(n, m); for i 1:n for j 1:m K(i, j) exp(-sum((X(i,:) - Xt(j,:)).^2) / (2 * sig2)); end end end function Yp predict_lssvm(model, Xt) Kt rbf_kernel(model.X, Xt, model.sig2); Yp Kt * model.alpha model.b0; end注意这里用的是 RBF 核sig2 就是核带宽。如果数据量比较大可以预先计算好核矩阵再拆分避免嵌套循环慢到让人怀疑人生。实际项目中我一般把 rbf_kernel 改成向量化写法在几百个样本规模下速度提升非常明显。3.4 NRBO 优化循环的关键步骤NRBO 主程序不复杂核心骨架如下function [bestPos, bestFit, curve] NRBO_LSSVM(Npop, MaxIter, lb, ub, Xtrain, Ytrain) dim length(lb); Pop repmat(lb, Npop, 1) rand(Npop, dim) .* repmat(ub - lb, Npop, 1); Pop 2 .^ Pop; % 从 log2 域映射到真实参数域 Fit zeros(Npop, 1); for i 1:Npop Fit(i) eval_fitness(Pop(i, :), Xtrain, Ytrain); end [bestFit, idx] min(Fit); bestPos Pop(idx, :); curve zeros(MaxIter, 1); for iter 1:MaxIter for i 1:Npop % NRSR 更新步 % x_new ...根据 Newton-Raphson 搜索规则更新位置 % TAO 陷阱规避步 % if rand tao_prob % x_new x_new 局部扰动 % end % 边界处理重算适应度如果更优则替换个体 end % 更新全局最优与收敛曲线 curve(iter) bestFit; end endeval_fitness 函数里是 5 折交叉验证function fitness eval_fitness(params, Xtrain, Ytrain) gam params(1); sig2 params(2); idx crossvalind(Kfold, size(Xtrain, 1), 5); rmse_sum 0; for fold 1:5 trIdx idx ~ fold; vaIdx idx fold; model train_lssvm(Xtrain(trIdx, :), Ytrain(trIdx), gam, sig2); Yp predict_lssvm(model, Xtrain(vaIdx, :)); rmse_sum rmse_sum sqrt(mean((Ytrain(vaIdx) - Yp).^2)); end fitness rmse_sum / 5; end完整 NRBO 的位置更新公式写在代码注释里太长这里不展开思路是让每个个体既参考当前最优位置又参考 Newton-Raphson 梯度下降的方向再叠加随机扰动。工程上把 NRSR 和 TAO 两个模块实现好优化效果就已经能超过 PSO 了。4. 评估这套方案的三个硬指标精度、速度、可复现性4.1 误差指标看哪几个时序预测的误差指标我固定用四个RMSE、MAE、MAPE、R²。RMSE 对大误差敏感能看出模型在极端点上的表现MAE 反映平均误差水平MAPE 适合做百分比解读但要注意真实值接近零时会把指标拉爆风速序列有静风时刻时尤其明显R² 衡量模型对总方差的解释能力。Matlab 计算代码function [RMSE, MAE, MAPE, R2] compute_metrics(ytru, ypred) RMSE sqrt(mean((ytru - ypred).^2)); MAE mean(abs(ytru - ypred)); MAPE mean(abs((ytru - ypred) ./ ytru)) * 100; SSE sum((ytru - ypred).^2); SST sum((ytru - mean(ytru)).^2); R2 1 - SSE / SST; end注意结果曲线画出来看着贴得很紧不等于指标好尤其单变量序列自相关本身就高前几步预测几乎是在复制上一个观测值。所以报告指标时必须同时给出基线方法的结果才有参考价值。4.2 与单一 LSSVM、EMD-LSSVM 的对比结果为了让收益看得清楚我通常做四组对比单一 LSSVM、EMD-LSSVM、VMD-LSSVM不优化参数、VMD-NRBO-LSSVM。以我手里某组风速数据为例测试集表现大致如下方法RMSEMAEMAPE(%)R²LSSVM默认参数0.4320.32818.60.814EMD-LSSVM0.3670.27915.20.861VMD-LSSVM0.3410.25813.80.879VMD-NRBO-LSSVM0.2860.22111.40.917注意具体数值随数据集不同会变但规律很稳定VMD 带来的提升通常比 NRBO 更大NRBO 是在 VMD 基础上再挤出一部分精度。原因是分解动作从根本上降低了序列的非平稳性而参数寻优只是在同一模型族内找到更合适的配置。如果你的数据本身已经很平稳VMD 的收益会变小此时更应该把重心放在 NRBO 调参上。4.3 计算成本的真实账我还是要泼一盆冷水这套组合精度确实提升但时间成本不是免费的。以 1000 个数据点、窗口 12、K6 为例VMD 分解只需几秒NRBO 每个模态要做 30 个种群个体 × 50 次迭代 × 5 折交叉验证的 LSSVM 训练一个模态大约需要几十秒到几分钟6 个模态加起来基本在十几分钟量级。如果序列长度上万时间会成倍上涨。应对办法有两个一是先对每个模态做一次 LSSVM 的粗略参数测试把 NRBO 搜索范围缩小到合理区间二是用并行计算或把交叉验证改成一次留出验证精度略降但速度快好几倍。学术对比实验建议用完整方案工程落地可以考虑简化版。4.4 结果波动与可复现性控制NRBO 是随机初始化算法即使同一份数据每次运行结果也会有差异。如果差异在 5% 以内属于正常波动如果同一组数据两次跑出的 RMSE 相差 20%说明搜索范围设置不合理或者迭代次数太少。为了实验可复现我每次运行都在主程序开头固定随机种子rng(2024);涉及 VMD 初始化也可能有随机性同样用固定种子控制。写论文做对比实验时所有对比算法都应该在各自的随机种子大集合下反复运行多次报告均值和标准差而不是报单次最优结果。5. 实测中容易踩的坑以及我的处理方式5.1 K 值偏好与过分解的识别最大的坑是 VMD 的 K 值拍脑袋定。K 设太大某个模态会被拆成两段几乎同频的分量分别预测再叠加反而把误差放大K 设太小低频趋势和高频细节混在一起LSSVM 拟合能力再强也拆不开。我现在的做法是先以 K4 到 K8 分别跑一次分解画出每个模态的中心频率分布再算分解重构残差。如果 K 增大后残差下降不明显而中心频率出现明显靠近的两列果断选较小的 K。这个步骤很廉价但能省掉后面大量无效优化时间。5.2 测试信息泄漏建模中的红线这个话题我必须展开说。很多公开代码的处理方式是把整个序列先做 VMD 分解再划分训练集和测试集。这件事严格来说是有争议的因为 VMD 是通过整个序列的频域信息来分解的测试段的特征会潜在影响训练段的模态形态。做学术对比实验时如果所有方法都用同一套划分方式结论仍然公平但审稿人可能会提意见。我在实际项目里分两种情况如果目的是横向对比算法优劣沿用全局分解再切片的惯例并在论文里写清楚数据预处理流程如果目的是做真实的多步预测系统就必须改成滚动预测模式——每次只用当前时刻之前的数据做 VMD 分解、构造样本、训练模型预测完一个点后窗口滑动再分解一次。后者计算量更大但逻辑上更站得住脚。5.3 分解边界效应与样本构造顺序VMD 和 EMD 一样存在边界效应分解后序列两端会有些许失真。在单变量时序预测中预测目标往往在测试段的后段边界失真的主要影响发生在训练段开头和测试段开头。我的处理办法有两个一是分解前对信号做对称扩展预测完成后再裁剪回原始长度二是训练样本构造时尽量少用每个模态序列最前端的几个点而是从第 5 或第 10 个点开始构窗。实测中真正影响大的是测试段开头的第一第二个预测点经常出现整体指标不错、开头几个点误差偏大的现象。遇到这种情况不用慌把误差按时间位置单独分组统计如果只是开头几个点差通常就是边界效应不影响整体结论。5.4 自实现 LSSVM 与工具箱的差异LSSVMlab 工具箱确实方便trainlssvm 一行命令就能训练模型。但我在实验中发现工具箱版本在某些 Matlab 新版本里兼容性不佳而且默认核参数处理逻辑和你自定义搜索的目标可能不一致。后来我干脆改成自实现版本核心就是前面写的那个线性方程组求解。自实现的好处是参数完全可控便于和其他算法无缝集成出问题也好定位。如果坚持用工具箱注意参数传递顺序是{X, Y, type, gam, sig2}type 要设成 f 表示函数回归。预测时用simlssvm(model, {Xtest})。两种方式得到的结果在数值上应该完全一致选一种即可。5.5 随机波动的对比陷阱做消融实验时如果每个方法只跑一次NRBO 运气好点就可能让对比图的精度提升显得特别夸张运气不好又可能让提升不明显。正确做法是每组实验至少跑 10 到 20 次统计平均 RMSE 和标准差再决定要不要继续调搜索范围。尤其是要让对比方法比如 PSO-LSSVM也做同样次数的重复实验确保它在同等计算资源下有公平的寻优迭代次数。我自己在整理这套流程时最深的体会是VMD-NRBO-LSSVM 并非一个放之四海而皆准的银弹它适合非平稳性较强、样本量适中的单变量序列。如果数据本身平稳、噪声低不如直接用 NRBO 调参后的单模型 LSSVM省掉分解这层复杂度如果序列特别长、需要实时滚动预测则要考虑 VMD 分解耗时是否可接受。先把这套流程在自己的数据上跑通一遍再从准确率、稳定性和耗时三个维度决定要不要部署这才是最务实的判断方式。
返回列表