如何使用 Keras 预测时间范围的未来值?

数据挖掘 机器学习 Python 喀拉斯 预言 预测
2021-10-13 04:37:23

我刚刚用 Keras构建了这个LSTM 神经网络

    import numpy as np
    import pandas as pd 
    from sklearn import preprocessing
    from keras.layers.core import Dense, Dropout, Activation
    from keras.activations import linear
    from keras.layers.recurrent import LSTM
    from keras.models import Sequential
    from matplotlib import pyplot

    #read and prepare data from datafile
    data_file_name = "DailyDemand.csv"
    data_csv = pd.read_csv(data_file_name, delimiter = ';',header=None, usecols=[1,2,3,4,5])
    yt = data_csv[1:]
    data = yt
    data.columns = ['MoyenneTransactHier', 'MaxTransaction', 'MinTransaction','CountTransaction','Demand']
    # print (data.head(10))
    pd.options.display.float_format = '{:,.0f}'.format
    data = data.dropna ()
    y=data['Demand'].astype(int)
    cols=['MoyenneTransactHier', 'MaxTransaction', 'MinTransaction','CountTransaction']
    x=data[cols].astype(int)

    #scaling data
    scaler_x = preprocessing.MinMaxScaler(feature_range =(-1, 1))
    x = np.array(x).reshape ((len(x),4 ))
    x = scaler_x.fit_transform(x)
    scaler_y = preprocessing.MinMaxScaler(feature_range =(-1, 1))
    y = np.array(y).reshape ((len(y), 1))
    y = scaler_y.fit_transform(y)
    print("longeur de y",len(y))
    # Split train and test data
    train_end = 80
    x_train=x[0: train_end ,]
    x_test=x[train_end +1: ,]
    y_train=y[0: train_end]
    y_test=y[train_end +1:] 
    x_train=x_train.reshape(x_train.shape +(1,))
    x_test=x_test.reshape(x_test.shape + (1,))

    print("Data well prepared")
    print ('x_train shape ', x_train.shape)
    print ('y_train', y_train.shape)

    #Design the model - LSTM Network
    seed = 2016
    np.random.seed(seed)
    fit1 = Sequential ()
    fit1.add(LSTM(
        output_dim = 4,
        activation='tanh',
        input_shape =(4, 1)))
    fit1.add(Dense(output_dim =1))
    fit1.add(Activation(linear))
    #rmsprop or sgd
    batchsize = 1
    fit1.compile(loss="mean_squared_error",optimizer="rmsprop")
    #train the model
    fit1.fit(x_train , y_train , batch_size = batchsize, nb_epoch =20, shuffle=True)

    print(fit1.summary ())

    #Model error
    score_train = fit1.evaluate(x_train ,y_train ,batch_size =batchsize)
    score_test = fit1.evaluate(x_test , y_test ,batch_size =batchsize)
    print("in  train  MSE = ",round(score_train,4))
    print("in test  MSE = ",round(score_test ,4))

    #Make prediction
    pred1=fit1.predict(x_test)
    pred1 = scaler_y.inverse_transform(np.array(pred1).reshape ((len(pred1), 1)))
    real_test = scaler_y.inverse_transform(np.array(y_test).reshape ((len(y_test), 1))).astype(int)

    #save prediction
    testData = pd.DataFrame(real_test)
    preddData = pd.DataFrame(pred1)
    dataF = pd.concat([testData,preddData], axis=1)
    dataF.columns =['Real demand','Predicted Demand']
    dataF.to_csv('Demandprediction.csv')

    pyplot.plot(pred1, label='Forecast')
    pyplot.plot(real_test,label='Actual')
    pyplot.legend()
    pyplot.show()

然后它生成这个结果: 对测试数据的预测

在历史数据上建立和训练一个好的模型后,我不知道如何生成未来值的预测?比如未来10天的需求。数据是每天的。

这是如何塑造数据的示例

注意:这是数据形状的示例,绿色是标签,黄色是特征。
dropna()(删除空值)之后,它仍然是 100 个数据行,我在训练中使用了 80 个,在测试中使用了 20 个。

