当前位置:   article > 正文

LSTM实战:基于PyTorch的新冠疫情确诊人数预测

LSTM实战:基于PyTorch的新冠疫情确诊人数预测

目录

引言

一、探索数据集

1、导入相关库文件

2、导入每日确诊人数数据集

3、清洗每日确诊人数数据集

4、每日累计确诊的人数及其数据集可视化

5、每日撤消累计后的确诊人数及其数据集可视化

6、查看总共有多少数据量

二、数据预处理

1、训练和测试数据集

2、数据放缩

三、建立模型

1、封装训练模型

2、辅助训练模型

四、训练模型

五、预测模型 

1、局部数据预测

 2、全部数据预测


引言

在 Python 中使用 LSTM 预测新型冠状病毒每日确诊病例。参考原文


一、探索数据集

确诊人数数据网址下载该文件 time_series_covid19_confirmed_global.csv

1、导入相关库文件

  1. import torch # 导入PyTorch库,用于构建和训练深度学习模型
  2. import os # 导入os库,用于与操作系统交互
  3. import numpy as np # 导入NumPy库,用于数值计算
  4. import pandas as pd # 导入Pandas库,用于数据处理和分析
  5. from tqdm import tqdm # 导入tqdm库,用于显示进度条
  6. import seaborn as sns # 导入Seaborn库,用于数据可视化
  7. from pylab import rcParams # 导入rcParams对象,用于设置图形参数
  8. import matplotlib.pyplot as plt # 导入Matplotlib库,用于绘图
  9. from matplotlib import rc # 导入rc对象,用于自定义Matplotlib的默认配置
  10. from sklearn.preprocessing import MinMaxScaler # 导入MinMaxScaler,用于数据标准化
  11. from pandas.plotting import register_matplotlib_converters # 导入register_matplotlib_converters,用于处理时间序列数据
  12. from torch import nn, optim # 导入神经网络和优化器模块
  13. # 设置Matplotlib使用的后端为TkAgg
  14. import matplotlib
  15. matplotlib.use('TkAgg')
  16. # 设置Seaborn的样式和调色板
  17. sns.set(style='whitegrid', palette='muted', font_scale=1.2)
  18. # 自定义颜色调色板
  19. HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
  20. # 设置Seaborn的调色板
  21. sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))
  22. # 设置Matplotlib图形的大小
  23. rcParams['figure.figsize'] = 14, 10
  24. # 注册Matplotlib转换器
  25. register_matplotlib_converters()
  26. # 设置随机种子,以确保结果可复现
  27. RANDOM_SEED = 42
  28. np.random.seed(RANDOM_SEED)
  29. torch.manual_seed(RANDOM_SEED)

2、导入每日确诊人数数据集

读取COVID-19全球累计确诊病例数据集

  1. # 数据集包含省、国家/地区、纬度和经度以及病例数是累积的。
  2. df = pd.read_csv('./data/time_series_covid19_confirmed_global.csv')
  3. print(df.head())

3、清洗每日确诊人数数据集

去除前四列无用数据,保留每日累计确诊病例数据 

  1. # 去掉前四列我们不需要的数据,通过切片直接获取第五列之后的数据
  2. df = df.iloc[:, 4:]
  3. print(df.head())

4、每日累计确诊的人数及其数据集可视化

对每日累计确诊病例进行求和,转换索引为日期时间格式 

  1. # 我们对所有行求和,这样就得到了每日累计案例
  2. daily_cases = df.sum(axis=0)
  3. daily_cases.index = pd.to_datetime(daily_cases.index)
  4. print(daily_cases.head())

  1. plt.plot(daily_cases)
  2. plt.title("Cumulative daily cases")
  3. plt.show()

5、每日撤消累计后的确诊人数及其数据集可视化

计算每日新增确诊病例数

  1. # 我们通过当前值减去前一个值来撤消累加并保留序列的第一个值。
  2. daily_cases = daily_cases.diff().fillna(daily_cases[0]).astype(np.int64)
  3. print(daily_cases.head())

  1. plt.plot(daily_cases)
  2. plt.title("Daily cases")
  3. plt.show()

下图中有一个巨大的峰值主要是由于中国患者检测标准的变化。

6、查看总共有多少数据量

  1. # 查看一下我们拥有的数据量。
  2. print(daily_cases.shape)


二、数据预处理

1、训练和测试数据集

设置训练集和测试集的大小 

  1. # 我们将保留前 889 天用于训练,其余的 254 天用于测试。
  2. test_data_size = 889
  3. train_data = daily_cases[:-test_data_size]
  4. test_data = daily_cases[-test_data_size:]
  5. print(train_data.shape)
  6. print(test_data.shape)

2、数据放缩

对数据进行标准化,将数值缩放到0到1之间

  1. # 为了提高模型的训练速度和性能,我们必须缩放数据(值将在 0 和 1 之间)。
  2. scaler = MinMaxScaler()
  3. scaler = scaler.fit(np.expand_dims(train_data, axis=1))
  4. train_data = scaler.transform(np.expand_dims(train_data, axis=1))
  5. test_data = scaler.transform(np.expand_dims(test_data, axis=1))

