基于SARIMA、XGBoost和CNN-LSTM的時間序列預測對比(3)
XGBoost
XGBoost (eXtreme Gradient Boosting)是一種梯度增強決策樹算法。它使用集成方法,其中添加新的決策樹模型來修改現有的決策樹分數。與SARIMA不同的是,XGBoost是一種多元機器學習算法,這意味著該模型可以采用多特征來提高模型性能。
我們采用特征工程提高模型精度。還創建了3個附加特性,其中包括AC和DC功率的滯后版本,分別為S1_AC_POWER和S1_DC_POWER,以及通過交流功率除以直流功率的總體效率EFF。并將AC_POWER和MODULE_TEMPERATURE從數據中刪除。圖14通過增益(使用一個特征的分割的平均增益)和權重(一個特征在樹中出現的次數)顯示了特征的重要性級別。
通過網格搜索確定建模使用的超參數,結果為:*learning rate = 0.01, number of estimators = 1200, subsample = 0.8, colsample by tree = 1, colsample by level = 1, min child weight = 20 and max depth = 10
我們使用MinMaxScaler將訓練數據縮放到0到1之間(也可以試驗其他縮放器,如log-transform和standard-scaler,這取決于數據的分布)。通過將所有自變量向后移動一段時間,將數據轉換為監督學習數據集。
import numpy as np import pandas as pd import xgboost as xgb from sklearn.preprocessing import MinMaxScaler from time import time
def train_test_split(df, test_len=48): """ split data into training and testing. """ train, test = df[:-test_len], df[-test_len:] return train, test
def data_to_supervised(df, shift_by=1, target_var='DC_POWER'): """ Convert data into a supervised learning problem. """ target = df[target_var][shift_by:].values dep = df.drop(target_var, axis=1).shift(-shift_by).dropna().values data = np.column_stack((dep, target)) return data
def xgb_forecast(train, x_test): """ XGBOOST model which outputs prediction and model. """ x_train, y_train = train[:,:-1], train[:,-1] xgb_model = xgb.XGBRegressor(learning_rate=0.01, n_estimators=1500, subsample=0.8, colsample_bytree=1, colsample_bylevel=1, min_child_weight=20, max_depth=14, objective='reg:squarederror') xgb_model.fit(x_train, y_train) yhat = xgb_model.predict([x_test]) return yhat[0], xgb_model
def walk_forward_validation(df): """ A walk forward validation approach by scaling the data and changing into a supervised learning problem. """ preds = [] train, test = train_test_split(df)
scaler = MinMaxScaler(feature_range=(0,1)) train_scaled = scaler.fit_transform(train) test_scaled = scaler.transform(test)
train_scaled_df = pd.DataFrame(train_scaled, columns = train.columns, index=train.index) test_scaled_df = pd.DataFrame(test_scaled, columns = test.columns, index=test.index)
train_scaled_sup, test_scaled_sup = data_to_supervised(train_scaled_df), data_to_supervised(test_scaled_df) history = np.array([x for x in train_scaled_sup])
for i in range(len(test_scaled_sup)): test_x, test_y = test_scaled_sup[i][:-1], test_scaled_sup[i][-1] yhat, xgb_model = xgb_forecast(history, test_x) preds.append(yhat) np.append(history,[test_scaled_sup[i]], axis=0)
pred_array = test_scaled_df.drop("DC_POWER", axis=1).to_numpy() pred_num = np.array([pred]) pred_array = np.concatenate((pred_array, pred_num.T), axis=1) result = scaler.inverse_transform(pred_array)
return result, test, xgb_model
if __name__ == '__main__': start_time = time() xgb_pred, actual, xgb_model = walk_forward_validation(dropped_df_cat) time_len = time() - start_time
print(f'XGBOOST runtime: {round(time_len/60,2)} mins')
圖15顯示了XGBoost模型的預測值與SP2 2天內記錄的直流功率的比較。
CNN-LSTM
CNN-LSTM (convolutional Neural Network Long - Short-Term Memory)是兩種神經網絡模型的混合模型。CNN是一種前饋神經網絡,在圖像處理和自然語言處理方面表現出了良好的性能。它還可以有效地應用于時間序列數據的預測。LSTM是一種序列到序列的神經網絡模型,旨在解決長期存在的梯度爆炸/消失問題,使用內部存儲系統,允許它在輸入序列上積累狀態。
在本例中,使用CNN-LSTM作為編碼器-****體系結構。由于CNN不直接支持序列輸入,所以我們通過1D CNN讀取序列輸入并自動學習重要特征。然后LSTM進行解碼。與XGBoost模型類似,使用scikitlearn的MinMaxScaler使用相同的數據并進行縮放,但范圍在-1到1之間。對于CNN-LSTM,需要將數據重新整理為所需的結構:[samples, subsequences, timesteps, features],以便可以將其作為輸入傳遞給模型。
由于我們希望為每個子序列重用相同的CNN模型,因此使用timedidistributedwrapper對每個輸入子序列應用一次整個模型。在下面的圖16中可以看到最終模型中使用的不同層的模型摘要。
在將數據分解為訓練數據和測試數據之后,將訓練數據分解為訓練數據和驗證數據集。在所有訓練數據(包括驗證數據)的每次迭代之后,模型可以進一步使用這一點來評估模型的性能。
學習曲線是深度學習中使用的一個很好的診斷工具,它顯示了模型在每個階段之后的表現。下面的圖17顯示了模型如何從數據中學習,并顯示了驗證數據與訓練數據的收斂。這是良好模特訓練的標志。
import pandas as pd import numpy as np from sklearn.metrics import mean_squared_error from sklearn.preprocessing import MinMaxScaler import keras from keras.models import Sequential from keras.layers.convolutional import Conv1D, MaxPooling1D from keras.layers import LSTM, TimeDistributed, RepeatVector, Dense, Flatten from keras.optimizers import Adam
n_steps = 1 subseq = 1
def train_test_split(df, test_len=48): """ Split data in training and testing. Use 48 hours as testing. """ train, test = df[:-test_len], df[-test_len:] return train, test
def split_data(sequences, n_steps): """ Preprocess data returning two arrays. """ x, y = [], [] for i in range(len(sequences)): end_x = i + n_steps
if end_x > len(sequences): break x.append(sequences[i:end_x, :-1]) y.append(sequences[end_x-1, -1])
return np.array(x), np.array(y)
def CNN_LSTM(x, y, x_val, y_val): """ CNN-LSTM model. """ model = Sequential() model.add(TimeDistributed(Conv1D(filters=14, kernel_size=1, activation="sigmoid", input_shape=(None, x.shape[2], x.shape[3])))) model.add(TimeDistributed(MaxPooling1D(pool_size=1))) model.add(TimeDistributed(Flatten())) model.add(LSTM(21, activation="tanh", return_sequences=True)) model.add(LSTM(14, activation="tanh", return_sequences=True)) model.add(LSTM(7, activation="tanh")) model.add(Dense(3, activation="sigmoid")) model.add(Dense(1))
model.compile(optimizer=Adam(learning_rate=0.001), loss="mse", metrics=['mse']) history = model.fit(x, y, epochs=250, batch_size=36, verbose=0, validation_data=(x_val, y_val))
return model, history
# split and resahpe data train, test = train_test_split(dropped_df_cat)
train_x = train.drop(columns="DC_POWER", axis=1).to_numpy() train_y = train["DC_POWER"].to_numpy().reshape(len(train), 1)
test_x = test.drop(columns="DC_POWER", axis=1).to_numpy() test_y = test["DC_POWER"].to_numpy().reshape(len(test), 1)
#scale data scaler_x = MinMaxScaler(feature_range=(-1,1)) scaler_y = MinMaxScaler(feature_range=(-1,1))
train_x = scaler_x.fit_transform(train_x) train_y = scaler_y.fit_transform(train_y)
test_x = scaler_x.transform(test_x) test_y = scaler_y.transform(test_y)
# shape data into CNN-LSTM format [samples, subsequences, timesteps, features] ORIGINAL train_data_np = np.hstack((train_x, train_y)) x, y = split_data(train_data_np, n_steps) x_subseq = x.reshape(x.shape[0], subseq, x.shape[1], x.shape[2])
# create validation set x_val, y_val = x_subseq[-24:], y[-24:] x_train, y_train = x_subseq[:-24], y[:-24]
n_features = x.shape[2] actual = scaler_y.inverse_transform(test_y)
# run CNN-LSTM model if __name__ == '__main__': start_time = time()
model, history = CNN_LSTM(x_train, y_train, x_val, y_val) prediction = []
for i in range(len(test_x)): test_input = test_x[i].reshape(1, subseq, n_steps, n_features) yhat = model.predict(test_input, verbose=0) yhat_IT = scaler_y.inverse_transform(yhat) prediction.append(yhat_IT[0][0])
time_len = time() - start_time mse = mean_squared_error(actual.flatten(), prediction)
print(f'CNN-LSTM runtime: {round(time_len/60,2)} mins') print(f"CNN-LSTM MSE: {round(mse,2)}")
圖18顯示了CNN-LSTM模型的預測值與SP2 2天內記錄的直流功率的對比。
由于CNN-LSTM的隨機性,該模型運行10次,并記錄一個平均MSE值作為最終值,以判斷模型的性能。圖19顯示了為所有模型運行記錄的mse的范圍。
下表顯示了每個模型的MSE (CNN-LSTM的平均MSE)和每個模型的運行時間(以分鐘為單位)。
從表中可以看出,XGBoost的MSE最低、運行時第二快,并且與所有其他模型相比具有最佳性能。由于該模型顯示了一個可以接受的每小時預測的運行時,它可以成為幫助運營經理決策過程的強大工具。
總結在本文中我們分析了SP1和SP2,確定SP1性能較低。所以對SP2的進一步調查顯示,并且查看了SP2中那些模塊性能可能有問題,并使用假設檢驗來計算每個模塊在統計上明顯表現不佳的次數,' Quc1TzYxW2pYoWX '模塊顯示了約850次低性能計數。
我們使用數據訓練三個模型:SARIMA、XGBoost和CNN-LSTM。SARIMA表現最差,XGBOOST表現最好,MSE為16.9,運行時間為1.43 min。所以可以說XGBoost在表格數據中還是最優先得選擇。
本文代碼:https://github.com/Amitdb123/Solar_Power_Analysis-Prediction
數據集:https://www.kaggle.com/datasets/ef9660b4985471a8797501c8970009f36c5b3515213e2676cf40f540f0100e54
作者:Amit Bharadwa
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。