LSTM实战详细代码——匈牙利水痘病例时间序列预测


引言

        本文为机器学习大作业选题——匈牙利水痘病例预测(Prediction of the Hungarian case of chicken pox)的LSTM解决方法,参与答辩并获得优秀,主要是使用LSTM对病例数进行时间序列预测,包含数据集LSTM原理简述代码及解析结果展示四部分。所有文件如下

LSTM实战详细代码——匈牙利水痘病例时间序列预测_第1张图片

 下载链接:https://pan.baidu.com/s/13aYBe6AHnkPIVE7vyBL_hA       提取码:1234 

数据集

        提供的数据集分为三部分,分别是包含422条时间序列数据的训练集包含100条时间序列数据的测试集包含各县关系的空间连接图,训练集和测试集记录了对应连续时间序列的匈牙利各县的每周患病人数,空间连接图记录了各县两两连接的关系,共有20个顶点(19个县和首都布达佩斯),节点之间有61条边。

LSTM原理简述

        循环神经网络(Recurrent Neural Network,RNN)是一种用于处理序列数据的神经网络。相比一般的神经网络来说,他能够处理序列变化的数据,RNN对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息。

        其实RNN相对于全连接神将网络,只是在隐藏层多了个输入,每个节点都会将上一个节点隐藏层的输出作为当前节点隐藏层的输入放在一起训练,是因为它可以记住每一时刻的信息,每一时刻的隐藏层不仅由该时刻的输入层决定,还由上一时刻的隐藏层决定。但是当输入的序列过长后,后面的节点会越来越学习不到最开始节点的特征,会遇到梯度消失和梯度爆炸的问题。

        为了解决这个问题,就有了LSTM(Long short-term memory),LSTM能够实现既保留过去信息又能避免梯度爆炸和梯度消失问题依靠的就是它的“门控装置”

        首先,z和传统RNN中的输入类似,是加上了前一时刻隐藏层信息之后的输入,使用tanh激活函数处理,而控制这个输入的三个门分别是输入门、遗忘门和输出门,使用sigmod激活函数处理后得到的值都在0到1之间,1表示该门完全打开,0表示该门完全关闭。

        有了这三个门控,LSTM就可以对上一时刻隐藏层传来的输入进行筛选,而不是像传统RNN一样的全盘接受,经过筛选后的信息只保留少数更明显的特征,能够使有效特征在长时间的训练中保留,并避免了梯度爆炸和梯度消失。

        上述是我在阅读了一些博客和文章后的看法,下面是个人觉得对RNN和LSTM讲的比较好的博客链接

真的是让我豁然开朗一身通透的讲解:史上最详细循环神经网络讲解(RNN/LSTM/GRU)

涉及到的梯度下降很清楚的解释:通俗易懂讲解梯度下降法 - 知乎 (zhihu.com)

什么叫梯度爆炸和梯度消失(手撕BP公式):从反向传播推导到梯度消失and爆炸的原因

        如果能看完并吃透上述三篇博客,基本对LSTM就大概理解了,但是神经网络作为经典黑盒,我们并不能很清楚的知道里面的真正细节,如果想要真正从事NLP相关的,看这几篇博客肯定不够,它们只能起到一个引路的作用,想要了解细节,还是要通过看系统的知识讲解并动手去撕源码

代码及解析

        下文列出可运行代码及详细注释

import pandas as pd
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten, LSTM, TimeDistributed, RepeatVector
from keras.layers.normalization import BatchNormalization
from keras.optimizers import Adam
from keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import matplotlib.pyplot as plt
%matplotlib inline

n_in = 300 #历史数量
n_out = 100 #预测数量
n_features = 1
# n_test = 1
n_val = 1
n_epochs = 100

