时间序列预测七模型实战:LSTM、GRU、CNN+LSTM 对比与避坑指南

发布时间:2026/10/18 12:16:46
时间序列预测七模型实战:LSTM、GRU、CNN+LSTM 对比与避坑指南 简介这份资源面向希望系统入门时间序列预测的开发者与学习者围绕同一类预测任务横向对比BP神经网络、CNN、LSTM、GRU、RNN、SVM以及CNNLSTM混合模型等多种建模思路帮助读者理解不同网络结构在时序数据上的适用场景与效果差异。压缩包共25个文件以9个Python脚本为核心配合10个CSV、3个XLSX数据文件及TXT、JSON、PKL等辅助文件整体约5.08MB脚本与数据按模型分目录组织便于逐个运行与对照实验。内容覆盖上车测试与训练数据、月度太阳黑子等典型时序数据集既有单模型实现也有CNN与LSTM的融合结构可用来练习数据读取、特征构造、模型搭建与预测评估的完整流程。目前已有1177人学习适合作为课程设计、入门练手或算法对比实验的参考素材。1. 从一份时间序列预测学习包说起七种模型同台到底该怎么跑很多人做时间序列预测第一步就卡在“模型选型”上——业务方丢过来一份带时间戳的销量表或者传感器数据要求下周给个预测结果你打开搜索引擎满屏都是 LSTM、GRU、Transformer到底用哪个这份「时间序列预测学习」资源包的价值就在这它把 BP、CNN、LSTM、GRU、RNN、SVM 以及 cnnlstm 混合结构这七种常见方案各自配了一份可运行的数据和脚本放在同一个压缩包里。你不用再东拼西凑找 demo解压之后每个文件夹就是一个独立的最小可复现单元。适合谁刚接触时序预测、想快速把各模型跑通对比一遍的开发者也适合已经用过 LSTM 但没试过 cnnlstm 混合结构、想看看特征提取层加进去到底有没有提升的熟手。包里数据分两类一类是上车测试/训练数据xlsx 格式偏业务场景一类是 Monthly Sunspots.csv经典太阳黑子数据集偏教学验证。两条线并行方便你既看业务数据表现也看标准数据集上的收敛情况。2. 拆包看结构七套脚本各自吃什么数据、吐什么结果2.1 目录映射与数据格式对照解压之后不要急着跑先把目录和数据格式对一遍。这个包的结构不是统一框架而是按模型分文件夹各自为政所以每个子目录的入口脚本、数据路径、依赖都不一样。下面这张表是我实际拆包后整理的对应关系跑之前先确认你手上有没有对应的数据文件。模型/结构入口脚本配套数据数据格式任务类型BP/NNNN_model.py需自行指定或复用 xlsxxlsx/csv回归预测RNNelman_rnn.py内置序列构造或 csvcsv单步/多步预测LSTMLSTM模型.py上车训练数据.xlsx、上车测试数据.xlsxxlsx业务时序预测GRUGRU_Sunspots.pyMonthly Sunspots.csvcsv标准数据集验证SVMsvmprediction.py read_data.py20180829.xlsxxlsx回归预测cnnlstmcnn_lstm.py data_helper.pymini_data 目录自定义混合结构预测这张表的核心信息是数据格式不统一。LSTM 和 SVM 走 xlsxGRU 走 csvcnnlstm 走 mini_data 自定义格式。这意味着你不能指望一个数据加载函数通吃所有脚本每个文件夹都得单独看它的 read 逻辑。常见做法是先把 xlsx 用 pandas 读进来确认列名和时间列再决定要不要转成 csv 统一管理。2.2 各脚本的输入输出约定以 LSTM 为例LSTM模型.py默认读取同目录下的上车训练数据.xlsx和上车测试数据.xlsx。你需要确认两件事时间列是哪一列、预测目标列是哪一列。很多新手直接跑报KeyError就是因为脚本里写死的列名和你数据里的列名对不上。import pandas as pd # 读取训练数据先看列名和形状 train_df pd.read_excel(上车训练数据.xlsx) print(train_df.columns.tolist()) print(train_df.shape) print(train_df.head()) # 常见坑时间列可能是字符串需要转成 datetime # train_df[时间列名] pd.to_datetime(train_df[时间列名]) # train_df train_df.sort_values(时间列名).reset_index(dropTrue)这段代码的作用是“先侦察再动手”。参数说明pd.read_excel的sheet_name默认是第一个 sheet如果你的数据在第二个 sheet要显式指定。sort_values那行注释很关键——时序数据必须按时间排序否则 LSTM 学到的顺序是乱的loss 会莫名其妙地震荡这种玄学问题十有八九是排序没做。GRU 那边走的是Monthly Sunspots.csv这个数据集列少、干净适合先跑通流程再换业务数据。GRU_Sunspots.py里通常会做归一化和滑动窗口构造窗口大小lookback是个关键参数后面单独讲。SVM 这套稍微特殊read_data.py负责读20180829.xlsx并做特征工程svmprediction.py负责建模预测。SVM 做时序预测的思路是把历史若干步拼成特征向量然后当回归问题解。它的优势是小样本下不容易过拟合劣势是窗口一大特征维度爆炸训练时间直线上升。cnnlstm 这套是包里结构最完整的mini_data放数据data_helper.py做批处理和窗口构造cnn_lstm.py定义网络。CNN 层负责从局部窗口里提特征LSTM 层负责学时序依赖这个组合在不少时序任务上确实比纯 LSTM 稳。但它的数据管道是自定义的你得先读懂data_helper.py里的__init__.py和mini_build相关逻辑才能把自有数据塞进去。3. 把 LSTM 和 GRU 跑起来窗口构造、归一化与训练参数3.1 滑动窗口构造lookback 到底设多少时序预测和普通回归最大的区别在于样本不是独立同分布的而是用过去 N 步预测未来 M 步。这个 N 就是 lookback回看窗口。设太小模型看不到足够的历史模式设太大噪声被放大训练也慢。我一般会先看数据的周期性如果数据有明显的 7 天周期lookback 至少设 14如果是月度数据lookback 设 12 或 24。import numpy as np def make_windows(series, lookback24, horizon1): series: 一维归一化后的序列 lookback: 回看步数 horizon: 预测未来第几步 返回: X shape (样本数, lookback, 1), y shape (样本数,) X, y [], [] for i in range(len(series) - lookback - horizon 1): X.append(series[i:ilookback]) y.append(series[ilookbackhorizon-1]) X np.array(X).reshape(-1, lookback, 1) y np.array(y) return X, y逻辑说明循环从 0 到len(series)-lookback-horizon1每次取 lookback 长度的窗口作为输入取窗口后第 horizon 个点作为标签。reshape(-1, lookback, 1)是为了适配 LSTM 的输入格式(batch, timesteps, features)。参数怎么改horizon1 是单步预测改成 3 就是预测未来第三步lookback 根据数据周期调整。注意归一化要在构造窗口之前做而且要用训练集的最大最小值去归一化测试集不能各自归一化否则信息泄露测试集表现会虚高。3.2 LSTM 模型搭建与训练参数LSTM模型.py里的网络结构一般不会太复杂常见是两层 LSTM 加一个全连接输出。但有几个参数直接决定你能不能跑出合理结果。from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.optimizers import Adam model Sequential([ LSTM(64, return_sequencesTrue, input_shape(lookback, 1)), Dropout(0.2), LSTM(32, return_sequencesFalse), Dropout(0.2), Dense(1) ]) model.compile(optimizerAdam(learning_rate0.001), lossmse) history model.fit(X_train, y_train, epochs100, batch_size32, validation_split0.1, verbose1)参数说明第一层 LSTM 的return_sequencesTrue是为了把序列传给第二层 LSTM如果只有一层 LSTM这行可以去掉。Dropout(0.2)是防过拟合的数据量小的时候可以加到 0.3。learning_rate0.001是 Adam 的常用起点如果 loss 下降太慢可以调到 0.005如果震荡就降到 0.0005。batch_size32不是固定的样本少就设 16 甚至 8。validation_split0.1是从训练集尾部切 10% 做验证注意时序数据不能随机切验证集必须按时间顺序切否则又是信息泄露。GRU 的脚本结构类似把LSTM换成GRU即可参数量会少一些训练速度通常快 20% 到 30%。在 Monthly Sunspots 这种数据量不大的场景下GRU 和 LSTM 的最终误差往往差不多但 GRU 收敛更快。我的习惯是先跑 GRU 快速验证数据管道和窗口设置对不对确认没问题再换 LSTM 精调。3.3 训练过程怎么看loss 曲线与早停跑起来之后不要只盯着最后那个 MSE 数字。训练过程中要看两个东西训练 loss 和验证 loss 的差距、验证 loss 是否开始上升。如果训练 loss 一直降但验证 loss 在某个 epoch 后开始涨说明过拟合了这时候要么加 Dropout要么减模型容量要么早点停。from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue) history model.fit(X_train, y_train, epochs200, batch_size32, validation_split0.1, callbacks[early_stop], verbose1)patience10的意思是验证 loss 连续 10 个 epoch 没改善就停restore_best_weightsTrue会恢复到验证 loss 最低那个 epoch 的权重。这个回调能帮你省掉手动调 epoch 数的麻烦也是避免过拟合的后悔药。注意monitor默认是val_loss如果你自己切了验证集要改成对应的 key。4. cnnlstm 混合结构CNN 提特征、LSTM 学依赖怎么接才不翻车4.1 混合结构的连接方式与维度对齐cnnlstm 的核心思路是先用一维卷积在时间轴上滑动提取局部模式比如连续几天的突增突降再把卷积输出的特征序列喂给 LSTM 学长期依赖。这个结构在不少时序任务上比纯 LSTM 效果好因为 CNN 层相当于自动做了特征工程。但连接的时候最容易翻车的地方是维度。Conv1D 的输出是(batch, new_timesteps, filters)LSTM 需要的是(batch, timesteps, features)。如果卷积的 stride 和 padding 没设好new_timesteps会变LSTM 的input_shape就对不上。from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense, Flatten from tensorflow.keras.models import Sequential model Sequential([ Conv1D(filters32, kernel_size3, activationrelu, input_shape(lookback, 1)), MaxPooling1D(pool_size2), Conv1D(filters64, kernel_size3, activationrelu), LSTM(50, return_sequencesFalse), Dense(1) ]) model.compile(optimizeradam, lossmse) model.summary()逻辑说明第一层 Conv1D 的input_shape(lookback, 1)1 是特征维度单变量时序就是 1。kernel_size3表示每次看 3 个连续时间步。MaxPooling1D(pool_size2)把时间步减半减少计算量。第二层 Conv1D 的 filters 加到 64提取更丰富的特征。最后 LSTM 的return_sequencesFalse只取最后一个时间步的输出接 Dense 出预测值。参数怎么调如果model.summary()报维度错误先看 MaxPooling 之后的时间步是多少再确认 LSTM 能不能接上。常见做法是池化之后时间步还太长可以再加一层池化或者把 LSTM 的input_shape改成(None, filters)让它自动适配。data_helper.py里的mini_build相关逻辑就是干这个的——把原始数据切成适合卷积和循环层的形状。4.2 数据管道对接把自有数据塞进 mini_datamini_data目录和data_helper.py是配套的。你要用自己的数据跑 cnnlstm最稳妥的方式是照着mini_data里的格式准备一份然后改data_helper.py里的读取路径。# data_helper.py 里常见的读取和窗口构造逻辑 import pandas as pd import numpy as np def load_mini_data(path, lookback24, horizon1): df pd.read_csv(path) # 假设第一列是时间第二列是数值 series df.iloc[:, 1].values.astype(float) # 归一化 series (series - series.min()) / (series.max() - series.min() 1e-8) X, y [], [] for i in range(len(series) - lookback - horizon 1): X.append(series[i:ilookback]) y.append(series[ilookbackhorizon-1]) return np.array(X).reshape(-1, lookback, 1), np.array(y)这段代码和前面 LSTM 的窗口构造逻辑一致区别在于它从 csv 读数据并且假设了列的位置。如果你的数据列顺序不同改df.iloc[:, 1]里的索引。1e-8是防止除以零。注意归一化用的是全局最大最小值实际项目中应该只用训练集的最大最小值这里为了简化没做区分你自己改的时候要补上。4.3 训练与验证混合结构到底有没有提升跑完 cnnlstm 之后和纯 LSTM 的结果对比一下。对比的时候不能只看一个随机划分的测试集因为时序数据波动大单次划分的结果可能只是运气。我的做法是用同样的 lookback 和 horizon分别跑 LSTM 和 cnnlstm各跑 3 次取平均 MSE。如果 cnnlstm 的平均 MSE 比 LSTM 低 10% 以上那这个提升大概率是真实的如果只低 2% 到 3%可能是随机波动不值得增加复杂度。另外要注意cnnlstm 的参数量通常比纯 LSTM 大训练时间也更长。如果数据量很小比如只有几百个点CNN 层可能学不到有意义的局部模式反而更容易过拟合。这种情况下纯 GRU 或 SVM 可能是更务实的选择。5. 避坑与排查七套脚本跑下来最容易翻车的五个地方5.1 现象loss 是 nan训练一开始就崩原因学习率太大或者数据里有 nan/无穷大值或者归一化的时候除以了零。时序数据里经常有缺失值pandas 读进来是 NaN直接送进模型就会导致 loss 变 nan。解决训练前先做df.isnull().sum()检查缺失值用df.fillna(methodffill)前向填充或者插值补上。归一化时分母加1e-8。学习率从 0.001 起步不要一上来就 0.01。5.2 现象预测结果是一条直线完全不跟着数据波动原因模型没学到东西可能是 lookback 太小、归一化把数据压得太扁、或者训练 epoch 不够。另一个常见原因是输出层用了 sigmoid 但目标值没归一化到 0 到 1 之间。解决先确认归一化范围如果目标值在 0 到 1 之外输出层不要用 sigmoid。把 lookback 调大试试比如从 12 调到 24。训练 epoch 加到 200 以上配合 EarlyStopping。如果还是直线检查数据本身是不是方差太小。5.3 现象SVM 跑得特别慢内存爆了原因SVM 做时序预测时如果 lookback 设得大特征维度就是 lookback样本数乘以特征维度很容易撑爆内存。而且 SVM 的训练复杂度是 O(n²) 到 O(n³)样本一多就慢得离谱。解决控制 lookback 在 10 到 20 之间不要超过 30。样本数超过几千条时SVM 不是好选择换 LSTM 或 GRU。如果一定要用 SVM可以先用 PCA 降维或者用LinearSVC替代SVC。5.4 现象cnnlstm 报维度不匹配改了半天改不对原因Conv1D 和 MaxPooling1D 会改变时间步长度LSTM 的input_shape如果写死了具体数字池化之后就对不上。另外data_helper.py里 reshape 的形状和模型输入不一致也会报错。解决用model.summary()逐层看输出形状确认池化后的时间步。LSTM 的input_shape可以写成(None, filters)让 Keras 自动推断。数据管道那边在 reshape 之后打印X.shape和模型第一层的输入要求对一遍。5.5 现象GRU 在 Sunspots 上表现很好换到业务数据就崩原因Sunspots 是平滑的周期性数据业务数据往往有噪声、缺失、突变。在干净数据上调的窗口大小和归一化方式换到脏数据上不适用。解决换数据后重新做探索性分析看缺失值比例、异常值分布、周期性是否明显。归一化方式可能要从 min-max 改成 z-score因为业务数据可能有极端值min-max 会被拉偏。lookback 也要重新试不要直接套用。6. 进阶技巧用同一套数据把七个模型串起来对比跑通单个脚本只是第一步这份资源真正的用法是用同一份数据、同一个窗口设置把七个模型跑一遍横向对比。这样你才能知道在你的数据上到底哪个模型性价比最高。具体做法选一份你手头的数据比如上车训练数据.xlsx统一做归一化和窗口构造导出成X_train.npy、y_train.npy、X_test.npy、y_test.npy。然后每个模型脚本只改数据加载部分都读这四个 npy 文件。这样模型之间的差异就只来自网络结构本身而不是数据预处理。# 统一数据准备脚本 prepare_data.py import pandas as pd import numpy as np df pd.read_excel(上车训练数据.xlsx) series df.iloc[:, 1].values.astype(float) series (series - series.min()) / (series.max() - series.min() 1e-8) lookback, horizon 24, 1 X, y [], [] for i in range(len(series) - lookback - horizon 1): X.append(series[i:ilookback]) y.append(series[ilookbackhorizon-1]) X, y np.array(X).reshape(-1, lookback, 1), np.array(y) split int(len(X) * 0.8) np.save(X_train.npy, X[:split]) np.save(y_train.npy, y[:split]) np.save(X_test.npy, X[split:]) np.save(y_test.npy, y[split:]) print(train:, X[:split].shape, test:, X[split:].shape)这个脚本跑完你就有了统一的数据集。接下来每个模型脚本开头加两行np.load就能用同一份数据。对比的时候记录每个模型的测试集 MSE 和训练时间做成一张表。模型测试 MSE训练时间参数量级适用场景BP/NN待填快小基线对比RNN待填中小短序列LSTM待填慢中长依赖GRU待填中中长依赖、追求速度SVM待填小样本快不适用小样本cnnlstm待填最慢大局部模式明显这张表填完你对自己数据该用哪个模型就有数了。我的血泪经验是不要迷信复杂模型很多时候 GRU 和 SVM 的性价比比 cnnlstm 高得多尤其是在数据量不大、上线时间紧的情况下。从那以后我每次拿到新的时序数据都强制先跑一遍统一对比再决定用哪个模型而不是上来就堆 LSTM。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询