赞
踩
由于原模型只能预测一天,不满足需求,所以在上篇的基础模型上进行修改,使原模型可以预测未来多天结果。
修改之后,新模型可以根据多天的数据预测未来多天的结果。应用范围广泛,可以用于,股票预测,汇率预测,安全仓库预测,电力负荷预测等各种实际的应用。可以根据数据集的不同,使用该模型解决各种实际的预测问题。
由于项目数据集不公开,本文使用公开数据集,Beijing PM2.5 Data Set进行仿真实验。具体来说,根据前五天的环境变量信息,预测未来五天的污染值。
(23条消息) lstm多变量预测_wh来啦的博客-CSDN博客
原模型:
改进之后的模型:
Beijing PM2.5 Data Set
下载数据集地址:
http://archive.ics.uci.edu/ml/datasets/Beijing+PM2.5+Data
如果失效,百度直接搜索Beijing PM2.5 Data Set,也可以免费获取数据集。
对数据进行清洗,得到可以使用的数据。数据清洗时需要根据数据本身的特点,进行针对性的清洗。
首先将数据划分为X,Y。本次实验需要设计输入五天的变量,输出未来五天的预测值,所以,n_in=5,表示需要历史五天的数据,n_out=5,表示预测未来五天的值,代码如下:
- def series_to_supervised(data, n_in=5, n_out=5, dropnan=True):
- # convert series to supervised learning
- n_vars = 1 if type(data) is list else data.shape[1]
- df = pd.DataFrame(data)
- cols, names = list(), list()
- # input sequence (t-n, ... t-1)
- for i in range(n_in, 0, -1):
- cols.append(df.shift(i))
- names += [('var%d(t-%d)' % (j + 1, i)) for j in range(n_vars)]
- # forecast sequence (t, t+1, ... t+n)
- for i in range(0, n_out):
- cols.append(df.shift(-i))
- if i == 0:
- names += [('var%d(t)' % (j + 1)) for j in range(n_vars)]
- else:
- names += [('var%d(t+%d)' % (j + 1, i)) for j in range(n_vars)]
- # put it all together
- agg = pd.concat(cols, axis=1)
- agg.columns = names
- # drop rows with NaN values
- if dropnan:
- agg.dropna(inplace=True)
- # normalize features
- return agg
将不需要预测的数据drop掉,得到我们希望预测的数据结构。
- def cs_to_sl():
- # load dataset
- dataset = pd.read_csv('pollution.csv', header=0, index_col=0)
- values = dataset.values
- # integer encode direction
- encoder = LabelEncoder()
- values[:, 4] = encoder.fit_transform(values[:, 4])
- # ensure all data is float
- values = values.astype('float32')
- # frame as supervised learning
- reframed = series_to_supervised(values, 5, 5)
- # drop columns we don't want to predict
- reframed.drop(reframed.columns[[41,42,43,44,45,46,47,49,50,51,52,53,54,55,57,58,59,60,61,62,63,65,66,67,68,69,70,71,73, 74, 75, 76, 77, 78, 79]], axis=1, inplace=True)
- print(reframed.head())
- return reframed
因为一天有八个变量,需要历史五天的数据,所有X就有8*5列(40列)数据,而要预测未来五天的污染物值,所以Y有5列数据,合在一起就有45列数据。,具体的历史数据,预测数据结构如下:
然后将数据划分为训练集(train),测试集(test)。由于数据列表数发生变化,归一化的过程调整到这一部分,否者列数对应不上,反归一化时会报错。由于预测的列数发生变化,划分train_x,train_y,test_x,test_y时,需要调整相应的维度,这里调整为.[:,:-5][:,-5:]。具体代码如下:
- def train_test(reframed):
- # split into train and test sets
- values = reframed.values
- n_train_hours = 365 * 24*3
- scaler = MinMaxScaler(feature_range=(0, 1))
- values = scaler.fit_transform(values)
- train = values[:n_train_hours, :]
- test = values[n_train_hours:, :]
- # split into input and outputs
- train_X, train_y = train[:, :-5],train[:, -5:]
- test_X, test_y = test[:, :-5], test[:, -5:]
- # reshape input to be 3D [samples, timesteps, features]
- train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))
- test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))
- print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
- return train_X, train_y, test_X, test_y, scaler
调整模型结构,从原来的一层lstm,调整到三层lstm。为了避免过拟合的问题,使用Dropout函数。由于要预测未来五天的数据,所以最后一个dense的输出,从原来的1,调整为5。同时,修改模型的学习率,使模型取得更好的效果。最后,在对应的列上,使用反归一化,得到未来预测的结果。其他参数,如epoch,batchsize等,可以自己调整,就不细说了。嘻嘻
- def fit_network(train_X, train_y, test_X, test_y, scaler):
- model = Sequential()
- model.add(LSTM(50, return_sequences=True,input_shape=(train_X.shape[1], train_X.shape[2])))
- model.add(Dropout(0.3))
- model.add(LSTM(50,return_sequences=True))
- model.add(Dropout(0.3))
- model.add(LSTM(50))
- model.add(Dense(5))
- model.compile(loss='mae', optimizer='adam')
- # fit network
- reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')
-
- history = model.fit(train_X, train_y, epochs=50, batch_size=72, validation_data=(test_X, test_y), verbose=2,
- shuffle=False, callbacks=[reduce_lr])
- # plot history
- pyplot.plot(history.history['loss'], label='train')
- pyplot.plot(history.history['val_loss'], label='test')
- pyplot.legend()
- pyplot.show()
- # make a prediction
- yhat = model.predict(test_X)
- test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))
- # invert scaling for forecast
- inv_yhat = concatenate((test_X, yhat),axis=1)
- inv_yhat = scaler.inverse_transform(inv_yhat)
- print(inv_yhat[-1:])
- inv_yhat = inv_yhat[:, -5:]
- # invert scaling for actual
- inv_y = concatenate((test_X, test_y), axis=1)
- inv_y = scaler.inverse_transform(inv_y)
- inv_y = inv_y[:, -5:]
- # calculate RMSE
- rmse = sqrt(mean_squared_error(inv_y, inv_yhat))
- print('Test RMSE: %.3f' % rmse)
结果分析: 至于为什么自己误差那么大,可能是因为数据选得不好;或者是因为模型结构不够完美,需要微调;或者是因为一次预测五天,相比预测一天,误差本来就会很大。这个就得慢慢分析,调整了,嘻嘻。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。