使用LSTM网络做预报(Forecast)
在一次小小的比赛中需要做趋势预测,当时找了很多种方法,最后也对LSTM的使用做出一定的研究,现在大多数能找到的都是Predict,对于Forecast的做法虽然找到了原理,但由于各种原因自己未能很好写出。最后是完成了,这里也做一个小小的记录。
LSTM
完全不想解释,因为只是调包侠,原理还不懂,调参都是手动调的,很离谱。
代码
导入基础模块,preprocessing用作数据归一化预处理
# 导入模块
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.models import Sequential, load_model
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
下面对疫情数据进行读取,疫情数据分为三列,分别为Date、Confirmed、New,因为只做一维数据,所以先drop掉Date和New,并且将剩下的Confirmed列用values的方式读取出来。
# 读取数据
dataframe = pd.read_csv('./datalab/62612/中国疫情.csv')
dataframe = dataframe.drop(columns=['Date'])
dataframe = dataframe.drop(columns=['New'])
dataset = dataframe.values
为了做归一化,将int转化为float,随后进行归一化处理
dataset = dataset.astype('float32')
#归一化
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
分割
#分割训练集与测试集
train_size = int(len(dataset)*0.80)
test_size = len(dataset)-train_size
train,test = dataset[0:train_size,:],dataset[train_size:,:]
下面就是Forecast的核心。因为LSTM适用于给出下一刻数据,那么我们就采取时间滑窗的方式,将预测出的下一刻数据加入到数据集中,在进行下一刻预测。其中,create_dataset是LSTM建立数据集的核心,而create_predict是建立滑窗。
look_back也是timesteps,它代表着LSTM的映射关系,例如1就代表着1个X预测1个Y,3就代表3个X预测1个Y,在数据量小时,可以适当调整
#滑窗,建立数据集
def create_dataset(dataset,look_back):
dataX,dataY = [],[]
for i in range(len(dataset)-look_back-1):
a = dataset[i:(i+look_back),0]
dataX.append(a)
dataY.append(dataset[i+look_back,0])
return np.array(dataX),np.array(dataY)
def create_predict(dataset,look_back):
dataX = []
for i in range(len(dataset)-look_back):
a = dataset[i+1:,0]
dataX.append(a)
return np.array(dataX)
look_back = 1
trainX,trainY = create_dataset(train,look_back)
testX,testY = create_dataset(test,look_back)
对训练集与测试集进行转换,因为keras需要。
#转换数据
trainX = np.reshape(trainX,(trainX.shape[0],1,trainX.shape[1]))
testX = np.reshape(testX,(testX.shape[0],1,testX.shape[1]))
初始化LSTM模型,注意input_shape,它决定了投进模型的数据维度,所以设置为look_back与前面设置的映射关系相符合。
model = Sequential()
model.add(LSTM(4, input_shape=(None,look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=8, verbose=False)
Predict
#预测
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
#反归一化
trainPredict = scaler.inverse_transform(trainPredict)
testPredict = scaler.inverse_transform(testPredict)
Forecast的又一个核心,运用了栈的原理,将Predict的值压入dataset中。
此处尤其注意,这几个操作所需的数据格式不一样,也是我试过很多次试出来的。append无法对array变量作用(或者是ndarray,我也忘了),所以要先将其变成List,同时,predict出的值自带中括号(我也不知道是什么数据类型),所以需要将其扁平化(一顿瞎编,我也不懂)(这一部分尤其重要,很多时候就停滞在此了)
predict_series = []
for i in range(30):
p = dataset[-(look_back + 1):]
p1 = create_predict(p, look_back)
p2 = np.reshape(p1, (p1.shape[0], 1, p1.shape[1]))
predict = model.predict(p2)
dataset = np.vstack((dataset,predict))
predict = scaler.inverse_transform(predict)
predict=predict.flatten()
predict = predict.tolist()
predict_series.append(predict)
print(predict_series)
此部分为画图做准备,重新读取数据,并且设定出forecast的范围,因为往后预测了30步,所以此处设置为+1~+31
dataframe = pd.read_csv('./datalab/62612/中国疫情.csv')
future=np.arange(dataframe['Date'].shape[0]+1,dataframe['Date'].shape[0]+31,1)
plt.figure(figsize=(12, 8))
plt.plot(trainPredict)
plt.plot(testPredict)
plt.plot(future,predict_series)
dataframe = pd.read_csv('./datalab/62612/中国疫情.csv')
dataframe = dataframe.drop(columns=['Date'])
dataframe = dataframe.drop(columns=['New'])
dataset = dataframe.values
plt.plot(dataset)
plt.xlabel('天数')
plt.ylabel('感染人群数目')
plt.legend(['trainPredict','testPredict','forecast','data'], loc='best')
plt.show
Finished!
此文章自己观看,单纯当胡编就行了。