python:单变量时间序列LSTM预测

目的:使用2009-2021年的月度发病人数,预测2022的月发病人数
数据格式如下所示:

img

问题:对2009年-2021年数据进行LSTM建模,然后在做预测,发现预测效果极差,请问有没有什么模型优化的方法。(或者如下代码有没有那里有问题)
代码如下:

from pandas import read_csv
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
from keras.utils.vis_utils import plot_model
#数据预处理,把Value值转换为float
DA = read_csv("C:\\Users\\Administrator\\Desktop\\123.csv")
data = DA['value'].values.astype(float)
#划分测试集和训练集
test_data_size = 12
train_data = data[:-test_data_size]
test_data = data[-test_data_size:]
#进行数据归一化,消除量纲的影响
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:])
import torch
import torch.nn as nn
train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
#该数据为月度数据,所以把序列长度设为12
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)
#创建LSTM模型
class LSTM(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=200, 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)
epochs = 200

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}')
#做预测
fut_pred = 12
test_inputs = train_data_normalized[-train_window:].tolist()
print(test_inputs)
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:]
#得到预测值
import numpy as np
actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:] ).reshape(-1, 1))
print(actual_predictions)


“Devil组”引证GPT后的撰写:

  • 首先,根据提供的代码,我发现模型名称为LSTM,这与要使用的LSTM层的名称冲突,因此建议将模型名称更改为其他名称以避免这种冲突。
  • 其次,模型在训练过程中只使用了训练数据,并没有使用测试数据进行验证。因此,建议在训练过程中添加一个验证步骤,以便在训练过程中监测模型在测试数据上的表现。
  • 第三,模型训练的时候,学习率设置为0.001,这个学习率对于某些数据集和模型可能不太适合,建议尝试不同的学习率,以找到更好的学习率。
  • 第四,建议将模型的层数和神经元数进行调整,以找到更好的模型结构。如果模型过于简单,则无法捕捉数据中的复杂模式。但是,如果模型过于复杂,则可能会过拟合数据。
  • 第五,尝试使用其他类型的循环神经网络,如GRU和Bidirectional LSTM,以找到更适合数据的模型。
  • 最后,建议在训练之前进行数据可视化分析,以确保数据没有异常值或孤立点,并且确保数据集包含足够的样本,以便模型能够在不同的时间尺度上进行良好的预测。