资讯详情

MATLAB LSTM多变量时序预测实战:从Excel数据到R2、MAE等指标全流程

📅 2026/10/29 23:21:20 | 华诺云谱 👁 阅读
MATLAB LSTM多变量时序预测实战:从Excel数据到R2、MAE等指标全流程
简介这份资源面向深度学习与时间序列分析的学习者和工程人员提供基于长短期记忆网络LSTM的多变量时间序列预测MATLAB实现方案可用于气象、能源、金融等存在多变量耦合的预测场景。压缩包共8个文件约1022KB包含1个m脚本文件承载LSTM网络构建、训练与预测主流程1个xlsx数据集提供多列变量与时间戳4个png图像展示原始数据与预测结果对比另有docx说明文档和txt文本辅助理解运行过程。代码在预测后计算R2、MAE、MSE、RMSE、MAPE等指标便于从拟合优度与误差两个角度评估模型表现。目前已有359人学习适合希望掌握LSTM多维时序建模、指标评估与MATLAB深度学习工具箱实操的读者参考复现。1. 从一份 MATLAB LSTM 时序预测包说起它到底能跑出什么结果如果你手上有一组带时间戳的多列数据想预测其中某一列的下一步走势又不想从零搭一套 Python 环境那这份基于 MATLAB 的 LSTM 多变量时间序列预测代码包大概率能让你在一个下午内看到第一条预测曲线。它包含LSTM.m主程序、数据集.xlsx样本数据、若干结果截图和一份运行说明文档核心是用长短期记忆网络对多维输入做回归预测并输出 R2、MAE、MSE、RMSE、MAPE 这一整套评价指标。适合做课题复现的学生、需要快速验证时序建模思路的算法工程师以及习惯在 MATLAB 里做数据分析、不想切到 Python 的从业者。下面我按「这份代码怎么跑起来、参数怎么改、哪里容易翻车」的顺序把它拆开讲一遍。2. LSTM 多变量时序预测的原理与这份代码的选型逻辑2.1 为什么多变量场景优先考虑 LSTM 而不是 ARIMA单变量时序预测里ARIMA 这类统计模型靠差分和自回归项就能吃下大部分平稳序列参数少、可解释性强。但一旦输入变成多列——比如同时喂入温度、湿度、风速去预测电力负荷——变量之间的交互关系是非线性且带时滞的ARIMA 的线性假设就撑不住了。LSTM 的门控结构输入门、遗忘门、输出门本质上是在每个时间步决定「记住什么、丢掉什么」这让它能捕捉跨几十个时间步的长程依赖而不像普通 RNN 那样梯度消失。这份代码选择 LSTM 而不是 BiLSTM 或 Transformer逻辑也很直接多变量回归预测任务里如果预测目标只依赖历史信息、不依赖未来信息单向 LSTM 就够用BiLSTM 的双向结构反而会引入未来信息泄漏的风险。至于 Transformer在样本量只有几百到几千条时注意力机制容易过拟合调参成本也高。所以这份代码的定位是「够用、能复现、指标齐全」不是追求 SOTA。2.2 数据从 Excel 到 LSTM 输入张量的转换链路MATLAB 的 LSTM 网络要求输入是元胞数组或特定维度的数值数组而数据集.xlsx里是扁平的表格中间必须做一步窗口化。常见做法是滑动窗口用前n个时间步的所有变量作为输入第n1步的目标变量作为标签。这个n就是后续要调的关键参数。% 读取多变量时序数据假设最后一列是预测目标 data readmatrix(数据集.xlsx); data data(:, 2:end); % 去掉时间戳列保留数值列 % 归一化LSTM 对输入尺度敏感必须做 dataNorm mapminmax(data, 0, 1); % 按列归一化到 [0,1] % 滑动窗口构造样本lookback 为回看步数 lookback 12; % 常见取值 6~24视采样频率而定 numSamples size(dataNorm, 1) - lookback; X cell(numSamples, 1); Y zeros(numSamples, 1); for i 1:numSamples X{i} dataNorm(i:ilookback-1, :); % 维度特征数 × 时间步 Y(i) dataNorm(ilookback, end); % 预测目标为最后一列 end这段代码里三个参数决定成败lookback控制模型能看到多长的历史太小则学不到趋势太大则样本数骤减且训练变慢mapminmax的归一化范围固定为 [0,1]是因为 LSTM 的 tanh 激活输出也在 [-1,1] 附近尺度对齐后收敛更稳X{i}的维度排列是「特征数 × 时间步」这是 MATLABsequenceInputLayer要求的格式转置写反了会直接报维度不匹配。2.3 网络结构定义与训练超参数的对应关系LSTM.m里的网络定义部分通常长这样一个sequenceInputLayer接lstmLayer再接fullyConnectedLayer和regressionLayer。层数不深但每个参数都有讲究。numFeatures size(dataNorm, 2); % 输入变量个数 numHiddenUnits 64; % 隐藏单元数常用 32/64/128 layers [ ... sequenceInputLayer(numFeatures) lstmLayer(numHiddenUnits, OutputMode, last) dropoutLayer(0.2) fullyConnectedLayer(1) regressionLayer]; options trainingOptions(adam, ... MaxEpochs, 200, ... MiniBatchSize, 32, ... InitialLearnRate, 0.005, ... LearnRateSchedule, piecewise, ... LearnRateDropPeriod, 50, ... LearnRateDropFactor, 0.5, ... GradientThreshold, 1, ... ValidationData, {XVal, YVal}, ... ValidationFrequency, 10, ... Plots, training-progress, ... Verbose, 0);OutputMode设为last表示只取最后一个时间步的输出做回归这是预测单一目标值的标准做法如果要做序列到序列预测才改成sequence。dropoutLayer(0.2)是防过拟合的常规手段样本量小于 500 时可以提到 0.3。GradientThreshold设为 1 是梯度裁剪LSTM 训练初期梯度容易爆炸不加这个参数 loss 曲线会直接飞掉。InitialLearnRate用 0.005 而不是默认的 0.01是因为时序回归任务对学习率更敏感太大容易在最优解附近震荡。3. 从 Excel 到预测曲线完整跑通流程与评价指标解读3.1 训练集/测试集划分与数据泄漏的边界时序数据的划分不能用随机打乱必须按时间顺序切。常见做法是前 80% 做训练、后 20% 做测试验证集从训练集尾部再切 10%。这份代码如果用了randperm打乱索引那就是一个隐藏的坑——打乱后模型会「看到」未来的数据R2 虚高到 0.99 但实际预测能力为零。% 按时间顺序划分禁止随机打乱 trainRatio 0.8; n length(Y); idxTrain 1:floor(n * trainRatio); idxTest floor(n * trainRatio) 1:n; XTrain X(idxTrain); YTrain Y(idxTrain); XTest X(idxTest); YTest Y(idxTest); % 从训练集尾部再切验证集 valRatio 0.1; nTrain length(YTrain); idxVal floor(nTrain * (1 - valRatio)) 1:nTrain; XVal XTrain(idxVal); YVal YTrain(idxVal); XTrain XTrain(1:idxVal(1)-1); YTrain YTrain(1:idxVal(1)-1);划分完之后归一化参数必须只用训练集计算再应用到测试集。如果对全量数据做mapminmax测试集的极值信息就泄漏进了训练过程。正确做法是记录训练集的 min/max用mapminmax(apply, ...)处理测试集。3.2 五个评价指标的计算与各自适用场景代码包里提到的 R2、MAE、MSE、RMSE、MAPE 不是凑数的每个指标反映的误差特性不同。R2 衡量拟合优度越接近 1 越好但它对异常值敏感MAE 是绝对误差的平均量纲和原始数据一致直观MSE 放大了大误差的权重适合关注极端偏差的场景RMSE 是 MSE 开根号量纲还原后比 MSE 好解释MAPE 是百分比误差适合比较不同量级序列的预测精度。% 反归一化后再算指标否则数值没有物理意义 YPred predict(net, XTest); YPred mapminmax(reverse, YPred, minY, maxY); YTestReal mapminmax(reverse, YTest, minY, maxY); R2 1 - sum((YTestReal - YPred).^2) / sum((YTestReal - mean(YTestReal)).^2); MAE mean(abs(YTestReal - YPred)); MSE mean((YTestReal - YPred).^2); RMSE sqrt(MSE); MAPE mean(abs((YTestReal - YPred) ./ YTestReal)) * 100; fprintf(R2%.4f MAE%.4f MSE%.4f RMSE%.4f MAPE%.2f%%\n, ... R2, MAE, MSE, RMSE, MAPE);这里有个血泪经验指标一定要在反归一化之后算。如果拿 [0,1] 区间的预测值去算 MAE得到的数字看起来很小很漂亮但和原始数据的物理量纲完全对不上写进报告里就是自欺欺人。另外 MAPE 在真实值接近 0 时会爆炸如果目标变量有零值或近零值MAPE 要慎用或者改用 SMAPE。3.3 预测结果可视化与残差检查代码包里的1.png到4.png大概率是训练 loss 曲线、预测对比图、残差图和散点图。自己跑的时候预测对比图要重点看两件事一是模型是否只是「滞后一步」地复制了真实值二是峰值和谷值是否被系统性低估。LSTM 回归任务里模型倾向于预测均值附近的平滑曲线极端值往往预测不准这是 MSE 损失函数的固有特性。figure; plot(YTestReal, b-, LineWidth, 1.2); hold on; plot(YPred, r--, LineWidth, 1.2); legend(真实值, 预测值); xlabel(时间步); ylabel(目标变量); title(sprintf(R2%.4f RMSE%.4f, R2, RMSE)); figure; residual YTestReal - YPred; plot(residual, k-); hold on; yline(0, r--); xlabel(时间步); ylabel(残差); title(残差序列);残差图如果呈现明显的周期性波动说明lookback没覆盖住数据的周期长度如果残差方差随时间增大说明数据存在异方差性可能需要先做对数变换再喂给网络。4. 避坑与排查这份代码最容易翻车的五个地方4.1 现象训练 loss 降到 0.001 但测试集 R2 是负数原因几乎可以锁定为数据泄漏或归一化错误。检查两处划分索引是否用了随机打乱归一化是否对全量数据做了mapminmax。还有一种可能是lookback设得太大训练样本数只剩几十条模型把训练集背下来了。解决方式是把lookback降到 6~12确认划分逻辑按时间顺序归一化参数只从训练集统计。4.2 现象报错「Invalid training data. The output size of the last layer does not match the number of classes」这是fullyConnectedLayer的输出维度写错了。回归任务输出单一目标值应该是fullyConnectedLayer(1)如果预测目标有多列改成对应的列数。同时检查YTrain的维度MATLAB 要求回归标签是numSamples × 1的数值向量如果从 Excel 读进来是行向量要转置。4.3 现象训练进度窗口的 loss 曲线剧烈震荡不收敛先看InitialLearnRate0.01 以上在时序回归里经常太大降到 0.005 或 0.001 试试。再看MiniBatchSize样本量小于 200 时用 32 会导致每个 epoch 只有几个 batch梯度更新噪声大改成 16 或 8。如果还震荡加GradientThreshold到 1 或 0.5并在 LSTM 层后加dropoutLayer(0.3)。4.4 现象预测曲线整体平移形状对但数值差一个常数归一化和反归一化的 min/max 不匹配。训练时用训练集的 min/max 归一化预测后必须用同一组 min/max 反归一化。如果中间重新计算了测试集的 min/max就会出现整体偏移。解决方式是把训练集的归一化参数存成变量测试和预测阶段统一调用mapminmax(apply, ...)和mapminmax(reverse, ...)。4.5 现象MAPE 算出几百甚至无穷大目标变量里存在零值或接近零的值除法直接爆炸。先检查YTestReal的最小绝对值如果小于 1e-6MAPE 就不可用。替代方案是改用 SMAPE或者对目标变量做平移加一个常数后再算 MAPE。更稳妥的做法是报告 MAE 和 RMSE这两个指标不受零值影响。5. 进阶调参与结果验证让 R2 从 0.8 推到 0.95 的实操技巧5.1 用贝叶斯优化替代手工试参手工调numHiddenUnits、lookback、InitialLearnRate这三个参数组合空间大且相互耦合。MATLAB 的bayesopt可以在几十次迭代内找到较优组合比网格搜索省时间。% 定义可优化变量 optimVars [ optimizableVariable(lookback, [6, 48], Type, integer) optimizableVariable(numHiddenUnits, [32, 256], Type, integer) optimizableVariable(InitialLearnRate, [1e-4, 1e-2], Transform, log) ]; % 目标函数返回验证集 RMSE objFcn (params) trainAndEval(params, dataNorm); results bayesopt(objFcn, optimVars, ... MaxObjectiveEvaluations, 30, ... IsObjectiveDeterministic, false, ... UseParallel, false);目标函数里每次用当前参数重新构造窗口、训练网络、在验证集上算 RMSE。30 次评估大概跑 20~40 分钟取决于数据量和隐藏单元数。注意IsObjectiveDeterministic设为 false因为 LSTM 初始化有随机性同一组参数两次训练结果会有波动。5.2 多步预测的递归策略与误差累积单步预测只预测下一个时间点多步预测要递归地把预测值喂回输入。递归 10 步以上误差会累积放大R2 会明显下降。缓解方式是训练时就用多步标签或者改用 seq2seq 结构。% 递归多步预测horizon 为预测步数 horizon 10; YPredMulti zeros(horizon, 1); currentInput XTest{1}; % 初始输入窗口 for h 1:horizon yHat predict(net, {currentInput}); YPredMulti(h) yHat; % 把预测值拼到输入窗口尾部去掉最老的一步 currentInput [currentInput(:, 2:end), ... [currentInput(:, end), yHat]]; % 简化示意按实际特征数调整 end递归预测的误差累积是结构性的不要指望靠调参完全消除。实际项目里如果预测步数超过 5 步建议直接训练一个输出维度为horizon的网络而不是递归调用单步模型。5.3 验证模型不是「背答案」的三个检查第一把测试集的时间顺序倒过来再预测一次如果 R2 依然很高说明模型学的是统计分布而非时间依赖大概率有泄漏。第二用训练集末尾的一段做预测和测试集开头的预测结果对比如果差异巨大说明模型对分布偏移敏感。第三画预测值 vs 真实值的散点图理想情况是点沿对角线分布如果散点呈水平带状说明模型只会预测均值。我自己的习惯是每次跑完新数据先把这三个检查过一遍再去看 R2 数字。有一次 R2 跑到 0.97散点图一画发现是一条水平线回头查代码发现归一化用了全量数据改过来之后 R2 掉到 0.89但那个数字才是真的。从那以后我每次拿到时序预测代码第一件事就是查划分和归一化第二件事就是画散点图。希望这份拆解能帮你少走几个弯路。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