#keras #recurrent-neural-network #forecasting #multi-step
#keras #recurrent-neural-network #forecasting #multi-step
Вопрос:
У меня есть проблема при использовании RNN, и я хочу предсказать несколько шагов вперед. Код «работает», но вывод не имеет смысла, в основном t 2 намного точнее, чем t 1, и то же самое относится к t 3, и очень нелогично, что вывод на один шаг вперед должен быть значительно менее точным. Настройка данных выглядит следующим образом; Мы хотим спрогнозировать общий объем продаж (на нескольких платформах) за данный час. Данных об общем объеме продаж не хватает, поэтому мы не располагаем ими постоянно. Продажи на внутренней платформе осуществляются в режиме реального времени, поэтому никаких задержек с этими данными нет. Наконец, у нас есть внешний прогноз, однако прогноз статичен и пересматривается не очень часто, но у нас он далеко в будущем. Проблема прогнозирования заключается в том, что мы хотим предсказать общий объем продаж на ближайшие 4 часа. Однако, поскольку общие данные о продажах задерживаются, мы уже знаем, каковы наши внутренние продажи за первый час, и у нас также есть внешний прогноз на все 4 часа. Как включить это в мою модель? Является ли моя текущая настройка правильным методом для этого?
Входные переменные имеют форму (Образцы, временные рамки, функции), где первый столбец в X_array[:,0,:] соответствует наблюдениям, которые являются первыми в последовательности, поэтому он является самой старой частью и аналогичен для Y_train —gt; Y_train[Имена целей].столбцы = [‘t 1’, ‘t 2’, ‘t 3’, ‘t 4’]
Приведенный ниже код является имитацией проблемы, а это означает, что второй элемент AE/MAPE должен быть меньше первого элемента — gt; t 2 имеет меньшую ошибку, чем t 1:
from tensorflow.keras.callbacks import EarlyStopping from sklearn.preprocessing import StandardScaler, MinMaxScaler import math import pandas as pd import numpy as np import tensorflow as tf from tensorflow import keras import datetime as dt pd.options.mode.chained_assignment = None # default='warn'
Сделать данные
df = pd.date_range('2021-01-01', '2021-12-01', freq='H') df = pd.DataFrame(df[0:len(df)-1], columns={'DateTime'}) df['TotalSales'] = 0 np.random.seed(1) for i in df.index: if i == df.index[0]: df['TotalSales'].iloc[i] = 1 else: x = df['TotalSales'].iloc[i-1] np.random.normal(0, 1, 1) if x lt; 0: df['TotalSales'].iloc[i] = 1 0.1 * math.exp(x) else: df['TotalSales'].iloc[i] = 1 0.9 * x df['InternalSales'] = 0.2 * df['TotalSales'] np.random.normal(0, 0.2, len(df)) df['ExternalForecast'] = df['TotalSales'] np.random.normal(0, 2, len(df)) df['ExternalForecast'][df['ExternalForecast']lt;0] = 0.1 df['InternalSales'].iloc[len(df)-3:] = np.nan # We do not know these observations df['TotalSales'].iloc[len(df)-4:] = np.nan # We do not know these observations df.set_index('DateTime', inplace=True) df.tail()
Выровнять данные
df['InternalSales_Lead1'] = df['InternalSales'].shift(-1) df['ExternalForecast_Lead2'] = df['ExternalForecast'].shift(-4) # typo df['ExternalForecast_Lead4'] =.. pd.set_option('display.max_columns', 5) df.tail()
Setting
valid_start = '2021-10-01' test_start = '2021-11-01' Gran = 60 # minutes Names = ['InternalSales_Lead1', 'ExternalForecast_Lead2'] Target = 'TotalSales' AlternativeForecast = 'ExternalForecast' TimeSteps = 24 # hours HORIZON = 4 # step ahead X_array = df.copy() X_array = X_array[Names] df.reset_index(inplace=True) Data = df[df['DateTime'].dt.date.astype(str) lt; test_start] scaler = StandardScaler().fit(Data[Names]) yScaler = MinMaxScaler().fit(np.array(Data[Target]).reshape(-1, 1)) df['Scaled_' Target] = yScaler.transform(np.array(df[Target]).reshape(-1, 1)) X_array = pd.DataFrame(scaler.transform(X_array), index=X_array.index,columns=X_array.columns) def LSTM_structure(Y, X, timestep, horizon, TargetName): if TargetName==None: print('TargetName must be specified') Array_X = np.zeros(((len(X) - timestep 1), timestep, len(X.columns))) for variable in range(0,len(X.columns)): col = X.columns[variable] for t in range(timestep, len(X) 1): # Array_X[t - timestep,:,variable] = np.array(X[col].iloc[(t - timestep):t]).T Array_X[t - timestep, :, variable] = X[col].iloc[(t - timestep):t].values if horizon ==1: Y_LSTM = Y[(timestep - 1):] Y_LSTM['t' str(horizon)] = Y_LSTM[TargetName] else: Y_LSTM = Y[(timestep - 1):] for t in range(1,horizon 1): Y_LSTM['t ' str(t)] = Y_LSTM[TargetName].shift(-(t-1)) return Y_LSTM, Array_X Y_total, X_array = LSTM_structure(Y=df[['DateTime', Target, 'Scaled_' Target, AlternativeForecast]], X=X_array, timestep=TimeSteps, horizon=HORIZON, TargetName='Scaled_' Target) # X_array.shape = (7993, 24, 2) Y_total.reset_index(drop=True, inplace=True) Y_train = Y_total[Y_total['DateTime'].dt.date.astype(str) lt; valid_start] X_train_scale = X_array[Y_train.index,:,:] Y_Val = Y_total[(Y_total['DateTime'].dt.date.astype(str) gt;= valid_start) amp; (Y_total['DateTime'].dt.date.astype(str) lt; test_start)] X_val_scale = X_array[Y_Val.index,:,:] Y_test = Y_total[Y_total['DateTime'].dt.date.astype(str) gt;= test_start] X_test_scale = X_array[Y_test.index,:,:]
Model
TargetNames = Y_total.filter(like='t ').columns LATENT_DIM = 5 BATCH_SIZE = 32 EPOCHS = 10 try: del model except Exception: pass model = keras.Sequential() model.add(keras.layers.GRU(LATENT_DIM, input_shape=(TimeSteps, X_train_scale.shape[2]))) model.add(keras.layers.RepeatVector(HORIZON)) model.add(keras.layers.GRU(LATENT_DIM, return_sequences=True)) model.add(keras.layers.TimeDistributed(keras.layers.Dense(1))) model.add(keras.layers.Flatten()) model.compile(optimizer='SGD', loss='mse') model.summary() earlystop = EarlyStopping(monitor='val_loss', min_delta=0, patience=3, restore_best_weights=True) i = 1 np.random.seed(i) tf.random.set_seed(i) hist = model.fit(X_train_scale, Y_train[TargetNames], batch_size=BATCH_SIZE, epochs=EPOCHS, validation_data=(X_val_scale, Y_Val[TargetNames]), callbacks=[earlystop], verbose=1) y_hat_scaled = model.predict(X_test_scale) for i in range(1, HORIZON 1): Y_test['Predict_t ' str(i)] = yScaler.inverse_transform(np.array(y_hat_scaled[:,i-1]).reshape(-1, 1))
Make format correct
for i in range(1, HORIZON 1): if i == 1: Performance = Y_test[['DateTime', Target, AlternativeForecast,'Predict_t ' str(i)]] else: Temp = Y_test[['DateTime', 'Predict_t ' str(i)]] Temp['DateTime'] = Temp['DateTime'] dt.timedelta(minutes=Gran * (i-1)) Performance = pd.merge(Performance, Temp[['DateTime', 'Predict_t ' str(i)]], how='left', on='DateTime')
Plot
from matplotlib import pyplot as plt plt.plot(Performance['DateTime'], Performance[Target], label=Target) for i in range(1, HORIZON 1): plt.plot(Performance['DateTime'], Performance['Predict_t ' str(i)], label='Predict_t ' str(i)) plt.title('Model Performance') plt.ylabel('MW') plt.xlabel('Time') plt.legend() plt.show()
Performance
for i in range(1, HORIZON 1): ae= (Performance['Predict_t ' str(i)] - Performance[Target]).abs().mean() mape = ((Performance['Predict_t ' str(i)] - Performance[Target]).abs()/Performance[Target]).mean() * 100 if i == 1: AE= ae MAPE = round(mape,2) else: AE= np.append(AE, ae) MAPE = np.append(MAPE, round(mape,2)) # Alternative forecast ae = (Performance[AlternativeForecast] - Performance[Target]).abs().mean() mape = ((Performance[AlternativeForecast] - Performance[Target]).abs()/Performance[Target]).mean() * 100 AE= np.append(AE, ae) MAPE = np.append(MAPE, round(mape, 2)) AE MAPE
I hope one of you have time to help me with this problem of mine 🙂