当前位置: 首页 > news >正文

lstm时间序列预测_pytorch入门使用PyTorch进行LSTM时间序列预测

想了解更多好玩的人工智能应用,请关注公众号“机器AI学习 数据AI挖掘”,”智能应用"菜单中包括:颜值检测、植物花卉识别、文字识别、人脸美妆等有趣的智能应用。。

315881860dc5aa4bb7351b6f4762a7eb.png

本节将介绍另一种常用的门控循环神经网络:长短期记忆(long short-term memory,LSTM)。它 比门控循环单元的结构稍微复杂一点。

1.1、数据集和问题定义

import torch
import torch.nn as nn

import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

让我们打印Seaborn库内置的所有数据集的列表:

['anscombe',
'attention',
'brain_networks',
'car_crashes',
'diamonds',
'dots',
'exercise',
'flights',
'fmri',
'gammas',
'iris',
'mpg',
'planets',
'tips',
'titanic']

让我们将数据集加载到我们的应用程序中

flight_data = sns.load_dataset("flights")
flight_data.head()

该数据集有三列:year,month,和passengers。该passengers列包含指定月份旅行旅客的总数。让我们绘制数据集的形状:

flight_data.shape
(144, 3)

可以看到数据集中有144行和3列,这意味着数据集包含12年的乘客旅行记录。

任务是根据前132个月来预测最近12个月内旅行的乘客人数。请记住,我们有144个月的记录,这意味着前132个月的数据将用于训练我们的LSTM模型,而模型性能将使用最近12个月的值进行评估。

让我们绘制每月乘客的出行频率。

接下来的脚本绘制了每月乘客人数的频率:

fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 15
fig_size[1] = 5
plt.rcParams["figure.figsize"] = fig_size
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.xlabel('Months')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(flight_data['passengers'])
[<matplotlib.lines.Line2D at 0x1b409470>]

输出显示,多年来,乘飞机旅行的平均乘客人数有所增加。一年内旅行的乘客数量波动,这是有道理的,因为在暑假或寒假期间,旅行的乘客数量与一年中的其他部分相比有所增加。

1.2、数据预处理

数据集中的列类型为object,如以下代码所示:

flight_data.columns
Index(['year', 'month', 'passengers'], dtype='object')

第一步是将passengers列的类型更改为float。

all_data = flight_data['passengers'].values.astype(float)
print(all_data)
[112. 118. 132. 129. 121. 135. 148. 148. 136. 119. 104. 118. 115. 126.
141. 135. 125. 149. 170. 170. 158. 133. 114. 140. 145. 150. 178. 163.
172. 178. 199. 199. 184. 162. 146. 166. 171. 180. 193. 181. 183. 218.
230. 242. 209. 191. 172. 194. 196. 196. 236. 235. 229. 243. 264. 272.
237. 211. 180. 201. 204. 188. 235. 227. 234. 264. 302. 293. 259. 229.
203. 229. 242. 233. 267. 269. 270. 315. 364. 347. 312. 274. 237. 278.
284. 277. 317. 313. 318. 374. 413. 405. 355. 306. 271. 306. 315. 301.
356. 348. 355. 422. 465. 467. 404. 347. 305. 336. 340. 318. 362. 348.
363. 435. 491. 505. 404. 359. 310. 337. 360. 342. 406. 396. 420. 472.
548. 559. 463. 407. 362. 405. 417. 391. 419. 461. 472. 535. 622. 606.
508. 461. 390. 432.]

接下来,我们将数据集分为训练集和测试集。LSTM算法将在训练集上进行训练。然后将使用该模型对测试集进行预测。将预测结果与测试集中的实际值进行比较,以评估训练后模型的性能。

前132条记录将用于训练模型,后12条记录将用作测试集。以下脚本将数据分为训练集和测试集。

test_data_size = 12

train_data = all_data[:-test_data_size]
test_data = all_data[-test_data_size:]
print(test_data)
[417. 391. 419. 461. 472. 535. 622. 606. 508. 461. 390. 432.]

我们的数据集目前尚未规范化。最初几年的乘客总数远少于后来几年的乘客总数。标准化数据以进行时间序列预测非常重要。以在一定范围内的最小值和最大值之间对数据进行规范化。我们将使用模块中的MinMaxScaler类sklearn.preprocessing来扩展数据。

以下代码 分别将最大值和最小值分别为-1和1归一化。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(-1, 1))
train_data_normalized = scaler.fit_transform(train_data .reshape(-1, 1))
print(train_data_normalized[:5])
print(train_data_normalized[-5:])
[[-0.96483516]
[-0.93846154]
[-0.87692308]
[-0.89010989]
[-0.92527473]]
[[1. ]
[0.57802198]
[0.33186813]
[0.13406593]
[0.32307692]]

您可以看到数据集值现在在-1和1之间。

在此重要的是要提到数据标准化仅应用于训练数据,而不应用于测试数据。如果对测试数据进行归一化处理,则某些信息可能会从训练集中 到测试集中。

下一步是将我们的数据集转换为张量,因为PyTorch模型是使用张量训练的。要将数据集转换为张量,我们可以简单地将数据集传递给FloatTensor对象的构造函数,如下所示

