使用 Conv1D-LSTM 进行时间序列预测:预测多个未来时间步【优化】

news2025/1/19 3:17:00

未优化之前的版本见下,作者当时主要是为Mark这个项目,未进行深入分析。
使用 Conv1D-LSTM 进行时间序列预测:预测多个未来时间步

Introduction

通常有许多时间序列预测方法,例如 ARIMA、SARIMA 和 Holtz-winters,但是随着深度学习的出现,许多人开始使用 LSTM 进行时间序列预测。**那么为什么我们需要使用 Conv1D-LSTM/RNN 进行时间序列预测呢?**下面是我能想到的一些原因:

  • Conv1D 层平滑了输入时间序列,因此我们不必将滚动平均或滚动标准差值添加到输入特征中。
  • LSTM 可以模拟具有多个输入变量的问题。我们需要将 3D 输入向量作为 LSTM 的输入形状。
  • 这为时间序列预测增加了很大的优势,传统的线性方法在适应多元或多输入预测问题时可能很难。 (对于多元预测问题,需要注意的是,当我们使用多元数据进行预测时,我们还需要“未来的多元”输入数据来预测未来结果!……为了缓解这种情况,我们有下面讨论的两种方法。)
  • 灵活性使用多种 seq2seq LSTM 模型组合来预测时间序列 - 多对一模型(在我们想要给出所有先前输入的情况下预测当前时间步长时很有用),多对多模型(在我们希望一次预测多个未来时间步长时很有用)以及这些变体的其他几种组合。

seq2seq LSTM 指的是序列到序列(sequence-to-sequence) LSTM 模型,也称为编码器-解码器(encoder-decoder) LSTM 模型

在本篇文章中,将重点介绍 many-to-many 模型。在这种情况下,我们可以用两种不同的方法来解决问题。

迭代预测或自回归方法: 创建一个包含前几个时间步的滑动窗口,来预测当前时间步的值,然后进行预测。现在,将当前预测值添加回窗口中,以便在下一个时间步进行预测,以此类推。这种方法相对较简单,但会在每个时间步骤上累积误差,而且预测结果不太准确。

直接预测或单次预测: 创建一个包含前几个时间步的滑动窗口,来预测未来的值。在这里,我们使用“K”步预测方法。也就是说,“K”的值,即我们想要预测多少时间步骤的数据,需要提前给出。
在这里插入图片描述
本文的核心思想和数学方程式来自于一篇研究论文。我尝试使用这个直接预测的技术来预测未来 30 天的 the Global active power
Time Series Forecasting Using LSTM Networks: A Symbolic Approach

Okay, lets do some coding!

读取数据

这里的数据需要私信给作者获取。

# Read the data
df = pd.read_csv('./data/household_power_consumption.txt',
                 parse_dates={'dt' : ['Date', 'Time']},
                 sep=";", infer_datetime_format=True,
                 low_memory=False, na_values=['nan','?'], index_col='dt')
# The first five lines of df is shown below
df.head()
# we use "dataset_train_actual" for plotting in the end.
dataset_train_actual = df.copy()
# create "dataset_train for further processing
dataset_train = df.copy()

在这里插入图片描述

这段代码用于读取一个家庭用电量数据集,并将其转化为 Pandas 数据框(DataFrame)格式。

首先,使用 import pandas as pd 导入 Pandas 库。接着,使用 pd.read_csv 函数读取名为 “household_power_consumption.txt” 的 CSV 文件,并将其转化为 Pandas 数据框对象 df。在读取 CSV 文件时,使用 parse_dates 参数将 “Date” 列和 “Time” 列合并为一个名为 “dt” 的日期时间列,并使用 sep=";" 参数指定列分隔符为分号。infer_datetime_format=True 参数告诉 Pandas 尝试自动解析日期时间格式,low_memory=False 参数表示一次性读取所有数据,na_values=['nan','?'] 参数表示将数据中的 “nan” 和 “?” 字符识别为缺失值。最后,使用 index_col='dt' 参数将 “dt” 列设置为数据框的索引。

然后,使用 df.head() 函数打印数据框的前五行,以便查看数据结构和内容。接着,使用 dataset_train_actual = df.copy() 将数据框复制一份,用于后续的可视化。最后,使用 dataset_train = df.copy() 将数据框再次复制一份,用于进一步的数据预处理。

