前言:

       由于原模型只能预测一天,不满足需求,所以在上篇的基础模型上进行修改,使原模型可以预测未来多天结果。

      修改之后,新模型可以根据多天的数据预测未来多天的结果。应用范围广泛,可以用于,股票预测,汇率预测,安全仓库预测,电力负荷预测等各种实际的应用。可以根据数据集的不同,使用该模型解决各种实际的预测问题。

       由于项目数据集不公开,本文使用公开数据集,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)

最后展示一下运行结果:

    结果分析: 至于为什么自己误差那么大,可能是因为数据选得不好;或者是因为模型结构不够完美,需要微调;或者是因为一次预测五天,相比预测一天,误差本来就会很大。这个就得慢慢分析,调整了,嘻嘻。

来源:wh来啦

物联沃分享整理
物联沃-IOTWORD物联网 » lstm 预测未来多天

发表评论