train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)

最后的预处理步骤是将我们的训练数据转换为序列和相应的标签。

您可以使用任何序列长度,这取决于领域知识。但是,在我们的数据集中,使用12的序列长度很方便,因为我们有月度数据,一年中有12个月。如果我们有每日数据,则更好的序列长度应该是365,即一年中的天数。因此,我们将训练的输入序列长度设置为12。

接下来,我们将定义一个名为的函数create_inout_sequences。该函数将接受原始输入数据,并将返回一个元组列表。在每个元组中,第一个元素将包含与12个月内旅行的乘客数量相对应的12个项目的列表,第二个元组元素将包含一个项目,即在12 + 1个月内的乘客数量。

train_window = 12
def create_inout_sequences(input_data, tw):
inout_seq = []
L = len(input_data)
for i in range(L-tw):
train_seq = input_data[i:i+tw]
train_label = input_data[i+tw:i+tw+1]
inout_seq.append((train_seq ,train_label))
return inout_seq

执行以下脚本以创建序列和相应的标签进行训练:

train_inout_seq = create_inout_sequences(train_data_normalized, train_window)

如果打印train_inout_seq列表的长度,您将看到它包含120个项目。这是因为尽管训练集包含132个元素,但是序列长度为12,这意味着第一个序列由前12个项目组成,第13个项目是第一个序列的标签。同样,第二个序列从第二个项目开始,到第13个项目结束,而第14个项目是第二个序列的标签,依此类推。

现在让我们输出train_inout_seq列表的前5个项目:

train_inout_seq[:5]
[(tensor([-0.9648, -0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066,
-0.8593, -0.9341, -1.0000, -0.9385]), tensor([-0.9516])),
(tensor([-0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593,
-0.9341, -1.0000, -0.9385, -0.9516]),
tensor([-0.9033])),
(tensor([-0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341,
-1.0000, -0.9385, -0.9516, -0.9033]), tensor([-0.8374])),
(tensor([-0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000,
-0.9385, -0.9516, -0.9033, -0.8374]), tensor([-0.8637])),
(tensor([-0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000, -0.9385,
-0.9516, -0.9033, -0.8374, -0.8637]), tensor([-0.9077]))]

您会看到每个项目都是一个元组,其中第一个元素由序列的12个项目组成,第二个元组元素包含相应的标签。

1.3、创建LSTM模型

让我总结一下以上代码中发生的事情。LSTM该类的构造函数接受三个参数:

input_size:对应于输入中的要素数量。尽管我们的序列长度为12,但每个月我们只有1个值,即乘客总数,因此输入大小为1。hidden_layer_size:指定隐藏层的数量以及每层中神经元的数量。我们将有一层100个神经元。output_size:输出中的项目数,由于我们要预测未来1个月的乘客人数,因此输出大小为1。接下来,在构造函数中,我们创建变量hidden_layer_size,lstm,linear,和hidden_cell。LSTM算法接受三个输入:先前的隐藏状态,先前的单元状态和当前输入。该hidden_cell变量包含先前的隐藏状态和单元状态。的lstm和linear层变量用于创建LSTM和线性层。

在forward方法内部,将input_seq作为参数传递,该参数首先传递给lstm图层。lstm层的输出是当前时间步的隐藏状态和单元状态,以及输出。lstm图层的输出将传递到该linear图层。预计的乘客人数存储在predictions列表的最后一项中,并返回到调用函数。

下一步是创建LSTM()类的对象,定义损失函数和优化器。由于我们正在解决分类问题,

让我们输出模型:

class LSTM(nn.Module):
def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
super().__init__()
self.hidden_layer_size = hidden_layer_size

self.lstm = nn.LSTM(input_size, hidden_layer_size)

self.linear = nn.Linear(hidden_layer_size, output_size)

self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
torch.zeros(1,1,self.hidden_layer_size))

def forward(self, input_seq):
lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
predictions = self.linear(lstm_out.view(len(input_seq), -1))
return predictions[-1]
model = LSTM()
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
print(model)
LSTM(
(lstm): LSTM(1, 100)
(linear): Linear(in_features=100, out_features=1, bias=True)
)

1.4、训练模型

epochs = 150

for i in range(epochs):
for seq, labels in train_inout_seq:
optimizer.zero_grad()
model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))

y_pred = model(seq)

single_loss = loss_function(y_pred, labels)
single_loss.backward()
optimizer.step()

if i%25 == 1:
print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')

print(f'epoch: {i:3} loss: {single_loss.item():10.10f}')
epoch: 1 loss: 0.01599291
epoch: 26 loss: 0.00388177
epoch: 51 loss: 0.00561049
epoch: 76 loss: 0.00011478
epoch: 101 loss: 0.00737344
epoch: 126 loss: 0.01063965
epoch: 149 loss: 0.0034309230

1.5、做出预测

现在我们的模型已经训练完毕,我们可以开始进行预测了。

fut_pred = 12

