LSTM时间序列预测:EMD/EEMD/小波预处理与一元多元差分多步建模实战
简介这份资源围绕LSTM模型在时间序列预测中的实践展开面向具备一定深度学习基础、希望系统掌握序列建模与预测流程的学习者与开发者。内容从信号预处理到模型搭建层层递进涵盖经验模式分解、增强经验模式分解与小波分析等数据分解手段并对比一元、多元及差分处理下的LSTM实现还延伸至简单RNN与反向传播等基础环节帮助读者理解门控机制如何缓解梯度消失、捕获长期依赖。资源包共350个文件以82个ipynb交互式笔记、39个py脚本、18个h5模型权重、13个xlsx与11个csv数据表为主另含png图表、txt说明及npy数组等压缩包约14.63MB结构清晰便于按主题检索复现。目前已有3903人学习下载适合作为时间序列预测的实操参考与代码模板。1. 从一份多文件 LSTM 预测包说起它到底能跑出什么结果如果你手头有一批按时间采样的 CSV比如苹果、土豆、猪、姜这几类农产品的价格或产量序列想用 LSTM 做时间序列预测却卡在「先分解还是先差分」「单变量还是多变量」「单步还是多步」这几个岔路口那这份资源包基本就是照着这些岔路口铺开的。它把 EMD、EEMD、小波三种预处理和一元、多元、差分、多步四类 LSTM 结构拆成独立 notebook再配一份Makefile和setup.cfg把环境与执行入口固定下来。适合已经会写 Keras 或 PyTorch 基础 LSTM、但没系统对比过预处理与建模组合的人。下面按「资源结构 → 预处理 → 建模 → 避坑 → 进阶」的顺序拆。2. 资源结构与运行入口Makefile、setup.cfg 和 CSV 怎么配合2.1 文件清单与角色划分这份包不是单一脚本而是一组 notebook 加配置文件的组合。从文件名能直接读出设计意图文件类型在预测流程中的角色Makefile构建入口统一执行 notebook 转换、依赖安装、批量运行setup.cfg打包配置声明包元数据与依赖版本范围.coveragerc覆盖率配置限定统计范围排除 notebook 与测试目录EMD.ipynb预处理经验模式分解把非平稳序列拆成 IMFEEMD.ipynb预处理增强 EMD加白噪声集合平均抑制模态混叠Wavelets.ipynb预处理小波分解提供时频局部化视角EEMD_LSTM.ipynb组合EEMD 分解后逐分量送 LSTM 再重构lstm_univariate.ipynb建模单变量单步 LSTM 基线lstm_univariate_difference.ipynb建模单变量差分后 LSTM去趋势lstm_univariate_multistep.ipynb建模单变量多步预测lstm_multivariate.ipynb建模多变量输入 LSTMSimpleRNN.ipynb对照无门控 RNN作为 LSTM 的消融参照BP.ipynb对照反向传播基础实现理解梯度更新apple.csv/potato.csv/pig.csv/ginger.csv数据原始时间序列*_interpolate.csv数据插值补齐后的序列Makefile是整包的入口。常见做法是用它把 notebook 批量转成脚本再执行避免手动逐个打开。下面是一个可抄的Makefile骨架参数按你本机 Python 路径改# 把 notebook 批量转成可执行脚本再统一跑 PYTHON python3 NB_DIR . SCRIPT_DIR scripts convert: mkdir -p $(SCRIPT_DIR) jupyter nbconvert --to script $(NB_DIR)/*.ipynb --output-dir $(SCRIPT_DIR) run-univariate: convert $(PYTHON) $(SCRIPT_DIR)/lstm_univariate.py run-eemd: convert $(PYTHON) $(SCRIPT_DIR)/EEMD_LSTM.py clean: rm -rf $(SCRIPT_DIR)逻辑说明convert目标用nbconvert把每个 notebook 转成.py这样能在命令行里带参数、看日志、做 CI。run-univariate和run-eemd分别对应两条主线。参数上PYTHON换成你的解释器NB_DIR指向 notebook 所在目录。注意nbconvert默认不执行单元格只做格式转换所以脚本里如果有%matplotlib inline这类魔法命令转出来后要手动删掉或换成matplotlib.use(Agg)。2.2 setup.cfg 与依赖边界setup.cfg决定这份包能不能在干净环境里装起来。LSTM 预测常见的依赖是numpy、pandas、tensorflow或torch、PyEMD、PyWavelets、scikit-learn。一个能用的setup.cfg片段[metadata] name lstm-forecast-pack version 0.1.0 [options] packages find: install_requires numpy1.21 pandas1.3 scikit-learn1.0 PyEMD0.3 PyWavelets1.1 tensorflow2.8 [options.packages.find] exclude notebooks* tests*逻辑说明install_requires里把预处理和建模依赖分开列方便你换后端时只动一行。exclude把 notebook 目录排除在包外避免pip install时把大数据文件打进去。参数上tensorflow版本要和你的 CUDA 匹配如果只用 CPU 推理可以换成tensorflow-cpu。.coveragerc则用来在跑覆盖率时跳过 notebook 和插值数据目录常见配置是omit */notebooks/*, */tests/*。提示先跑pip install -e .确认依赖能解析再动 notebook。很多「跑不通」其实是依赖版本冲突不是模型问题。3. EMD、EEMD 与小波三种预处理到底怎么选3.1 EMD 与 EEMD 的分解逻辑EMD 把一条非平稳序列自适应地拆成若干 IMF 和一个残差。每个 IMF 代表一个时间尺度上的振荡频率从高到低排列。对 LSTM 来说直接喂原始价格序列模型要同时学趋势、季节和噪声难度大先分解再对每个 IMF 单独预测最后相加等于把问题拆小。EMD.ipynb里通常的调用是from PyEMD import EMD import numpy as np # 读取插值后的序列取单列 series np.loadtxt(apple_interpolate.csv, delimiter,, skiprows1)[:, 1] emd EMD() imfs emd(series) # 返回 shape(n_imf, len(series)) residue series - imfs.sum(axis0) print(IMF 数量:, imfs.shape[0])逻辑说明emd(series)返回二维数组行是 IMF列是时间点。residue是分解后的残差代表趋势项。参数上EMD()的max_imf可以限制分解层数默认不限制如果序列很长分解出的 IMF 可能超过 10 个后面逐个建模成本高常见做法是只保留前 5 到 8 个 IMF其余归入残差。EEMD 在 EMD 基础上加白噪声做集合平均解决模态混叠。EEMD.ipynb的典型调用from PyEMD import EEMD eemd EEMD() eemd.noise_seed(42) # 固定随机种子保证可复现 eemd.trials 100 # 集合次数越大越稳但越慢 eemd.noise_width 0.2 # 噪声幅度通常取序列标准差的 0.2 倍 imfs_eemd eemd(series)逻辑说明trials是加噪声重复分解的次数100 次是精度和耗时的折中noise_width控制加入噪声的幅度太小压不住混叠太大引入伪分量。固定noise_seed是血泪经验否则每次跑出来的 IMF 顺序和数值都有细微差异实验没法对比。3.2 小波分解的时频视角Wavelets.ipynb走的是另一条路。小波分解把序列投影到不同尺度的基函数上得到近似系数和细节系数。和 EMD 相比小波需要你选母小波和分解层数主观性更强但计算更快、结果更稳定。常见调用import pywt # 选用 db4 小波分解 4 层 coeffs pywt.wavedec(series, db4, level4) cA4, cD4, cD3, cD2, cD1 coeffs # 重构时只保留低频做趋势预测 trend pywt.waverec([cA4] [None]*4, db4)逻辑说明wavedec返回[cA_n, cD_n, ..., cD_1]cA是近似低频cD是细节高频。参数上db4适合平滑性较好的序列level一般取log2(len(series))向下取整再减 1。如果序列有突变点db1Haar反而更敏感。和 EMD 的差别在于小波分解层数是你定的EMD 是数据自适应的小波重构需要所有系数EMD 可以只取部分 IMF。注意三种预处理没有绝对优劣。EEMD 最稳但最慢小波最快但需要调母小波EMD 居中但模态混叠风险高。先各跑一遍看分解图再决定用哪个进 LSTM。4. 一元、多元、差分与多步LSTM 建模的四种骨架4.1 一元 LSTM 与差分处理lstm_univariate.ipynb是最小可用基线输入过去 N 个时间点预测下一个点。核心是构造滑动窗口import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense def make_windows(series, look_back12): X, y [], [] for i in range(len(series) - look_back): X.append(series[i:ilook_back]) y.append(series[ilook_back]) return np.array(X), np.array(y) X, y make_windows(series, look_back12) X X.reshape((X.shape[0], X.shape[1], 1)) # LSTM 需要 3D 输入 model Sequential([ LSTM(64, activationtanh, input_shape(12, 1)), Dense(1) ]) model.compile(optimizeradam, lossmse) model.fit(X, y, epochs50, batch_size32, validation_split0.2)逻辑说明look_back12表示用过去 12 个点预测第 13 个点这个参数要按采样频率调——日数据常用 7 到 30月数据常用 3 到 12。LSTM(64)的 64 是隐藏单元数序列越长、模式越复杂就往上加但超过 128 在小数据集上容易过拟合。reshape那一步是新手最常翻车的地方Keras 的 LSTM 要求输入是(样本, 时间步, 特征)少一维直接报错。lstm_univariate_difference.ipynb在进窗口前多做一步差分diff np.diff(series, n1) # 一阶差分去趋势 # 预测完 diff 后用 cumsum 还原 pred_series np.cumsum(np.insert(pred_diff, 0, series[0]))逻辑说明差分把非平稳序列变成近似平稳LSTM 更容易学到短期波动。参数n1是一阶差分如果序列还有季节趋势可以用n12做季节差分。还原时cumsum的起点必须是原始序列第一个值否则整体偏移。4.2 多元 LSTM 与多步预测lstm_multivariate.ipynb把多个相关序列拼成特征矩阵。比如苹果、土豆、猪、姜的价格可能受共同因素影响一起喂进去能让模型共享信息import pandas as pd df pd.read_csv(apple_interpolate.csv) # 假设已对齐时间轴拼成 (T, 4) 的特征矩阵 features df[[apple, potato, pig, ginger]].values X, y make_windows(features, look_back12) # X shape: (样本, 12, 4)最后一维是特征数 model Sequential([ LSTM(64, input_shape(12, 4)), Dense(1) ])逻辑说明多元输入的关键是时间轴对齐*_interpolate.csv就是为这一步准备的——原始序列有缺失时先插值补齐再拼矩阵。Dense(1)表示只预测其中一个目标变量如果要同时预测多个把输出改成Dense(4)。参数上特征数从 1 变 4 后LSTM的参数量增加训练时间变长batch_size可以适当调小。lstm_univariate_multistep.ipynb做多步预测两种常见策略直接多输出和递归预测。直接多输出是把Dense(1)改成Dense(k)一次预测未来 k 个点递归预测是预测一步后把结果拼回输入再预测下一步。前者误差不累积但需要更多训练样本后者实现简单但误差会滚雪球。代码上直接多输出更干净def make_multistep_windows(series, look_back12, horizon3): X, y [], [] for i in range(len(series) - look_back - horizon 1): X.append(series[i:ilook_back]) y.append(series[ilook_back:ilook_backhorizon]) return np.array(X), np.array(y) X, y make_multistep_windows(series, look_back12, horizon3) model Sequential([ LSTM(64, input_shape(12, 1)), Dense(3) # 一次输出未来 3 个点 ])逻辑说明horizon3是预测步长Dense(3)对应三个输出。损失函数仍用mse但评估时要分步看误差通常第 1 步最准第 3 步明显变差。如果 horizon 超过 5建议改用编码器-解码器结构普通 LSTM 加Dense会力不从心。4.3 SimpleRNN 与 BP 的对照价值SimpleRNN.ipynb和BP.ipynb不是用来出预测结果的是用来做消融和理解的。把LSTM(64)换成SimpleRNN(64)其他不变跑同一份数据你会看到长序列上 SimpleRNN 的验证损失明显更高这就是门控机制的价值。BP.ipynb手写反向传播能帮你确认梯度消失到底发生在哪一层。这两个文件在调参卡住时特别有用——当你不确定是数据问题还是模型问题时用它们做对照能快速定位。5. 避坑与排查这份包里最容易翻车的五个点5.1 插值文件与原始文件混用现象模型在训练集上 loss 很低一到测试集就崩。原因apple.csv和apple_interpolate.csv时间轴长度不同混用后窗口错位。解决统一用插值后的文件做建模原始文件只用来核对缺失位置在make_windows前打印len(series)确认。5.2 EEMD 每次结果不一致现象同一份数据跑两次IMF 数量和数值都有差异。原因EEMD 加白噪声时没固定种子。解决在EEMD()后立刻调eemd.noise_seed(42)并把trials固定为 100。如果还要求完全可复现把分解结果存成.npy后续 LSTM 直接读分解结果。5.3 差分后忘记还原现象预测曲线和原始曲线形状对但数值差一个量级。原因模型学的是差分序列评估时直接拿差分值对比原始值。解决预测完先cumsum再和原始序列比还原起点用训练集最后一个原始值不是测试集第一个值。5.4 look_back 设得比序列还长现象make_windows返回空数组model.fit报维度错误。原因look_back大于等于序列长度。解决先算len(series)look_back取不超过len(series)//5的值序列短于 100 个点时LSTM 本身就不合适考虑换传统时序模型。5.5 多变量输入时特征未归一化现象某个特征量纲远大于其他特征模型只学那一个其他特征形同虚设。原因多元 LSTM 对输入尺度敏感。解决进窗口前对每个特征单独做MinMaxScaler预测后再逆变换scaler 只在训练集上 fit避免信息泄漏。提示这五个坑里插值混用和差分还原是最常见的「看起来对、实际错」。每次跑完先画一张预测 vs 真实的对比图肉眼过一遍再信指标。6. 进阶技巧用 EEMD_LSTM 组合与滚动验证把误差压下来EEMD_LSTM.ipynb是整包里最值得细看的一个。它的思路是EEMD 把原始序列拆成若干 IMF 和残差每个分量单独送 LSTM 预测最后把所有分量的预测值相加得到最终结果。这样做的好处是每个 IMF 频率单一LSTM 学起来轻松代价是分量多时训练次数成倍增加。实操上我一般只保留前 6 个 IMF其余归入残差一起预测。组合预测的关键在重构顺序。下面是一个可复用的重构片段# imfs_pred: list每个元素是某个 IMF 的预测序列 # residue_pred: 残差预测序列 final_pred np.sum(imfs_pred, axis0) residue_pred # 如果之前做了差分这里再 cumsum 还原 final_pred np.cumsum(np.insert(final_pred, 0, last_train_value))[1:]逻辑说明np.sum(imfs_pred, axis0)把所有分量预测按时间点相加residue_pred单独加。参数上last_train_value是训练集最后一个原始值用于差分还原。如果没做差分去掉cumsum那行。验证方法上别用单次 train/test split。时间序列要用滚动验证固定窗口向前滑每次用过去 T 个点训练、预测接下来 H 个点记录每步误差。下面是一个最小滚动验证框架def rolling_validate(series, train_size, horizon, step1): errors [] for start in range(0, len(series) - train_size - horizon 1, step): train series[start:starttrain_size] test series[starttrain_size:starttrain_sizehorizon] pred train_and_predict(train, horizon) # 你的训练预测函数 errors.append(np.mean((pred - test) ** 2)) return np.mean(errors), np.std(errors)逻辑说明train_size是每次训练用的历史长度horizon是预测步长step控制滑动间隔。返回的均值和标准差一起看——均值低但标准差大说明模型不稳定换个随机种子结果就变。参数上train_size至少取look_back的 3 倍horizon别超过train_size的 1/5。还有一个容易忽略的点EEMD 分解本身有边界效应序列两端的 IMF 不可靠。滚动验证时如果测试段落在边界附近误差会虚高。常见做法是分解前在序列两端做镜像延拓或者干脆把边界各去掉 10% 再评估。从那以后我每次跑 LSTM 预测都强制先画三张图原始序列与分解分量、训练集预测 vs 真实、滚动验证误差分布。三张图都过了才去看 RMSE 和 MAE 这些数字。希望帮到你。本文还有配套的精品资源点击获取