基于WIN10的64位系统演示

一、写在前面

我们来继续这篇文章:

《BMC Public Health》杂志的2022年一篇题目为《ARIMA and ARIMA-ERNN models for prediction of pertussis incidence in mainland China from 2004 to 2021》文章的模拟数据做案例。

这文章做的是用:使用单纯ARIMA模型和ARIMA-ERNN组合模型预测中国大陆百日咳发病率。

第100+10步 ChatGPT文献复现:ARIMA-ERNN预测百日咳插图

文章是用单纯的ARIMA模型作为对照,更新了ARIMA-ERNN模型。本期,我们试一试ARIMA-ERNN组合模型能否展示出更优秀的性能。

数据不是原始数据哈,是我使用GPT-4根据文章的散点图提取出来近似数据,只弄到了2004-2017年的。

二、闲聊和复现:

1ARIMA-ERNN组合模型的构建策略

又涉及到组合模型的构建。不过这个策略跟上一期提到的ARIMA-NARNN组合模型所使用的的建模策略不一样,来看看GPT-4的总结:

第100+10步 ChatGPT文献复现:ARIMA-ERNN预测百日咳插图(1)

不懂大家看懂了没,反正我是有个疑问:

“所以是一个ARIMA的预测值作为输入,然后对应一个实际值作为输出,训练ERNN模型”

GPT-4肯定了我的回答:

第100+10步 ChatGPT文献复现:ARIMA-ERNN预测百日咳插图(2)

是直接用n个ARIMA的预测值作为输入,实际值作为输出,去构建神经网络,有点像ARIMA-GRNN的策略。

所以说,组合模型,玩的就是花。

(2)组合模型构建

那就帮用pytorch写一个代码呗:

import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error

# Load data
data_path = 'ERNN.csv'
data = pd.read_csv(data_path, parse_dates=True, index_col=0)

# Ensure column accuracy (second column is actual values, third column is ARIMA predictions)
actuals = data.iloc[:, 0]
predictions = data.iloc[:, 1]

# Use 36 consecutive ARIMA prediction values as input
n = 36
inputs = [predictions.shift(-i) for i in range(n)]
inputs = pd.concat(inputs, axis=1)[:-n]  # Remove the last n rows as they are incomplete
targets = actuals[n:]  # Remove the first n targets to align data

# Split data into training and testing sets, last 12 as test set
train_inputs = inputs[:-12]
train_targets = targets[:-12]
test_inputs = inputs[-12:]
test_targets = targets[-12:]

# Convert to PyTorch tensors
train_inputs = torch.tensor(train_inputs.values).float()
train_targets = torch.tensor(train_targets.values).float().unsqueeze(1)
test_inputs = torch.tensor(test_inputs.values).float()
test_targets = torch.tensor(test_targets.values).float().unsqueeze(1)

# Create DataLoaders
train_dataset = TensorDataset(train_inputs, train_targets)
test_dataset = TensorDataset(test_inputs, test_targets)
batch_size = 12  # One data point at a time
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False, drop_last=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, drop_last=True)

# Define ERNN model
import torch
import torch.nn as nn

# Define ERNN model using ReLU
class ERNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(ERNN, self).__init__()
        self.hidden_size = hidden_size
        self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
        self.i2o = nn.Linear(input_size + hidden_size, output_size)
        self.tanh = nn.Tanh()

    def forward(self, input, hidden):
        if input.size(0) != hidden.size(0):
            hidden = self.initHidden(input.size(0))
        combined = torch.cat((input, hidden), 1)
        hidden = self.tanh(self.i2h(combined))
        output = self.i2o(combined)
        return output, hidden

    def initHidden(self, batch_size):
        return torch.zeros(batch_size, self.hidden_size)

# Initialize model
model = ERNN(input_size=n, hidden_size=24, output_size=1)

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.004, momentum=0.9)  # 使用带动量的SGD模拟traingdx

# 训练模型
def train_model(model, criterion, optimizer, train_loader, epochs):
    model.train()
    for epoch in range(epochs):
        total_loss = 0
        for inputs, targets in train_loader:
            optimizer.zero_grad()
            current_batch_size = inputs.size(0)  # 获取当前批次的大小
            hidden = model.initHidden(current_batch_size)  # 使用当前批次大小初始化隐藏状态
            outputs, hidden = model(inputs, hidden)
            loss = criterion(outputs, targets)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        if epoch % 1000 == 0:  # 每1000次迭代输出一次损失
            print(f'Epoch {epoch}: Loss = {total_loss / len(train_loader)}')

train_model(model, criterion, optimizer, train_loader, epochs=200000)  # 训练10000次迭代

