ARTICLE DETAIL

资讯详情

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

EMD-KPCA-LSTM提升多变量时序预测精度:原理、代码与实验对比

EMD-KPCA-LSTM提升多变量时序预测精度:原理、代码与实验对比 简介时间序列预测是工业与工程数据建模中的常见任务但非平稳、多尺度、含噪声的信号往往让神经网络难以稳定拟合。LSTM虽擅长捕捉长短期依赖却需要从混叠信号中隐式分离不同频段的波动导致欠拟合或过拟合。经验模态分解EMD能将复杂信号逐层拆解为多个固有模态函数与残差降低非平稳性核主成分分析KPCA则利用核技巧提取高维特征中的非线性结构有效压缩维度。两者结合LSTM可让网络专注于学习分量间的映射关系提升回归预测的可靠性与泛化能力。该方法适用于能耗预测、设备寿命估计、负荷预报等场景。本文基于Matlab实现裸LSTM、EMD-LSTM、EMD-KPCA-LSTM三组对比实验展示从信号分解到降维再到预测的完整流程并给出关键代码与参数选择经验为多输入单输出时序回归任务提供可复现的优化思路。 把一组多变量时间序列直接扔进LSTM做回归预测我第一版代码只用了一个下午就跑通了结果测试集R²在0.6左右晃悠。训练过程里损失曲线一路往下掉看着很漂亮可到了验证集和测试集上预测曲线和真实曲线明显对不齐。工业数据、负荷数据、振动数据基本都是非平稳、多尺度、带噪声的裸LSTM再强也难以同时消化不同频段叠加出来的复杂波动。最近我把这套“多输入单输出回归预测”重新整理成了三组对比实验纯LSTM、EMD-LSTM、EMD-KPCA-LSTM在同一个数据集上比较了预测误差和稳定性并打包了完整的Matlab程序和数据。这篇就把整个流程、代码细节和踩过的坑一次说清楚。1. 多输入单输出时序预测为什么我试了裸LSTM之后不满足1.1 这类任务到底长什么样所谓多输入单输出最典型的形式是有一张数据表若干列代表不同传感器或工况特征比如温度、压力、振动幅值、电流、流量等最后一列是你要预测的目标值比如设备剩余寿命、能耗指标、某种质量参数。数据按时间顺序排列任务目标是利用当前时刻以及过去若干个时刻的多维观测预测未来某一时刻的目标值。在Matlab里处理时常规做法是滑动窗口假设用过去T个时刻的D维特征预测下一个时刻的目标值。那么每个训练样本的输入形状是D×T的矩阵输出是一个标量。把所有样本组合起来就是标准的sequence-to-one回归任务。这种设定在工程预测里非常常见也是我这次对比实验的基础框架。1.2 裸LSTM为什么容易“练得动、测不准”LSTM对时间序列的长短期依赖捕捉能力确实强但它不是万能的。原始数据里如果同时混着趋势项、周期波动、随机噪声和非线性漂移LSTM需要自己从这些混叠信号里隐式地学出一个映射关系。网络虽然理论上可以逼近任意函数但实际训练中隐层单元要同时承担“拆解不同频段”和“建立时序依赖”两项工作参数效率和泛化能力都会下降。我自己的数据集里目标变量明显存在多尺度波动有近似线性的趋势有周期性起伏还叠加了高频毛刺。直接用原始特征训练LSTM问题主要有三个非平稳性让LSTM的输入分布在不同时间窗口内差异很大模型很难稳定学习。高频噪声和低频趋势混在一起梯度更新容易被噪声主导。如果特征维度又比较多网络参数规模会快速膨胀小样本场景下非常容易过拟合。更关键的是这三个问题不是单纯靠加深网络、加dropout就能解决的。预处理阶段如果能先把信号分解开让LSTM只负责学习“分解后的分量到目标值的映射”预测任务就简化了一大截。1.3 预处理三板斧EMD、KPCA、LSTM各自分工我最终采用的方案是把任务拆成三步EMD经验模态分解用来把每个输入特征的复杂信号拆成若干个不同尺度的IMF分量和一个残差项降低非平稳性。KPCA核主成分分析用来处理EMD之后特征维度暴涨的问题同时利用核函数捕捉分量之间的非线性相关性把高维特征压缩成低维但信息密度更高的特征。LSTM用来对压缩后的特征做最终的序列回归预测。三组对比实验正好验证了每一步的作用裸LSTM是基线EMD-LSTM证明了分解这一步对预测精度的提升EMD-KPCA-LSTM则进一步证明了在分解之后加一道非线性降维不仅能降低训练开销还能让指标再上一个台阶。2. 先用EMD把非线性非平稳信号拆开预测问题才真正简化2.1 EMD的直觉理解拿筛子一层层分拣信号EMD全称经验模态分解核心思想是把一个信号拆成若干个固有模态函数IMF加一个残差。每个IMF需要满足两个条件极值点数目和过零点数目相等或者最多相差一个上包络线和下包络线关于时间轴局部对称。换句话说每个IMF像一个相对干净的振荡分量频率尺度彼此区分。你可以把原始信号想象成一杯混合了很多种豆子的容器EMD的作用就是把豆子按大小分拣出来。分拣过程是迭代的先用极大值点和极小值点构造上、下包络线取均值得到均值包络原信号减去均值包络得到候选IMF如果候选不满足IMF条件就重复筛选直到满足条件为止。剩下的残差通常代表趋势项或直流分量。对预测任务来说这么做最直接的好处是LSTM不再需要自己从混叠信号里拆解不同频段而是直接面对一组更平稳、更规律的分量。每个IMF的时间尺度相对单一规律性更容易被LSTM学到。残差项则保留了信号的整体趋势正好适合LSTM去拟合长期走向。2.2 Matlab里调用emd的实操细节Matlab从R2017b开始在Signal Processing Toolbox里内置了emd函数直接调用就行不需要额外安装工具箱。基本用法是这样[imf, residual] emd(x);这里x是输入的一维信号imf是一个矩阵行数等于分解出的IMF数量列数等于信号长度residual是残差向量。如果信号被分解出K个IMF那么原始信号约等于sum(imf,1) residual。我通常会在分解后做一步重构验证reconstruct sum(imf, 1) residual; max_abs_err max(abs(reconstruct - x)); fprintf(最大重构误差: %.4e\n, max_abs_err);如果重构误差在1e-8量级以下说明分解正常。如果出现明显偏差多半是参数设置或者数值精度问题。emd函数有几个关键参数值得关注MaxNumIMF限制分解出的IMF最大个数。默认值是10如果信号非常复杂可以适当调大比如15或20。SiftRelativeTolerance筛选过程的停止容差。默认值是1如果希望IMF更精细可以调小到0.5左右但计算时间会增加。MaxNumSifting每个IMF的最大筛选次数。默认100实际使用时我一般保持默认。我的经验是先用默认参数跑一遍观察分解结果和重构误差如果某些IMF明显混叠了多个尺度再降低SiftRelativeTolerance或者考虑用EEMD集合经验模态分解来缓解模态混叠问题。不过EEMD的计算量是EMD的数倍数据规模大时要权衡。2.3 多输入特征怎么统一做EMD多输入场景下每个特征列都是一条独立的时间序列所以需要对每一列分别做EMD。这里有个容易踩的细节不同特征分解出的IMF数量可能不同。有些特征可能分解出8个IMF有些可能是10个直接拼接成特征矩阵会导致维度对不齐。我用的处理方式是设置一个统一的IMF数量上限P对每个特征只保留前P个IMF加上残差项。这样每个特征都映射成一个固定长度为P1的分量组所有特征拼接后得到统一的逐点特征矩阵方便后续KPCA降维和LSTM输入。对应代码大概是下面这个样子。注意EMD输入要求是列向量输出要转置后再拼接numFeatures size(data_norm, 2); P 8; % 统一保留的IMF数量 featMatrix []; for f 1:numFeatures [imf, residual] emd(data_norm(:, f)); nIMF size(imf, 1); if nIMF P % 不足部分补零 imf_pad [imf; zeros(P - nIMF, length(residual))]; else imf_pad imf(1:P, :); end featBlock [imf_pad; residual]; % 每个特征得到(P1)个分量 featMatrix [featMatrix, featBlock]; % 按时间点拼接 end这样得到featMatrix的形状是N×(numFeatures×(P1))N是时间点数量。如果原始有10个特征每个保留8个IMF加1个残差那特征维度就是90。这个维度对LSTM来说已经偏高了这正是下一步引入KPCA的主要原因。3. 特征维度爆了怎么办KPCA降维的原理与局限性3.1 为什么线性PCA在这个场景不够用EMD分解之后特征维度可能从原来的10维膨胀到80-100维。直接把这些特征全部喂给LSTM一是网络参数量激增训练时间翻倍二是容易过拟合。所以必须降维。降维首选自然是PCA但PCA本质是线性变换只能捕捉特征之间的线性相关性。EMD分解出的各IMF分量之间、不同特征的同尺度分量之间常常存在非线性关联用线性PCA压缩会丢失一部分有效信息。KPCA就是这个场景下更合适的选择。KPCA的核心思想是先用核函数把原始数据映射到一个高维特征空间在高维空间里做PCA。由于核函数隐式定义了高维空间的内积我们不需要真的把数据映射过去只需要计算核矩阵然后对核矩阵做特征分解。高斯核函数是最常用的选择形式是k(x_i, x_j) exp(-||x_i - x_j||^2 / (2σ²))σ是核宽度决定了样本之间的相似度随距离衰减的速度。3.2 手写一个简单的KPCA降维函数Matlab里没有专门的KPCA内置函数虽然有个别工具箱提供支持但我更推荐自己写一个既灵活又能看清原理。下面是我在项目中用的版本基于高斯核function [X_proj, eigvecs] simple_kpca(X, sigma, k) % X: n_samples x n_features % sigma: 高斯核宽度 % k: 保留的主成分个数 n size(X, 1); % 计算高斯核矩阵 K zeros(n, n); for i 1:n for j i:n d2 sum((X(i,:) - X(j,:)).^2); K(i,j) exp(-d2 / (2 * sigma^2)); K(j,i) K(i,j); end end % 中心化核矩阵 one_n ones(n, n) / n; Kc K - one_n * K - K * one_n one_n * K * one_n; % 特征分解 [V, D] eig(Kc); d diag(D); [~, idx] sort(d, descend); eigvecs V(:, idx(1:k)); % 投影 X_proj Kc * eigvecs; end使用这段代码要注意几点核矩阵是n×nn是样本数量。如果样本量很大核矩阵会非常占内存。我实际数据量大概几千个样本量级跑起来没问题如果上万就需要考虑分块或近似方法了。特征分解得到的特征向量最好归一化一下尤其在做严格形式化计算时需要除以特征值的平方根。在预测任务里有时直接用上面的投影结果也能得到不错的效果。σ的选择对结果影响很大。σ太小样本之间相似度普遍很低核矩阵接近单位阵降维效果近似于把每个样本孤立σ太大样本之间相似度都接近1投影出来没有区分度。3.3 KPCA核宽度的实用选择方法我没有用严格的交叉验证框架而是采用了一个更实用的办法先计算样本两两距离的中位数然后在中位数的0.1倍到10倍范围内取几个候选值分别跑一遍KPCALSTM对比验证集误差选效果最好的σ。这样比拍脑袋定值靠谱得多又不会太耗时。顺带说一句KPCA降维后保留的主成分个数也不是越多越好。我对比过保留10、20、30、40个主成分的效果发现20个左右在这个数据集上综合表现最好。保留太少会丢失细节保留太多等于没降多少维训练代价变大但指标提升有限。4. 三种模型在Matlab里的实现差异数据组织、网络结构与训练参数4.1 数据准备滑动窗口怎么切才不走样所有模型共用的数据准备流程是这样的先把原始数据按时间先后顺序切分成训练集和测试集前80%训练后20%测试。注意不能随机打乱数据否则会把未来信息混进训练集导致验证指标虚高。切分训练集和测试集之后再做归一化。这一点极其重要归一化的均值和标准差必须只用训练集计算再用这组参数去归一化测试集否则测试集的信息就泄漏到了训练过程中。train_raw data(1:trainN, :); test_raw data(trainN1:end, :); mu mean(train_raw, 1); sd std(train_raw, 0, 1); sd(sd 1e-12) 1; train_norm (train_raw - mu) ./ sd; test_norm (test_raw - mu) ./ sd;滑动窗口的构造代码统一写成下面这种形式。注意输入cell数组里每个元素是D×T矩阵对应T个时间步、D个特征输出是下一时刻的目标值function [XCell, Y] create_sliding_window(data, T, outIdx) n size(data, 1) - T; XCell cell(n, 1); Y zeros(n, 1); for i 1:n XCell{i} data(i:iT-1, :); Y(i) data(iT, outIdx); end end窗口长度T的选择也需要单独说。T太短LSTM学不到足够的时序依赖T太长样本数量减少训练成本上升。我在这套数据上对比了T8、12、20最终用了12。实际任务里建议用验证集误差来选不要拍脑袋定。4.2 三种模型各自的输入长什么样这一节是整个实验设计的核心差异所在。纯LSTM直接用滑动窗口构造的原始特征序列作为输入。假设原始有10个输入特征那每个样本就是10×12的矩阵。EMD-LSTM先对每个特征逐列做EMD分解取前P个IMF加残差拼接成高维逐点特征矩阵再做滑动窗口。每个样本的输入维度就从10变成了10×(P1)在我这套设置里就是90维。EMD-KPCA-LSTM在高维逐点特征矩阵上先做KPCA降维到20维然后再滑动窗口。每个样本输入是20×12的矩阵。三个模型的差别只在特征提取阶段网络结构、训练超参数、数据划分完全保持一致。这样对比出来的效果差异才能归因于EMD和KPCA这两个处理步骤。4.3 LSTM网络结构与训练选项网络结构我用了一个相对保守的双层LSTM加dropout结构rng(1); layers [ sequenceInputLayer(numFeatures) lstmLayer(64, OutputMode, sequence) dropoutLayer(0.2) lstmLayer(32, OutputMode, last) fullyConnectedLayer(1) regressionLayer]; options trainingOptions(adam, ... MaxEpochs, 200, ... MiniBatchSize, 32, ... InitialLearnRate, 0.005, ... Shuffle, every-epoch, ... Verbose, 0, ... Plots, training-progress); net trainNetwork(Xtr, Ytr, layers, options);简单解释一下几个关键选择第一层LSTM用了OutputMode为sequence让输出保持序列形式第二层LSTM才用last只输出最后一个时间步的结果。这样可以保留更多中间层学到的时序特征。dropout加在两层LSTM之间比例0.2。对于样本量不是特别大的数据集这个比例能有效防止过拟合又不会让网络学不动。初始学习率0.005配合adam优化器整体训练比较稳。如果数据噪声大可以再降到0.001。rng(1)必须放在trainNetwork之前用来固定随机种子。LSTM初始化有随机性不固定种子的话同一套数据和代码每次跑出来的结果都不一样实验就没法对比了。训练完成之后用predict函数对测试集做预测Ypred predict(net, Xte);如果得到的结果是行向量记得转置成和真实标签一样的列向量再计算指标。5. 结果对比怎么做才不“自欺欺人”评价指标与样本分析5.1 四个指标的计算方式我这次用了四个指标评估预测效果均方根误差RMSE、平均绝对误差MAE、平均绝对百分比误差MAPE、决定系数R²。各自的计算代码很简单rmse sqrt(mean((Ytrue - Ypred).^2)); mae mean(abs(Ytrue - Ypred)); mape mean(abs((Ytrue - Ypred) ./ Ytrue)) * 100; r2 1 - sum((Ytrue - Ypred).^2) / sum((Ytrue - mean(Ytrue)).^2);这里有个细节MAPE在目标值接近0的时候会变得很不稳定因为真实值作为分母一旦接近0误差比例会被无限放大。如果数据集存在这种情况建议改用对称MAPE或者干脆用RMSE和MAE做主要评估。5.2 一组典型结果从0.61到0.89的跨越在我这个数据集上三组模型的对比结果大致是下面这样。为了说明趋势我用了一组代表值具体程序包里的结果会因数据和随机种子略有浮动但趋势一致模型RMSEMAEMAPE(%)R²LSTM0.1240.0987.820.612EMD-LSTM0.0870.0655.140.820EMD-KPCA-LSTM0.0710.0523.960.893裸LSTM的R²只有0.61左右测试集上预测曲线和真实曲线存在明显错位尤其是波动剧烈的位置预测值经常“跟不上”真实值的变化。加入EMD分解之后R²提升到0.82RMSE几乎降了三分之一。这个提升非常直观EMD把非平稳信号拆成相对平稳的分量后LSTM学习起来轻松太多了。EMD-KPCA-LSTM进一步把R²提升到0.89RMSE再降18%左右。值得注意的是它在训练时间上反而比EMD-LSTM更短因为输入维度从90降到了20网络参数数量大幅减少收敛也更快。这个结果说明KPCA不只是“为了降维而降维”它把EMD分解后分量之间的冗余信息去掉了让LSTM能够把容量用在真正有判别力的特征上。5.3 曲线和残差图怎么看除了四个指标我习惯把测试集的预测曲线和真实曲线画在一起同时画残差分布图。曲线图能直观看到哪些时间段误差大残差图能看出是否存在系统性偏差。figure; plot(Ytrue, b-, LineWidth, 1.2); hold on; plot(Ypred, r--, LineWidth, 1.2); legend(真实值, 预测值, Location, best); grid on;残差图如果呈现出随机分布在零线附近的形态说明模型拟合比较充分如果残差存在明显的趋势或者周期性说明还有未提取出来的有效信息可以考虑调整EMD的IMF数量或者KPCA的核参数。6. 实操坑位复盘端点效应、核函数、归一化与复现性6.1 EMD端点效应和模态混叠EMD在实际使用中最常见的两个坑是端点效应和模态混叠。端点效应是指信号两端的包络线容易向外发散导致两端分解出的IMF明显畸变。处理办法有几个一是在分解前对信号做端点延拓比如镜像延拓法二是在做预测时尽量不要使用靠近序列两端的时间点三是在滑动窗口构造样本时适当丢弃序列最早和最晚的一部分窗口。我在程序里采用的做法是先判断当前数据集中哪个时间区间容易受端点效应影响然后把这个区间的样本标记出来在后续分析中重点关注预测误差是否集中在这个区间。如果误差确实集中在两端就要考虑改进分解策略。模态混叠是指同一个IMF里混入了不同时间尺度的成分表现为IMF的振幅随时间不均匀。缓解办法是用EEMD或CEEMDAN这类集合方法它们通过加入高斯白噪声辅助分解抑制模态混叠但计算量会显著增加。如果数据量不大可以先试EMD效果不好再升级到EEMD。6.2 KPCA的核宽度选择千万别拍脑袋高斯核的σ对KPCA结果影响巨大。我最初直接取σ1跑了一版结果降维后的特征几乎没有任何区分度LSTM效果甚至比裸LSTM还差。后来改成“以样本两两距离的分布为基准”的选参方法才把效果提上去。具体做法是从训练集里随机抽1000个样本计算两两欧氏距离取距离的中位数作为基准σ0然后在0.1σ0、0.5σ0、σ0、2σ0、10σ0几档里做小网格搜索用验证集误差选最优。这个方法虽然朴素但在工程上相当实用。6.3 数据泄漏比模型选错更致命很多人在做时序预测时容易忽略一个原则测试集的信息不能以任何形式进入训练过程。具体到程序里有三个地方非常容易犯这个错归一化时用整体数据的均值和方差而不是仅仅用训练集的。这会偷偷把测试集的信息带入模型。我的做法是先切分再归一化并且归一化参数只从训练集计算。做EMD和KPCA时也需要注意。严格来说特征提取的参数也应该用训练集拟合。不过EMD本身没有从训练集外引入参数影响相对小但KPCA的σ和主成分数量如果在全量数据上调优就存在信息泄漏风险。我的程序里是先切分好训练集和测试集再在训练集上做特征提取和参数选择。滑动窗口构造样本时不能跨训练集和测试集边界。最后一个训练窗口如果包含了属于测试集的时间点那就有未来信息混入训练。6.4 复现性随机种子和多次运行取平均LSTM训练有随机性仅仅固定一次随机种子跑出来的结果可能有偏差。严格一点的实验设计是在同一个数据集上用不同的随机种子跑5次取误差的均值和标准差来评估模型稳定性。我在程序包里已经预设了固定随机种子的入口默认rng(1)可以直接跑出和这篇文章一致的版本如果你要更严谨地对比可以改成循环跑多次。另外提醒一句Matlab在GPU上训练LSTM时即使设置相同的随机种子由于并行计算顺序的不确定性结果也可能和CPU上有细微差异。所以如果要对三种模型做严格对比尽量在同一台机器、同一个计算设备上跑完所有实验。6.5 程序包里的文件组织建议最后说一下整套程序包的文件组织。我的习惯是分成四个文件main.m负责整体流程调度create_sliding_window.m负责滑动窗口构造simple_kpca.m负责核主成分分析降维run_lstm_experiment.m负责训练和评估单个模型。数据文件单独放一个data.xlsx包含所有输入特征和输出目标变量。这样三个模型的对比只需要在main.m里切换特征处理分支代码结构清晰也方便你改数据换成自己的场景。整套流程我前前后后重跑过几轮印象最深的是第一次把EMD得到的全部IMF直接丢给LSTM时训练时间直接翻倍测试集指标并没有同步变好。加了KPCA这一道压缩以后训练时间降了大约四成测试集误差反而更小。这也是我为什么更推荐EMD-KPCA-LSTM这条路径的原因。如果你手上的数据同样是多变量、非平稳的回归预测任务建议先别急着堆网络层数从头开始梳理一遍信号特征再决定LSTM该怎么接效果可能会出乎意料。本文还有配套的精品资源点击获取
返回列表