定义创建序列的函数 

  1. def create_sequences(data, seq_length):
  2. xs = []
  3. ys = []
  4. for i in range(len(data) - seq_length - 1):
  5. x = data[i:(i + seq_length)]
  6. y = data[i + seq_length]
  7. xs.append(x)
  8. ys.append(y)
  9. return np.array(xs), np.array(ys)
  10. # 设置序列长度
  11. seq_length = 9
  12. # 创建训练集和测试集的序列数据
  13. X_train, y_train = create_sequences(train_data, seq_length)
  14. X_test, y_test = create_sequences(test_data, seq_length)
  15. # 将数据转换为PyTorch张量
  16. X_train = torch.from_numpy(X_train).float()
  17. y_train = torch.from_numpy(y_train).float()
  18. X_test = torch.from_numpy(X_test).float()
  19. y_test = torch.from_numpy(y_test).float()
  20. print(X_train.shape)
  21. print(X_train[:2])
  22. print(y_train.shape)
  23. print(y_train[:2])

每个训练示例包含 9 个历史数据点序列和 1 个标签,该标签表示我们的模型需要预测的真实值。接下来看看我们转换后的数据的样貌。

三、建立模型

1、封装训练模型

定义 COVID-19 预测模型

  1. # 把模型封装到一个自torch.nn.Module的类中
  2. class CoronaVirusPredictor(nn.Module):
  3. def __init__(self, n_features, n_hidden, seq_len, n_layers=2):
  4. super(CoronaVirusPredictor, self).__init__()
  5. self.n_hidden = n_hidden
  6. self.seq_len = seq_len
  7. self.n_layers = n_layers
  8. self.lstm = nn.LSTM(
  9. input_size=n_features, # 输入特征维数:特征向量的长度,如 889
  10. # hidden_size 只是指定从LSTM输出的向量的维度,并不是最后的维度,因为LSTM层之后可能还会接其他层,如全连接层(FC),因此hidden_size对应的维度也就是FC层的输入维度。
  11. hidden_size=n_hidden, # 隐层状态的维数:每个 LSTM 单元或者时间步的输出的 h(t) 的维度,单元内部有权重与偏差计算
  12. # num_layers 为隐藏层的层数,官方的例程里面建议一般设置为1或者2。
  13. num_layers=n_layers, # RNN 层的个数:在竖直方向堆叠的多个相同个数单元的层数
  14. dropout=0.5 # 是否在除最后一个 LSTM 层外的 LSTM 层后面加 dropout 层
  15. )
  16. self.linear = nn.Linear(in_features=n_hidden, out_features=1)
  17. # 重置隐藏状态: 使用无状态 LSTM,需要在每个示例之后重置状态。
  18. def reset_hidden_state(self):
  19. self.hidden = (
  20. torch.zeros(self.n_layers, self.seq_len, self.n_hidden),
  21. torch.zeros(self.n_layers, self.seq_len, self.n_hidden)
  22. )
  23. # 前向传播: 获取序列,一次将所有序列通过 LSTM 层。采用最后一个时间步的输出并将其传递给我们的线性层以获得预测。
  24. def forward(self, sequences):
  25. lstm_out, self.hidden = self.lstm(
  26. sequences.view(len(sequences), self.seq_len, -1),
  27. self.hidden
  28. )
  29. last_time_step = \
  30. lstm_out.view(self.seq_len, len(sequences), self.n_hidden)[-1]
  31. y_pred = self.linear(last_time_step)
  32. return y_pred

2、辅助训练模型

定义训练模型的辅助函数 

  1. # 构建一个用于训练模型的辅助函数
  2. def train_model(
  3. model,
  4. train_data,
  5. train_labels,
  6. test_data=None,
  7. test_labels=None
  8. ):
  9. loss_fn = torch.nn.MSELoss(reduction='sum')
  10. optimiser = torch.optim.Adam(model.parameters(), lr=1e-3)
  11. num_epochs = 100
  12. train_hist = np.zeros(num_epochs)
  13. test_hist = np.zeros(num_epochs)
  14. for t in range(num_epochs):
  15. model.reset_hidden_state()
  16. y_pred = model(X_train)
  17. loss = loss_fn(y_pred.float(), y_train)
  18. if test_data is not None:
  19. with torch.no_grad():
  20. y_test_pred = model(X_test)
  21. test_loss = loss_fn(y_test_pred.float(), y_test)
  22. test_hist[t] = test_loss.item()
  23. if t % 10 == 0:
  24. print(f'Epoch {t} train loss: {loss.item()} test loss: {test_loss.item()}')
  25. elif t % 10 == 0:
  26. print(f'Epoch {t} train loss: {loss.item()}')
  27. train_hist[t] = loss.item()
  28. optimiser.zero_grad()
  29. loss.backward()
  30. optimiser.step()
  31. return model.eval(), train_hist, test_hist

四、训练模型

