news 2026/10/18 12:16:36

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
时间序列预测七模型实战:LSTM、GRU、CNN+LSTM 对比与避坑指南

简介:这份资源面向希望系统入门时间序列预测的开发者与学习者,围绕同一类预测任务,横向对比BP神经网络、CNN、LSTM、GRU、RNN、SVM以及CNN+LSTM混合模型等多种建模思路,帮助读者理解不同网络结构在时序数据上的适用场景与效果差异。压缩包共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 以及 cnn+lstm 混合结构这七种常见方案,各自配了一份可运行的数据和脚本,放在同一个压缩包里。你不用再东拼西凑找 demo,解压之后每个文件夹就是一个独立的最小可复现单元。适合谁?刚接触时序预测、想快速把各模型跑通对比一遍的开发者;也适合已经用过 LSTM 但没试过 cnn+lstm 混合结构、想看看特征提取层加进去到底有没有提升的熟手。包里数据分两类:一类是上车测试/训练数据(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回归预测
cnn+lstmcnn_lstm.py + data_helper.pymini_data 目录自定义混合结构预测

这张表的核心信息是:数据格式不统一。LSTM 和 SVM 走 xlsx,GRU 走 csv,cnn+lstm 走 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(drop=True)

这段代码的作用是“先侦察再动手”。参数说明: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 做时序预测的思路是把历史若干步拼成特征向量,然后当回归问题解。它的优势是小样本下不容易过拟合,劣势是窗口一大特征维度爆炸,训练时间直线上升。

cnn+lstm 这套是包里结构最完整的: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, lookback=24, horizon=1): """ series: 一维归一化后的序列 lookback: 回看步数 horizon: 预测未来第几步 返回: X shape (样本数, lookback, 1), y shape (样本数,) """ X, y = [], [] for i in range(len(series) - lookback - horizon + 1): X.append(series[i:i+lookback]) y.append(series[i+lookback+horizon-1]) X = np.array(X).reshape(-1, lookback, 1) y = np.array(y) return X, y

逻辑说明:循环从 0 到len(series)-lookback-horizon+1,每次取 lookback 长度的窗口作为输入,取窗口后第 horizon 个点作为标签。reshape(-1, lookback, 1)是为了适配 LSTM 的输入格式(batch, timesteps, features)。参数怎么改:horizon=1 是单步预测,改成 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_sequences=True, input_shape=(lookback, 1)), Dropout(0.2), LSTM(32, return_sequences=False), Dropout(0.2), Dense(1) ]) model.compile(optimizer=Adam(learning_rate=0.001), loss='mse') history = model.fit(X_train, y_train, epochs=100, batch_size=32, validation_split=0.1, verbose=1)

参数说明:第一层 LSTM 的return_sequences=True是为了把序列传给第二层 LSTM,如果只有一层 LSTM,这行可以去掉。Dropout(0.2)是防过拟合的,数据量小的时候可以加到 0.3。learning_rate=0.001是 Adam 的常用起点,如果 loss 下降太慢可以调到 0.005,如果震荡就降到 0.0005。batch_size=32不是固定的,样本少就设 16 甚至 8。validation_split=0.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(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(X_train, y_train, epochs=200, batch_size=32, validation_split=0.1, callbacks=[early_stop], verbose=1)

patience=10的意思是验证 loss 连续 10 个 epoch 没改善就停,restore_best_weights=True会恢复到验证 loss 最低那个 epoch 的权重。这个回调能帮你省掉手动调 epoch 数的麻烦,也是避免过拟合的后悔药。注意monitor默认是val_loss,如果你自己切了验证集,要改成对应的 key。

4. cnn+lstm 混合结构:CNN 提特征、LSTM 学依赖,怎么接才不翻车

4.1 混合结构的连接方式与维度对齐

cnn+lstm 的核心思路是:先用一维卷积在时间轴上滑动,提取局部模式(比如连续几天的突增突降),再把卷积输出的特征序列喂给 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(filters=32, kernel_size=3, activation='relu', input_shape=(lookback, 1)), MaxPooling1D(pool_size=2), Conv1D(filters=64, kernel_size=3, activation='relu'), LSTM(50, return_sequences=False), Dense(1) ]) model.compile(optimizer='adam', loss='mse') model.summary()

逻辑说明:第一层 Conv1D 的input_shape=(lookback, 1),1 是特征维度,单变量时序就是 1。kernel_size=3表示每次看 3 个连续时间步。MaxPooling1D(pool_size=2)把时间步减半,减少计算量。第二层 Conv1D 的 filters 加到 64,提取更丰富的特征。最后 LSTM 的return_sequences=False,只取最后一个时间步的输出,接 Dense 出预测值。

参数怎么调:如果model.summary()报维度错误,先看 MaxPooling 之后的时间步是多少,再确认 LSTM 能不能接上。常见做法是池化之后时间步还太长,可以再加一层池化,或者把 LSTM 的input_shape改成(None, filters)让它自动适配。data_helper.py里的mini_build相关逻辑就是干这个的——把原始数据切成适合卷积和循环层的形状。

4.2 数据管道对接:把自有数据塞进 mini_data

mini_data目录和data_helper.py是配套的。你要用自己的数据跑 cnn+lstm,最稳妥的方式是照着mini_data里的格式准备一份,然后改data_helper.py里的读取路径。