# Evaluate model
def evaluate_model(model, loader):
    model.eval()
    predictions, actuals = [], []
    with torch.no_grad():
        for inputs, targets in loader:
            current_batch_size = inputs.size(0)  # 获取当前批次的大小
            hidden = model.initHidden(current_batch_size)  # 使用当前批次大小初始化隐藏状态
            outputs, hidden = model(inputs, hidden)
            predictions.extend(outputs.detach().numpy())
            actuals.extend(targets.numpy())
    mse = mean_squared_error(actuals, predictions)
    mae = mean_absolute_error(actuals, predictions)
    mape = mean_absolute_percentage_error(actuals, predictions)
    return mse, mae, mape

# Evaluate on both training and testing data
train_mse, train_mae, train_mape = evaluate_model(model, train_loader)
test_mse, test_mae, test_mape = evaluate_model(model, test_loader)

# Print evaluation metrics for both training and testing datasets
print(f"Training MSE: {train_mse}, MAE: {train_mae}, MAPE: {train_mape}")
print(f"Test MSE: {test_mse}, MAE: {test_mae}, MAPE: {test_mape}")

又是可怕的调参,首先看看文章的参数:

“在确定隐藏层神经元数量(N)时,使用了以下经验公式:

N = √(n + m )+ a

其中m是输入层的神经元数量,n是输出层的神经元数量,a是一个常数(范围在1到10之间)。根据这个计算,ERNN的隐藏层有3到12个神经元。我们对ERNN的隐含层使用了Tan-Sigmoid函数,对输出层使用了Purelin函数,训练函数用的是traingdx,网络权重学习函数用的是Learngdm,模型性能评估使用了MSE。网络的参数设置如下:迭代步数为10,000步,学习率为0.01,学习目标(学习误差)为0.004。然后我们使用了一个2-9-1结构的ERNN来预测百日咳的发病率。ARIMA-ERNN模型的MSE为0.00077,优于ARIMA模型的0.00937。”

我试了试,一言难尽。

然后自己调了一下参数,目前最好就这样了,过拟合了:

Training MSE: 1.5360685210907832e-05, MAE: 0.003031895263120532, MAPE: 0.21757353842258453

Test MSE: 0.001023554359562695, MAE: 0.026323571801185608, MAPE: 0.37139490246772766

各位大佬有更好的结果麻烦分享一下参数,跪谢~

本代码可以调的参数有:

输入特征数量 (n):

这个参数决定了每个输入样本中使用的连续ARIMA预测值的数量。您可以尝试使用不同数量的输入特征来看是否能改善模型的表现。

批大小 (batch_size):

这影响到模型训练的速度及收敛性。较大的批大小可以提高内存利用率和训练速度,但可能影响模型的最终性能和稳定性。反之,较小的批大小可能使训练过程更稳定、收敛更精细,但训练速度会减慢。

隐藏层大小 (hidden_size):

这决定了隐藏层中神经元的数量。增加隐藏层的大小可以提高模型的学习能力,但也可能导致过拟合。相应地,减少隐藏层大小可能减少过拟合的风险,但可能限制模型的能力。

学习率 (lr):

学习率是优化算法中最重要的参数之一。如果学习率设置得太高,模型可能无法收敛;如果设置得太低,模型训练可能过于缓慢,甚至在到达最佳点之前停止训练。

动量 (momentum):

动量帮助加速SGD在正确方向上的收敛,还可以减少优化过程中的震荡。调整这个参数可以影响学习过程的平滑性和速度。

激活函数:

模型中使用的是 Tanh 激活函数。可以考虑使用 ReLU 或其变体(如 LeakyReLU, ELU 等)以期改善模型性能,尤其是在处理非线性问题时。

优化器:

虽然使用的是带动量的SGD,但您也可以尝试使用其他优化器,如 Adam、RMSprop 等,这些优化器可能在不同的应用场景中表现更好。

迭代次数 (epochs):

增加或减少训练迭代次数可以影响模型的学习程度。太少的迭代次数可能导致模型欠拟合,而太多的迭代次数可能导致过拟合或不必要的计算资源消耗。

三、后话

又学习了一种潜在的ARIMA组合模型的策略,同样的,把ERNN换成别的模型,就又是一片新天地了。

四、数据

不提供,自行根据下图提取吧

实在没有GPT-4,那就这个:

http://apps.automeris.io/wpd/index.zh_CN.html

第100+10步 ChatGPT文献复现:ARIMA-ERNN预测百日咳插图(3)

本站无任何商业行为
个人在线分享 » 第100+10步 ChatGPT文献复现:ARIMA-ERNN预测百日咳
E-->