数据处理

现在创建 training_set,它是一个二维的 NumPy 数组。

# Select features (columns) to be involved intro training and predictions
dataset_train = dataset_train.reset_index()
cols = list(dataset_train)[1:8]
# Extract dates (will be used in visualization)
datelist_train = list(dataset_train['dt'])
datelist_train = [date for date in datelist_train]
training_set = dataset_train.values

这段代码用于从数据集中选择用于训练和预测的特征(列),并创建一个二维的 NumPy 数组 training_set,其中包含了选定特征的所有数据。

首先,使用 dataset_train.reset_index() 将数据集的索引重置,以便使用时间步长作为索引。接着,使用 list(dataset_train)[1:8] 选择第 1 到第 7 列的特征(排除了索引和最后一列的标签),并将其作为列表 cols 存储。然后,使用 list(dataset_train['dt']) 提取日期列表,该列表将用于可视化。最后,将日期转换为 Python 的 date 类型,并将其存储在 datelist_train 列表中。

接下来,使用 dataset_train.values 将 Pandas 数据框对象转换为 NumPy 数组,并将其存储在 training_set 中。training_set 数组包含了所有选定特征的数据,每一行代表一个时间步长的数据,每一列代表一种特征。

特征缩放

创建两个缩放器,一个用于输入特征,另一个用于目标值的缩放。需要注意的是,“Global active power”列也包含在输入特征中。

# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
training_set_scaled = sc.fit_transform(training_set)
sc_predict = StandardScaler()
sc_predict.fit_transform(training_set[:, 0:1])

PASS:这里包含一个问题,时间的属性是有问题的。

创建网络训练数据结构

创建训练数据的数据结构:

# Creating a data structure with 72 timestamps and 1 output
X_train = []
y_train = []
n_future = 30 # Number of days we want to predict into the future.
n_past = 72 # Number of past days we want to use to predict future.
for i in range(n_past, len(training_set_scaled) - n_future +1):
    X_train.append(training_set_scaled[i - n_past:i,
                   0:dataset_train.shape[1]])
    y_train.append(training_set_scaled[i+n_future-1:i+n_future, 0])
X_train, y_train = np.array(X_train), np.array(y_train)

print('X_train shape == {}.'.format(X_train.shape))
print('y_train shape == {}.'.format(y_train.shape))

这段代码用于创建训练数据的数据结构,其中历史时间步长的长度为 72,预测期的长度为 30。这段代码将历史时间步长的数据和对应的目标数据组合在一起,并将它们添加到 X_trainy_train 中。

具体来说,对于每个时间步长,代码将使用前 72 个时间步长的数据作为输入特征,以及下一个时间步长的标签作为目标值。然后将所有的输入特征和目标值添加到 X_trainy_train 数组中,以便用于模型的训练。

最后,将 X_trainy_train 转换为 NumPy 数组,并打印它们的形状。其中,X_train 的形状为 (num_samples, n_past, num_features)y_train 的形状为 (num_samples, 1)

需要注意的是,这段代码中的 training_set_scaled 数组是经过缩放的数据集,其形状为 (num_samples, num_features)。在这里,我们将其转换为一个包含历史时间步长和目标值的二维数组,以便用于模型的训练。

如果我们使用 [0:72] 行和所有输入列的输入特征值,则学习到的目标值是数据中 [72+30–1:72+30] 行和一个目标列。因为我们直接预测未来的 30 个值,所以我们的模型是这样学习的:对于每个输入特征块(我们的回溯值为 72),目标值是前 30 个时间步长。

模型训练

以下是用于创建训练模型的代码,其中使用了卷积神经网络、双向 LSTM 和全连接层:

import tensorflow as tf
model = tf.keras.models.Sequential([
        tf.keras.layers.Conv1D(filters=32, kernel_size=3,
                               strides=1, padding="causal",
                               activation="relu",
                               input_shape=[None, 7]),
        
        tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32,                      return_sequences=True)),
        tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32,  return_sequences=False)),
        tf.keras.layers.Dense(1),
        tf.keras.layers.Lambda(lambda x: x * 200)])
# lr_schedule = tf.keras.callbacks.LearningRateScheduler(
# lambda epoch: 1e-8 * 10**(epoch / 20))
optimizer = tf.keras.optimizers.SGD(lr=1e-5, momentum=0.9)
model.compile(loss=tf.keras.losses.Huber(),
optimizer=optimizer,
metrics=["mse"])

