timesteps-样本的长度。
功能-使用的功能数量。
建模之前的第一件事是将2D格式的数据转换为3D数组。以下功能可以做到这一点:
例如,如果我们假设整个数据是数据的前10行,那么我们将过去3个小时用作特征,并希望预测出1步:
defcreate_X_Y(ts: np.array, lag=1, n_ahead=1, target_index=0) ->tuple: """A method to create X and Y matrix from a time series array for the training ofdeep learning models"""#Extractingthenumberoffeaturesthatarepassedfromthearrayn_features=ts.shape[1] #CreatingplaceholderlistsX, Y= [], [] iflen(ts) -lag<=0: X.append(ts) else: foriinrange(len(ts) -lag-n_ahead): Y.append(ts[(i+lag):(i+lag+n_ahead), target_index]) X.append(ts[i:(i+lag)]) X, Y=np.array(X), np.array(Y) #ReshapingtheXarraytoanRNNinputshapeX=np.reshape(X, (X.shape[0], lag, n_features)) returnX, Y
例如,如果我们假设整个数据是数据的前10行,那么我们将过去3个小时用作特征,并希望预测出1步:
ts=d[ ‘temp’, ‘day_cos’, ‘day_sin’, ‘month_sin’, ‘month_cos’, ‘pressure’, ‘wind_speed’].head(10).valuesX, Y=create_X_Y(ts, lag=3, n_ahead=1)
如我们所见,X矩阵的形状是6个样本,3个时间步长和7个特征。换句话说,我们有6个观测值,每个观测值都有3行数据和7列。之所以有6个观测值,是因为前3个滞后被丢弃并且仅用作X数据,并且我们预测提前1步,因此最后一个观测值也会丢失。
上图中显示了X和Y的第一个值对。
最终模型的超参数列表:
#Numberoflags (hoursback) touseformodelslag=48#Stepsaheadtoforecastn_ahead=1#Shareofobsintestingtest_share=0.1#Epochsfortrainingepochs=20#Batchsizebatch_size=512#Learningratelr=0.001#NumberofneuronsinLSTMlayern_layer=10#Thefeaturesusedinthemodelingfeatures_final= [‘temp’, ‘day_cos’, ‘day_sin’, ‘month_sin’, ‘month_cos’, ‘pressure’, ‘wind_speed’]
模型代码
classNNMultistepModel(): def__init__( self, X, Y, n_outputs, n_lag, n_ft, n_layer, batch, epochs, lr, Xval=None, Yval=None, mask_value=-999.0, min_delta=0.001, patience=5 ): lstm_input=Input(shape=(n_lag, n_ft)) #Seriessignallstm_layer=LSTM(n_layer, activation='relu')(lstm_input) x=Dense(n_outputs)(lstm_layer) self.model=Model(inputs=lstm_input, outputs=x) self.batch=batchself.epochs=epochsself.n_layer=n_layerself.lr=lrself.Xval=Xvalself.Yval=Yvalself.X=Xself.Y=Yself.mask_value=mask_valueself.min_delta=min_deltaself.patience=patiencedeftrainCallback(self): returnEarlyStopping(monitor='loss', patience=self.patience, min_delta=self.min_delta) deftrain(self): #Gettingtheuntrainedmodelempty_model=self.model#Initiatingtheoptimizeroptimizer=keras.optimizers.Adam(learning_rate=self.lr) #Compilingthemodelempty_model.compile(loss=losses.MeanAbsoluteError(), optimizer=optimizer) if (self.XvalisnotNone) & (self.YvalisnotNone): history=empty_model.fit( self.X, self.Y, epochs=self.epochs, batch_size=self.batch, validation_data=(self.Xval, self.Yval), shuffle=False, callbacks=[self.trainCallback()] ) else: history=empty_model.fit( self.X, self.Y, epochs=self.epochs, batch_size=self.batch, shuffle=False, callbacks=[self.trainCallback()] ) #Savingtooriginalmodelattributeintheclassself.model=empty_model#Returningthetraininghistoryreturnhistorydefpredict(self, X): returnself.model.predict(X)
创建用于建模之前的最后一步是缩放数据。
#Subsetingonlytheneededcolumnsts=d[features_final]nrows=ts.shape[0] #Splitingintotrainandtestsetstrain=ts[0:int(nrows* (1—test_share))] test=ts[int(nrows* (1—test_share)):] #Scalingthedatatrain_mean=train.mean() train_std=train.std()train= (train—train_mean) /train_stdtest= (test—train_mean) /train_std#Creatingthefinalscaledframets_s=pd.concat([train, test]) #CreatingtheXandYfortrainingX, Y=create_X_Y(ts_s.values, lag=lag, n_ahead=n_ahead)n_ft=X.shape[2]
现在我们将数据分为训练和验证
#SplitingintotrainandtestsetsXtrain, Ytrain=X[0:int(X.shape[0] * (1—test_share))], Y[0:int(X.shape[0] * (1—test_share))] Xval, Yval=X[int(X.shape[0] * (1—test_share)):], Y[int(X.shape[0] * (1—test_share)):]
数据的最终形状:
Shapeoftrainingdata: (243863, 48, 7) Shapeofthetargetdata: (243863, 1) Shapeofvalidationdata: (27096, 48, 7) Shapeofthevalidationtargetdata: (27096, 1)
剩下的就是使用模型类创建对象,训练模型并检查验证集中的结果。
#Initiatingthemodelobjectmodel=NNMultistepModel( X=Xtrain, Y=Ytrain, n_outputs=n_ahead, n_lag=lag, n_ft=n_ft, n_layer=n_layer, batch=batch_size, epochs=epochs, lr=lr, Xval=Xval, Yval=Yval, ) #Trainingofthemodelhistory=model.train()
使用训练好的模型,我们可以预测值并将其与原始值进行比较。
#Comparingtheforecastswiththeactualvaluesyhat= [x[0] forxinmodel.predict(Xval)] y= [y[0] foryinYval] #Creatingtheframetostorebothpredictionsdays=d[‘dt’].values[-len(y):]frame=pd.concat([ pd.DataFrame({‘day’: days, ‘temp’: y, ‘type’: ‘original’}), pd.DataFrame({‘day’: days, ‘temp’: yhat, ‘type’: ‘forecast’}) ]) #Creatingtheunscaledvaluescolumnframe[‘temp_absolute’] = [(x*train_std[‘temp’]) +train_mean[‘temp’] forxinframe[‘temp’]] #Pivotingpivoted=frame.pivot_table(index=’day’, columns=’type’) pivoted.columns= [‘_’.join(x).strip() forxinpivoted.columns.values] pivoted[‘res’] =pivoted[‘temp_absolute_original’] —pivoted[‘temp_absolute_forecast’] pivoted[‘res_abs’] = [abs(x) forxinpivoted[‘res’]]