创建并训练COVID-19预测模型 

  1. model = CoronaVirusPredictor(
  2. n_features=1,
  3. n_hidden=512,
  4. seq_len=seq_length,
  5. n_layers=2
  6. )
  7. model, train_hist, test_hist = train_model(
  8. model,
  9. X_train,
  10. y_train,
  11. X_test,
  12. y_test
  13. )
  14. plt.plot(train_hist, label="Training loss")
  15. plt.plot(test_hist, label="Test loss")
  16. plt.ylim((0, 100))
  17. plt.legend()
  18. plt.show()

查看训练和测试损失过程可视化:

五、预测模型 

1、局部数据预测

将训练数据、测试数据及预测数据绘制在同一张画布上,一起比较下预测结果。 

  1. with torch.no_grad():
  2. test_seq = X_test[:1]
  3. preds = []
  4. for _ in range(len(X_test)):
  5. y_test_pred = model(test_seq)
  6. pred = torch.flatten(y_test_pred).item()
  7. preds.append(pred)
  8. new_seq = test_seq.numpy().flatten()
  9. new_seq = np.append(new_seq, [pred])
  10. new_seq = new_seq[1:]
  11. test_seq = torch.as_tensor(new_seq).view(1, seq_length, 1).float()
  12. true_cases = scaler.inverse_transform(
  13. np.expand_dims(y_test.flatten().numpy(), axis=0)
  14. ).flatten()
  15. predicted_cases = scaler.inverse_transform(
  16. np.expand_dims(preds, axis=0)
  17. ).flatten()
  18. plt.plot(
  19. daily_cases.index[:len(train_data)],
  20. scaler.inverse_transform(train_data).flatten(),
  21. label='Historical Daily Cases')
  22. plt.plot(
  23. daily_cases.index[len(train_data):len(train_data) + len(true_cases)],
  24. true_cases,
  25. label='Real Daily Cases')
  26. plt.plot(
  27. daily_cases.index[len(train_data):len(train_data) + len(true_cases)],
  28. predicted_cases,
  29. label='Predicted Daily Cases')
  30. plt.legend()
  31. plt.show()

正如预期的那样,我们的模型效果表现不佳。 

 2、全部数据预测

使用所有数据来训练相同的模型,预测未来 30 天的确诊病例。

  1. # 现将使用所有可用数据来训练相同的模型。
  2. scaler = MinMaxScaler()
  3. scaler = scaler.fit(np.expand_dims(daily_cases, axis=1))
  4. all_data = scaler.transform(np.expand_dims(daily_cases, axis=1))
  5. print(all_data.shape)
  6. # 预处理和训练步骤相同。
  7. X_all, y_all = create_sequences(all_data, seq_length)
  8. X_all = torch.from_numpy(X_all).float()
  9. y_all = torch.from_numpy(y_all).float()
  10. model = CoronaVirusPredictor(
  11. n_features=1,
  12. n_hidden=512,
  13. seq_len=seq_length,
  14. n_layers=2
  15. )
  16. model, train_hist, _ = train_model(model, X_all, y_all)
  17. # 定义预测天数:使用“完全训练”的模型来预测未来 60 天的确诊病例
  18. DAYS_TO_PREDICT = 60
  19. # 使用训练好的模型进行预测
  20. with torch.no_grad():
  21. test_seq = X_all[:1]
  22. preds = []
  23. for _ in range(DAYS_TO_PREDICT):
  24. y_test_pred = model(test_seq)
  25. pred = torch.flatten(y_test_pred).item()
  26. preds.append(pred)
  27. new_seq = test_seq.numpy().flatten()
  28. new_seq = np.append(new_seq, [pred])
  29. new_seq = new_seq[1:]
  30. test_seq = torch.as_tensor(new_seq).view(1, seq_length, 1).float()
  31. # 将预测结果反向转换为原始数据范围
  32. predicted_cases = scaler.inverse_transform(
  33. np.expand_dims(preds, axis=0)
  34. ).flatten()
  35. # 构建预测日期范围:要使用历史和预测案例创建一个很酷的图表,我们需要扩展数据框的日期索引。
  36. predicted_index = pd.date_range(
  37. start=daily_cases.index[-1],
  38. periods=DAYS_TO_PREDICT + 1,
  39. inclusive="right"
  40. )
  41. # 创建预测结果Series对象
  42. predicted_cases = pd.Series(
  43. data=predicted_cases,
  44. index=predicted_index
  45. )
  46. # 绘制预测结果图表
  47. fig1 = plt.figure('Figure1')
  48. plt.plot(predicted_cases, label='Predicted Daily Cases')
  49. fig2 = plt.figure('Figure2')
  50. plt.plot(daily_cases, label='Historical Daily Cases')
  51. plt.plot(predicted_cases, label='Predicted Daily Cases')
  52. plt.legend()
  53. plt.show()

参与训练的全部数据。

预测未来 30 天确诊病例的数据

将历史和预测的确诊人数在一个图表中显示

模型性能不是很好,但考虑到数据量很少,这是可以预期的。 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/206003
推荐阅读
相关标签
  

闽ICP备14008679号