# data_helper.py 里常见的读取和窗口构造逻辑 import pandas as pd import numpy as np def load_mini_data(path, lookback=24, horizon=1): 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:i+lookback]) y.append(series[i+lookback+horizon-1]) return np.array(X).reshape(-1, lookback, 1), np.array(y)

这段代码和前面 LSTM 的窗口构造逻辑一致,区别在于它从 csv 读数据,并且假设了列的位置。如果你的数据列顺序不同,改df.iloc[:, 1]里的索引。1e-8是防止除以零。注意归一化用的是全局最大最小值,实际项目中应该只用训练集的最大最小值,这里为了简化没做区分,你自己改的时候要补上。

4.3 训练与验证:混合结构到底有没有提升

跑完 cnn+lstm 之后,和纯 LSTM 的结果对比一下。对比的时候不能只看一个随机划分的测试集,因为时序数据波动大,单次划分的结果可能只是运气。我的做法是:用同样的 lookback 和 horizon,分别跑 LSTM 和 cnn+lstm,各跑 3 次取平均 MSE。如果 cnn+lstm 的平均 MSE 比 LSTM 低 10% 以上,那这个提升大概率是真实的;如果只低 2% 到 3%,可能是随机波动,不值得增加复杂度。

另外要注意,cnn+lstm 的参数量通常比纯 LSTM 大,训练时间也更长。如果数据量很小(比如只有几百个点),CNN 层可能学不到有意义的局部模式,反而更容易过拟合。这种情况下纯 GRU 或 SVM 可能是更务实的选择。

5. 避坑与排查:七套脚本跑下来最容易翻车的五个地方

5.1 现象:loss 是 nan,训练一开始就崩

原因:学习率太大,或者数据里有 nan/无穷大值,或者归一化的时候除以了零。时序数据里经常有缺失值,pandas 读进来是 NaN,直接送进模型就会导致 loss 变 nan。

解决:训练前先做df.isnull().sum()检查缺失值,用df.fillna(method='ffill')前向填充或者插值补上。归一化时分母加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 现象:cnn+lstm 报维度不匹配,改了半天改不对

原因: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:i+lookback]) y.append(series[i+lookback+horizon-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待填小样本快不适用小样本
cnn+lstm待填最慢大局部模式明显

这张表填完,你对自己数据该用哪个模型就有数了。我的血泪经验是:不要迷信复杂模型,很多时候 GRU 和 SVM 的性价比比 cnn+lstm 高得多,尤其是在数据量不大、上线时间紧的情况下。从那以后我每次拿到新的时序数据,都强制先跑一遍统一对比,再决定用哪个模型,而不是上来就堆 LSTM。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 12:08:27

Daz资产接入UE第三人称模板:骨骼绑定、动画重定向与物理参数全解析

简介:面向虚幻引擎4开发者,这套以Daz3d资产为基础的第三人称模板工程示例,主要目标是让Genesis 8系列等角色在引擎内的导入、绑定与第三人称控制流程拥有可复用样板,适用于角色动画、游戏原型和数字人相关实验项目。工程内含Genes…

作者头像 李华
网站建设 2026/10/18 12:07:50

基于CNN的蔬菜识别系统:从数据集到模型部署全流程

看到这个题目,我第一反应是:这是毕业设计里一个非常经典,但又特别能出彩的选题。蔬菜识别,本质上是图像分类问题,踩中“深度学习”“CNN卷积网络”这两个核心技术栈,既有足够的技术深度可以写,又…

作者头像 李华
网站建设 2026/10/18 12:07:02

初学者AI生存地图:免费免登录工具+三步指令法

1. 这份收藏集不是“资料包”,而是一张初学者的生存地图“初学者终极生成式 AI 收藏集(一)”——看到这个标题,你脑子里浮现的可能是几十个链接、上百个工具名、一堆带“AI”后缀的网站截图,甚至还有人会下意识点开收藏…

作者头像 李华
网站建设 2026/10/18 12:06:57

ATVOSS架构:编译与硬件算力之间的标准化桥梁

做性能优化做了十几年,我越来越觉得有一个问题被低估了:大家聊编译器的时候默认它足够聪明,聊硬件的时候默认它足够快,但真正把两者放到同一个项目里对齐,情况往往非常拧巴。我们内部代号叫 ATVOSS 的这套架构&#xf…

作者头像 李华
网站建设 2026/10/18 12:05:59

浮点数精度之惑:从IEEE 754数字示例到手算验证与实战排查

1. 为什么单独抠一节课看数字示例1.1 浮点数其实是“近似招数”很多人第一次学编程,看到float、double这些类型,第一反应是“带小数的数嘛”,然后用起来也顺手,直到某天发现0.1 0.2算出来不是0.3,才意识到这个类型其实…

作者头像 李华
网站建设 2026/10/18 12:04:39

LLM应用工程师实战指南:从RAG到Agent的完整工程化路径

很多人第一次接触"LLM应用工程师"这个岗位,脑子里冒出来的画面是:把大模型的API接到项目里,写两段prompt,一个能聊天的机器人就上线了。真等自己动手做第一个要交付给客户使用的应用时,才会发现调接口只是最…

作者头像 李华