PyTorch+LSTM实现单变量时间序列预测

1. 前言

时间序列预测是机器学习领域中的经典问题之一,如何正确的应用深度学习模型来预测时间序列是本文的主要研究内容。本文将使用PyTorch框架和LSTM模型,通过单一变量预测,来对时间序列进行预测。

2. 数据准备

首先我们需要准备数据集,本文使用的是气温时间序列数据集,该数据集包括从1981年到1990年在加州平均每日的最高温度。可以从下面的链接中下载:

https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv

2.1 导入数据

使用pandas框架可以很方便的将csv文件导入,代码如下:

import pandas as pd

# 导入csv文件

df = pd.read_csv('daily-min-temperatures.csv')

2.2 观察数据

接下来我们可以通过head()函数来观察前几行的数据,代码如下:

print(df.head())

输出结果如下:

         Date  Temp

0 1981-01-01 20.7

1 1981-01-02 17.9

2 1981-01-03 18.8

3 1981-01-04 14.6

4 1981-01-05 15.8

从输出结果中我们可以看到,该数据集一共有两列,第一列是日期,第二列是气温。

2.3 作图观察

为了更好的理解数据,我们可以使用matplotlib和seaborn库作图来观察温度随时间的变化情况。

import matplotlib.pyplot as plt

import seaborn as sns

sns.lineplot(x='Date', y='Temp', data=df)

plt.show()

运行结果如下:

观察图形可以看出,气温呈现出明显的季节性规律,且随时间上升,温度也上升。

2.4 数据预处理

预处理的内容包括数据归一化、数据划分等处理。

2.4.1 数据归一化

在进行时间序列预测时,通常需要对数据进行归一化处理,以确保模型更好的收敛并提高预测精度。我们可以使用MinMaxScaler对数据集中的温度进行归一化。

from sklearn.preprocessing import MinMaxScaler

# 对数据进行归一化

scaler = MinMaxScaler(feature_range=(0, 1))

df['Temp'] = scaler.fit_transform(df[['Temp']])

2.4.2 数据划分

我们将数据分为训练集和测试集。设定训练集占用80%,测试集占用20%。

# 划分数据集

train_size = int(len(df) * 0.8)

train_data, test_data = df.iloc[:train_size, :], df.iloc[train_size:, :]

3. LSTM模型构建

LSTM(长短期记忆网络)是用于时间序列预测的一种广泛使用的递归神经网络架构。本文将使用PyTorch框架来构建LSTM模型。

3.1 导入库

我们需要先导入PyTorch、numpy和matplotlib库。

import torch

import torch.nn as nn

import numpy as np

import matplotlib.pyplot as plt

3.2 设定超参数

我们需要设定一些超参数,如时间步长、LSTM隐藏单元数等,以定义LSTM模型的形状和特征。

# 设置超参数

time_steps = 20

hidden_size = 128

n_features = 1

batch_size = 32

learning_rate = 0.01

epochs = 100

其中,time_steps是指每个输入的序列长度,hidden_size指LSTM层的隐藏状态维度,n_features是指特征数,batch_size是指随机梯度下降时每批次的样本数,learning_rate是学习率,epochs是迭代训练次数。

3.3 定义LSTM模型

接下来,我们可以定义LSTM模型。

class LSTM(nn.Module):

def __init__(self, n_features, hidden_size, time_steps):

super().__init__()

self.n_features = n_features

self.hidden_size = hidden_size

self.time_steps = time_steps

self.lstm = nn.LSTM(input_size=n_features, hidden_size=hidden_size, batch_first=True)

self.fc = nn.Linear(hidden_size, 1)

def forward(self, x):

h0 = torch.zeros(1, x.size(0), self.hidden_size).to(device)

c0 = torch.zeros(1, x.size(0), self.hidden_size).to(device)

out, (hn, cn) = self.lstm(x, (h0, c0))

out = self.fc(out[:, -1, :])

return out

我们使用了nn.LSTM和nn.Linear函数来分别定义LSTM层和全连接层。我们的模型结构为:LSTM层 -> 全连接层。

4. 训练模型

在训练模型之前,我们需要将数据转为适合LSTM模型的格式。

4.1 创建用于LSTM训练的数据集

我们需要将训练数据集转为LSTM模型可用的数据形式。将时间序列数据转变为LSTM模型训练所需的数据形式时,我们需要设置一个数据窗,比如我们可以假设在观测到第t天时,温度与前time_steps天的温度相关。基于此,我们可以将数据集转换为3D数组的形式,其中每个子数组的形状为:(batch_size, time_steps, n_features)。

def get_batch(data, time_steps, batch_size):

x_batch, y_batch = [], []

for i in range(len(data) - time_steps - 1):

x = data[i:(i + time_steps), 0]

y = data[(i + 1):(i + time_steps + 1), 0]

x_batch.append(x)

y_batch.append(y)

return np.array(x_batch), np.array(y_batch)

# 创建训练集和测试集的数据窗

x_train, y_train = get_batch(train_data.values, time_steps, batch_size)

x_test, y_test = get_batch(test_data.values, time_steps, batch_size)

# 将数据转为Torch张量

x_train = torch.from_numpy(x_train).float().to(device)

y_train = torch.from_numpy(y_train).float().to(device)

x_test = torch.from_numpy(x_test).float().to(device)

y_test = torch.from_numpy(y_test).float().to(device)

在上述代码中,get_batch函数将原始数据集转换为LSTM模型可用的数据窗形式。在每次迭代时,它每次移动一步,在1个数据窗中包含tim_steps个连续的数据点,其中第i个数据点与接下来的第i+1个要进行预测。

4.2 训练模型

定义LSTM模型后,我们需要定义优化器和损失函数,以便训练LSTM模型,并对其进行训练。

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

model = LSTM(n_features, hidden_size, time_steps).to(device)

criterion = nn.MSELoss(reduction='mean')

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# 模型训练

train_loss = []

test_loss = []

for epoch in range(epochs):

# 训练集

outputs = model(x_train)

optimizer.zero_grad()

loss = criterion(outputs, y_train)

loss.backward()

optimizer.step()

train_loss.append(loss.item())

# 测试集

test_predict = model(x_test)

loss = criterion(test_predict, y_test)

test_loss.append(loss.item())

if (epoch + 1) % 10 == 0:

print('采用RMSPROP作为优化器,Epoch [{}/{}], 训练损失: {:.4f}, 验证损失: {:.4f}'.format(epoch + 1, epochs, train_loss[-1], test_loss[-1]))

运行上述代码,训练出的结果如下:

5. 预测结果可视化

训练完毕后,我们可以使用模型来预测在测试集上的温度,并将预测结果可视化。

# 测试集上的预测

model.eval()

inputs = x_test

predict = model(inputs).cpu().detach().numpy()

# 将预测结果展开

predict = scaler.inverse_transform(predict)

y_test = scaler.inverse_transform(y_test.cpu().detach().numpy())

# 可视化结果

plt.plot(y_test, label='True Data')

plt.plot(predict, label='Predicted Data')

plt.legend()

plt.show()

运行上述代码,预测结果可视化如下:

6. 结论

通过本文,我们可以了解在PyTorch框架下如何使用LSTM模型对单变量时间序列数据集进行预测。我们通过对加州每日平均温度时间序列数据进行预处理和模型训练,成功地实现了温度时间序列的预测。

后端开发标签