1个回答
这个答案有点不同,但我希望它仍然能回答你的问题。它使用滚动预测/预测的思想。

因为你使用了horizo​​n这个词,我假设你的意思是你想在给定的时间步预测未来10天。有几种方法可以做到这一点。对于这种时间序列问题,通常会假设只有特定的历史会影响接下来的几个时间步长(忽略季节性影响)。

用文字举例:

因此,在您的情况下,您可以使用例如前 60 天,并预测接下来的 10 天。以您的 100 行数据为例,这意味着您实际上可以进行(100 - 60 - 9) = 31预测,每个预测提前 10 个时间步长(我们将需要这些31个 predictor_blocks之后)。从 100 行中,我们丢失了前 60 行来拟合第一个模型。在剩下的 40 行数据中,我们可以提前预测 10 步(第 61-70 行),然后我们将整个数据再移动一行并重复。10 个未来点的最后预测将针对第 91-100 行。在那之后我们不能再预测 10 步,所以我们停止了——这就是为什么我们必须减去额外的 9。[当然有方法可以继续进行预测,因为要使用所有数据]

一千字的例子:

让我画一幅画;帮助解释移动窗口预测的想法。

对于每个训练集(例如从红色t=0t=5训练集 1),您要预测以下 H 个时间步长(对应于橙色中的 t=6 - 测试集 1)。在这种情况下,你的视野只是一个,即H=1

滚动样本外预测的基本草图

据我了解,您想预测接下来的 10 天,这意味着您需要H=10.

为了在您的示例中尝试此操作,我认为您需要进行两项更改。

改变 #1

您的训练集和测试集的形状需要与新视野相匹配。模型输入的每个样本(x_trainx_test可以与以前保持相同。但是,测试集中的每个样本都必须包含H=10标签的下一个值,而不仅仅是单个值。

这是一个粗略的示例,说明您可以如何执行此操作:

# Define our horizon
H = 10

# Create data split, using values from my example above
window_size = 60
num_pred_blocks = 31    # as computed above

# Loop over the train and test samples to create the sliding window sets
x_train = []
y_train = []
for i in range(num_pred_blocks):
    x_train_block = x_train[i:(i + window_size)]    # 31 blocks of 60 * num-columns
    x_train.append(x_train_block)
    y_train_block = y_train[(i + window_size):(i + window_size + H)]    # 31 blocks of 10 * 1
    y_train.append(y_train_block)

因为您正在进行样本外测试,所以您的预测看起来已经很有趣了。一旦运行,您就可以使用您提到的新数据创建等效的测试数据集。

在不太了解您的数据的情况下,我不知道您是否应该预测与输入相同行或下一行的 y 值。此外,根据您的数据,您可以y在每个x_train块中包含过去的值。在这种情况下,您只需交换x整个表,即data[cols]where new_cols = ['Demand'] + cols

改变 #2

您需要通过强制模型输出H值来使模型反映这个范围。

以下是如何指定模型的示例:

# Define our horizon
H = 10

# Create the model using the parameterised horizon
fit1 = Sequential ()
fit1.add(LSTM(output_dim = 4, activation='tanh', input_shape =(4, 1)))
fit1.add(Dense(output_dim=30, activation='sigmoid')
fit1.add(Dense(output_dim=H))    # our horizon is produced!

注意: 在您的模型规范中,您不需要添加最终的 linear Activation,因为前面的 Dense 层默认包含线性激活。请参阅此处的优秀文档

这是一个很大的话题,你可以尝试很多事情。我同意您对问题的评论,您将需要更多数据来允许 RNN 对模型进行意义表示。

如果您这样做不仅仅是为了了解 LSTM 等,另一种实用的方法可能是研究更简单的时间序列模型,例如ARIMA 模型(不要被复杂的名称吓倒 - 它比 LSTM 简单得多) . 使用 Python 可以很容易地构建这样的模型,使用statsmodels 包,它有一个很好的实现