在上面的代码中,首先创建了一个序列模型(Sequential),然后将卷积层(Conv1D)、双向 LSTM 层(Bidirectional)、全连接层(Dense)和 Lambda 层(Lambda)依次添加到模型中。

其中,卷积层用于提取时间序列数据的特征,双向 LSTM 层用于处理时序数据,全连接层用于将 LSTM 层的输出映射到预测值,Lambda 层用于对输出进行缩放。

模型的优化器使用 SGD,并将学习率设置为 1e-5,动量设置为 0.9。损失函数使用 Huber 损失函数,评估指标使用均方误差(mse)。

动量(Momentum)是一个改进SGD的方法。
使用动量的原理是,在梯度下降的过程中,当前的更新不仅仅考虑当前的梯度,还考虑过去几个步骤的梯度。
这有两个好处:
1.可以加速收敛
2.可以避免局部极小值

结果展示

PASS: 由于这里有个Bug未解决(上文中也提到),时间戳在特征放缩时不能处理,后期的结果均未实践的,为博客自身的处理结果。(这个实际教程数据处理与博客不一致)

我使用学习率为1e-5,在使用上述使用 lr_schedule(学习率衰减策略)的模型进行训练后,并绘图(学习率对损失的图样),如下图所示。

import matplotlib.pyplot as plt
plt.semilogx(history.history["lr"], history.history["loss"])
plt.axis([1e-8, 1e-4, 0, 30])

在这里插入图片描述

计算和预测未来

Calculating the predictions into future.

# Perform predictions
predictions_future = model.predict(X_train[-n_future:])
# getting predictions for training data for plotting purpose
predictions_train = model.predict(X_train[n_past:])
y_pred_future = sc_predict.inverse_transform(predictions_future)
y_pred_train = sc_predict.inverse_transform(predictions_train)
# Construct two different dataframes for plotting.
PREDICTIONS_FUTURE = pd.DataFrame(y_pred_future, columns=['Global_active_power']).set_index(pd.Series(datelist_future))
PREDICTION_TRAIN = pd.DataFrame(y_pred_train, columns=['Global_active_power']).set_index(pd.Series(datelist_train[2 * n_past + n_future -1:]))

这段代码主要做两件事:

  1. 预测未来n_future个时间点的数据
  2. 为可视化目的,预测训练数据中的一部分

主要步骤是:

  1. 使用model.predict()方法,分别预测未来n_future个数据点和训练数据的一部分
predictions_future = model.predict(X_train[-n_future:])
predictions_train = model.predict(X_train[n_past:])
  1. 将预测值通过之前 fitted 的 scaler 反转变换
y_pred_future = sc_predict.inverse_transform(predictions_future)
y_pred_train = sc_predict.inverse_transform(predictions_train)
  1. 将预测值构造成两个DataFrame,可以用于绘图
PREDICTIONS_FUTURE = pd.DataFrame(y_pred_future, columns=['Global_active_power']).set_index(datelist_future)
PREDICTION_TRAIN = pd.DataFrame(y_pred_train,columns=['Global_active_power']).set_index(datelist_train[2 * n_past + n_future -1:])

可视化预测结果