test_inputs = train_data_normalized[-train_window:].tolist()
print(test_inputs)
[0.12527473270893097, 0.04615384712815285, 0.3274725377559662, 0.2835164964199066, 0.3890109956264496, 0.6175824403762817, 0.9516483545303345, 1.0, 0.5780220031738281, 0.33186814188957214, 0.13406594097614288, 0.32307693362236023]

您可以将上述值与train_data_normalized数据列表的最后12个值进行比较。

该test_inputs项目将包含12个项目。在for循环内,这12个项目将用于对测试集中的第一个项目进行预测,即项目编号133。然后将预测值附加到test_inputs列表中。在第二次迭代中,最后12个项目将再次用作输入,并将进行新的预测,然后将其test_inputs再次添加到列表中。for由于测试集中有12个元素,因此该循环将执行12次。在循环末尾,test_inputs列表将包含24个项目。最后12个项目将是测试集的预测值。

以下脚本用于进行预测:

如果输出test_inputs列表的长度,您将看到它包含24个项目。可以按以下方式打印最后12个预测项目:

model.eval()

for i in range(fut_pred):
seq = torch.FloatTensor(test_inputs[-train_window:])
with torch.no_grad():
model.hidden = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))
test_inputs.append(model(seq).item())
test_inputs[fut_pred:]
[1.1925697326660156,
1.5521266460418701,
1.7060068845748901,
1.760893702507019,
1.7794983386993408,
1.7928276062011719,
1.8045395612716675,
1.8172146081924438,
1.8299273252487183,
1.8416459560394287,
1.8509267568588257,
1.8585551977157593]

由于我们对训练数据集进行了标准化,因此预测值也进行了标准化。我们需要将归一化的预测值转换为实际的预测值。

actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))
print(actual_predictions)
[[602.80961418]
[684.60881197]
[719.61656624]
[732.10331732]
[736.33587205]
[739.36828041]
[742.03275019]
[744.91632336]
[747.80846649]
[750.474455 ]
[752.58583719]
[754.32130748]]

现在让我们针对实际值绘制预测值。看下面的代码:

x = np.arange(132, 144, 1)
print(x)
[132 133 134 135 136 137 138 139 140 141 142 143]

在上面的脚本中,我们创建一个列表,其中包含最近12个月的数值。第一个月的索引值为0,因此最后一个月的索引值为143。

在下面的脚本中,我们将绘制144个月的乘客总数以及最近12个月的预计乘客数量。

plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data['passengers'])
plt.plot(x,actual_predictions)
plt.show()

我们的LSTM所做的预测用橙色线表示。您可以看到我们的算法不太准确,但是它仍然能够捕获最近12个月内旅行的乘客总数的上升趋势以及偶尔的波动。您可以尝试在LSTM层中使用更多的时期和更多的神经元,以查看是否可以获得更好的性能。

为了更好地查看输出,我们可以绘制最近12个月的实际和预测乘客数量,如下所示:

plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)

plt.plot(flight_data['passengers'][-train_window:])
plt.plot(x,actual_predictions)
plt.show()

相关文章:

  • CSDN软件英雄会流水帐
  • jvm内存结构_你真的懂JVM内存结构吗?—深入理解JVM之内存结构
  • 技术大会英雄谱
  • python自动化和java自动化_Python和Java哪个更适合做自动化测试
  • java 创建目录_编程排行榜第一Java语言学习的第一个Java程序,小白快到碗里来...
  • 微软(北京).NET俱乐部第十四次技术沙龙-Visual Studio 2005 Team System企业级开发实训...
  • Visual Basic.net还是C# ——如何选择.net语言
  • c语言解三元一次方程组_人教版初中数学七年级下册三元一次方程组的解法2公开课优质课课件教案视频...
  • 华章公司近期重点产品介绍
  • illegalstateexception是什么异常_Java面试题Iterator怎么使用?有什么特点?
  • 部门预算进行时
  • altium 去掉部分铺铜_【干货】一文读懂铜再生分类与工艺
  • Symbian OS编码诀窍之编码诀窍
  • python set函数是什么意思_python中set是什么意思
  • 博客时代
  • [PHP内核探索]PHP中的哈希表
  • JavaScript-如何实现克隆(clone)函数
  • $translatePartialLoader加载失败及解决方式
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • angular2 简述
  • cookie和session
  • JavaScript设计模式之工厂模式
  • MySQL用户中的%到底包不包括localhost?
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • npx命令介绍
  • spring-boot List转Page
  • SQLServer之索引简介
  • Theano - 导数
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 翻译--Thinking in React
  • 解析 Webpack中import、require、按需加载的执行过程
  • k8s使用glusterfs实现动态持久化存储
  • PostgreSQL之连接数修改
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​LeetCode解法汇总518. 零钱兑换 II
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #数学建模# 线性规划问题的Matlab求解
  • (2)(2.10) LTM telemetry
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (4)logging(日志模块)
  • (附源码)ssm码农论坛 毕业设计 231126
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)Java算法:二分查找
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .gitattributes 文件
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .pyc文件是什么?
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • ??javascript里的变量问题
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • [ solr入门 ] - 利用solrJ进行检索
  • []我的函数库