#d导入数据
def load_stw_data() -> pd.DataFrame:
    
    #df_stw = pd.read_excel('data3.xlsx')
    #df_stw.columns = ['Date', 'patients']
    df_stw = pd.read_csv('all.csv')
    df_stw.drop(labels=['BUDAPEST','BARANYA','BACS','BORSOD','CSONGRAD',
                        'FEJER','GYOR','HAJDU','HEVES','JASZ',
                        'KOMAROM','NOGRAD','PEST','SOMOGY','SZABOLCS',
                        'TOLNA','VAS','VESZPREM','ZALA'],axis=1,inplace=True)
    df_stw['Date']=df_stw['Date'].astype(object)
    df_stw['Date']=pd.to_datetime(df_stw['Date'])
    tmp=df_stw.set_index('Date')
    return df_stw


#MinMaxScaler数据归一化,可以帮助网络模型更快的拟合,稍微有一些提高准确率的效果
def minmaxscaler(data: pd.DataFrame) -> pd.DataFrame:
    
    volume = data.BEKES.values
    volume = volume.reshape(len(volume), 1)
    volume = scaler.fit_transform(volume)
    volume = volume.reshape(len(volume),)    
    data['BEKES'] = volume
        
    return data

#划分训练数据集和验证数据集
def split_data(x, y, n_test: int):
    
    x_train = x[:-n_val-n_out+1]
    x_val = x[-n_val:]
    y_train = y[:-n_val-n_out+1]
    y_val = y[-n_val:] 
    
    return x_train, y_train, x_val, y_val


#划分X和Y
def build_train(train, n_in, n_out):
    
    train = train.drop(["Date"], axis=1)
    X_train, Y_train = [], []
    for i in range(train.shape[0]-n_in-n_out+1):
        X_train.append(np.array(train.iloc[i:i+n_in]))
        Y_train.append(np.array(train.iloc[i+n_in:i+n_in+n_out]["BEKES"]))
        
    return np.array(X_train), np.array(Y_train)

#构建最简单的LSTM
def build_lstm(n_in: int, n_features: int):
    
    model = Sequential()
    model.add(LSTM(256, activation='relu', input_shape=(n_in, n_features)))
    model.add(Dropout(0.2))
   
    model.add(Dense(n_out))
    model.compile(optimizer='adam', loss='mae')
    
    return model

#模型拟合
def model_fit(x_train, y_train, x_val, y_val, n_features):
    
    model = build_lstm(
        n_in   = n_in,
        n_features= 1
    )
    model.compile(loss='mae', optimizer='adam')
    model.fit(x_train, y_train, epochs=n_epochs, batch_size=32, verbose=1,  validation_data=(x_val, y_val))
    m = model.evaluate(x_val, y_val)
    print(m)
    
    return model

#读入数据
data = load_stw_data()
data.head()
scaler = MinMaxScaler(feature_range=(0, 1))
data = minmaxscaler(data)

data_copy = data.copy()
x, y = build_train(data_copy, n_in, n_out)
x_train, y_train, x_val, y_val = split_data(x, y, n_val)
model = build_lstm(n_in, 1)
model = model_fit(x_train, y_train, x_val, y_val, 1)
predict = model.predict(x_val)  

# predict = model.predict(x_val)  
validation = scaler.inverse_transform(predict)[0]

actual = scaler.inverse_transform(y_val)[0]

predict = validation
actual = actual
x = [x for x in range(100)]
fig, ax = plt.subplots(figsize=(15,5),dpi = 300)
ax.plot(x, predict, linewidth=2.0,label = "predict")
ax.plot(x, actual, linewidth=2.0,label = "actual")
ax.legend(loc=2);
plt.ylim((0, 70))
plt.grid(linestyle='-.')
plt.show()

from sklearn import metrics
print('MAE:',metrics.mean_absolute_error(actual, predict))

from sklearn.metrics import mean_squared_error
print('MSE:',mean_squared_error(actual, predict))

结果展示

        下图展示首都BUDAPEST和BARANYA、BACS、BEKES三县的预测结果

LSTM实战详细代码——匈牙利水痘病例时间序列预测_第2张图片

你可能感兴趣的:(机器学习,lstm,机器学习,深度学习)