# Set plot size
plt.rcParams['figure.figsize'] = 14, 5
# Plot parameters
START_DATE_FOR_PLOTTING = '2009-06-07'
# plot the target column in PREDICTIONS_FUTURE dataframe
plt.plot(PREDICTIONS_FUTURE.index, PREDICTIONS_FUTURE['Global_active_power'], color='r', label='Predicted Global Active power')
# plot the target column in PREDICTIONS_TRAIN dataframe
plt.plot(PREDICTION_TRAIN.loc[START_DATE_FOR_PLOTTING:].index, PREDICTION_TRAIN.loc[START_DATE_FOR_PLOTTING['Global_active_power'], color='orange', label='Training predictions')
# plot the target column in input dataframe
plt.plot(dataset_train_actual.loc[START_DATE_FOR_PLOTTING:].index, dataset_train_actual.loc[START_DATE_FOR_PLOTTING:]['Global_active_power'], color='b', label='Actual Global Active power')
plt.axvline(x = min(PREDICTIONS_FUTURE.index), color='green', linewidth=2, linestyle='--')
plt.grid(which='major', color='#cccccc', alpha=0.5)
plt.legend(shadow=True)
plt.title('Predcitions and Acutal Global Active power values', family='Arial', fontsize=12)
plt.xlabel('Timeline', family='Arial', fontsize=10)
plt.ylabel('Stock Price Value', family='Arial', fontsize=10)

上面的代码主要涉及以下变量:

  • dataset_train_actual: 包含实际训练数据(需要预测的目标变量)
  • PREDICTIONS_FUTURE:包含未来 predicting 数据(模型产生的预测值)
  • PREDICTION_TRAIN:包含训练 predicting 数据(模型在训练数据上的预测值)

主要做了以下事情:

  1. 设置绘图大小
  2. 定义一些绘图参数,例如起始日期
  3. 绘制PREDICTIONS_FUTURE中"Global_active_power"列(对应未来预测值)的图形
  4. 绘制 PREDICTION_TRAIN[START_DATE_FOR_PLOTTING:] 中"Global_active_power"列(对应训练数据上的预测值)的图形
  5. 绘制 dataset_train_actual[START_DATE_FOR_PLOTTING:] 中"Global_active_power "列(实际训练数据)的图形
  6. 添加网格线,图例,标题等图形元素

通过绘制这三条线图,可以很直观地比较模型在未来预测和训练期间的表现。

在这里插入图片描述

Reference

使用 Conv1D-LSTM 进行时间序列预测:预测多个未来时间步
Time-series Forecasting using Conv1D-LSTM : Multiple timesteps into future
Individual household electric power consumption Data Set

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/532508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络基础(子网划分)

文章目录 一、网络设备二、IP地址分类A类地址B类地址C类地址特殊IP地址 三、划分子网根据子网掩码判断主机数根据子网和主机判断子网掩码根据IP和子网掩码判断子网数 四、场景运用 一、网络设备 1.集线器(hub):不可以隔离冲突域,…

Redis内存优化——ZSet类型介绍及底层原理详解

系列文章目录 Redis内存优化——String类型介绍及底层原理详解 Redis内存优化——Hash类型介绍及底层原理详解 Redis内存优化——List类型介绍及底层原理详解 Redis内存优化——Set类型介绍及底层原理详解 Redis内存优化——ZSet类型介绍及底层原理详解 文章目录 系列文章目录…

Ingress:k8s集群进出流量的总管

Ingress:k8s集群进出流量的总管 Service 对象,它是 Kubernetes 内置的负载均衡机制,使用静态 IP 地址代理动态变化的 Pod,支持域名访问和服务发现,是微服务架构必需的基础设施。 Service 很有用,但也只能说…

分享一个国内可用的ChatGPT网站,免费无限制,支持AI绘画 - AI 百晓生

背景 ChatGPT作为一种基于人工智能技术的自然语言处理工具,近期的热度直接沸腾🌋。 作为一个AI爱好者,翻遍了各大基于ChatGPT的网站,终于找到一个免费!免登陆!手机电脑通用!国内可直接对话的C…

使用apisix代理静态文件

前言 最近公司考虑用apisix作为公司网关并且部署到k8s上,我这边收到一个小任务:使用apisix代理静态文件 通过apisix官网了解到它构建于 NGINX ngx_lua 的技术基础之上,所以按理应该和nginx代理静态资源是一样的。因为是通过docker容器部署…

STM32-内部温度传感器实验

STM32内部是有温度传感器的,以F1为例,它的温度采集范围是-40度到125度,精度为正负2度,采样通道为ADC1_INI6,上电控制位为TSVREFE位。 温度计算方式为:T(摄氏度) (V25 - Vsense) / Avg_Slope 25&#xff…

数据库管理-第七十六期 如何升级19c RAC(20230516)

数据库管理 2023-05-16 第七十六期 如何升级19c RAC1 回头处理2 升级AHF3 升级GI及DB3.1 拷贝所需文件3.2 升级OPatch3.3 升级GI与DB3.4 应用SQL变更 4 升级OJVM4.1 解压补丁4.2执行补丁冲突检查:4.3 升级OJVM4.4 应用SQL变更 5 最终验证总结 第七十六期 如何升级19…

NC 人力薪酬管理怎么结账?

NC 人力薪酬管理结账流程 1、先在【薪资发放】节点选择相应的薪资方案进行查询操作,然后进行计算操作; 2、计算操作完后,再进行审核操作; 3、如果薪资方案勾选了“发放数据需要审批”属性,则需要在【发放申请】节点…

【NB 2023】从一般蛋白质语言模型中高效进化人类抗体

Efficient evolution of human antibodies from general protein language models 哈佛大学化学与化学生物学系和圣路易斯华盛顿大学的研究人员共同完成的一篇论文,发表在Nature Biotechnology上。 抗体是一种大分子,属于免疫球蛋白家族,它…

springboot 启动后,调用接口时报错404问题汇总(层层推进、超全面)

线上环境 确保项目启动成功 看到这条日志才能判定项目是启动成功的 确保controller类被成功注册到了springboot容器中 首先,按springboot的类扫描规则来说,启动类和被扫描的组件类应该要在同一包下的 验证策略 从springboot容器中尝试去获取到contro…

【Springboot】yaml配置文件多环境切换

关于配置文件的详细说明可以看官方文档: 24. Externalized Configuration 以下是个人学习过程中的笔记,如有错误,请多指教! 目录 (一)配置文件 (二)yaml的概述及基本使用 yaml基本…

TCP与UDP相关知识(详细)

目录 一、UDP 和 TCP 的特点与区别 二、UDP 与TCP 首部格式 三、TCP 的三次握手和四次挥手 四、TCP 短连接和长连接的区别 五、TCP粘包、拆包及解决办法 六、TCP 可靠传输 七、TCP 滑动窗口 八、TCP 流量控制 九、TCP 拥塞控制 十、提供网络利用率 一、UDP 和 TCP 的特…

yolov8 pycharm运行(predict,不用command line)

yolov8就不介绍了,见主页 这里说下用pycharm运行。 代码参考segment页 from ultralytics import YOLO# Load a model model YOLO(yolov8n-seg.pt) # load an official model# Predict with the model results model(test_img.jpg) # predict on an image不通过…

Cube Map 系列之:手把手教你 实现 环境光贴图

什么是环境光贴图 下面先看两个例子: 使用左侧的纹理 渲染茶壶,得到茶壶对真实空间的反射效果 同样使用左侧的纹理,得到中心的球对四周物体的反射效果 所以,环境光贴图指的是通过构建物体周围世界的纹理,使用纹理贴…

25的大学生转行学云计算,能拿到10k+的月薪,是真的吗?

25的大学生转行学云计算,能拿到10k的月薪,是真的吗? 对于IT行业来说,月薪上万并不少见,毕竟互联网常年占据行业薪资排行榜首。作为技术行业,由于其发展的前沿性,引导性,也是作为其他…

26-2 vue-router

原始的方式好多东西需要我们自己去写,vue-router是一个集成好了的路由包,vue-router 官网 Vue Router | Vue.js 的官方路由 并非原始的东西就不好,只要是包就可能存在版本兼容问题,如果是简单的需求就建议用原始的方法 目录 1 …

如何进行远程控制电脑

电脑在我们日常生活中的作用是非常大的,尤其是在信息时代地位非常高。 其中,最常见、最具代表性的功能是实现远程控制功能。它可以直接解决一些问题,而不需要去现场,在一定程度上提高了工作效率。但是有很多朋友不知道如何实现远…

边缘计算盒子有哪些?边缘计算应用场景

边缘计算(Edge Computing)是一种分布式计算模型,旨在将数据处理和计算功能从中心数据中心移到数据源附近的边缘设备上。它的目标是在接近数据生成的地方进行实时数据处理和分析,减少数据传输延迟和网络拥塞,提高应用程…

计算机图形学-GAMES101-2

Vectors向量 一、向量的介绍 表示一个方向。计算向量的方法:AB (B-A)。向量对应的单位向量 AB / ||AB|| 。向量具有平移性,我们不关心它的开始位置。向量求和:三角形法则和平行四边形法则。在代数上计算直接把向量的…

如何防止网站被黑客攻击?黑客是怎样炼成的?

现在的黑客网站可谓是多如牛毛,不管在哪里只要你愿意学,都可以学到一招半式。看过别人的个性签名:卖菜的王大妈是黑客,烤红薯的李大爷也是黑客,对面成人用品店的老板,挖日,还是黑客-_-~!..黑客还真多啊!!!据…