0
本文作者: AI研習社-譯站 | 2020-08-17 13:14 |
字幕組雙語原文:如何使用XGBoost模型進行時間序列預(yù)測
英語原文:How to Use XGBoost for Time Series Forecasting
翻譯:雷鋒字幕組(Shangru)
XGBoost是在有效解決分類和回歸問題的一種梯度提升方法。
在廣泛的預(yù)測模型任務(wù)中,它快且有效,性能好。它在諸如Kaggle等數(shù)據(jù)科學競賽的獲勝者中最受歡迎。XGBoost也可以被用于時間序列預(yù)測,盡管它需要將時間序列數(shù)據(jù)集先轉(zhuǎn)換成監(jiān)督學習問題。它需要用到一種被稱為前進式驗證的特殊方法來評估模型,因為使用k折驗證來評估模型容易導(dǎo)致偏向樂觀的結(jié)果。本教程中,你將探索如何為時間序列預(yù)測開發(fā)一個XGBoost模型。
完成本教程后,你將了解:
XGBoost是對分類和回歸問題的梯度提升集成算法的實現(xiàn)
時間序列數(shù)據(jù)集可以通過滑窗表示轉(zhuǎn)換成監(jiān)督學習。
如何使用XGBoost模型對時間序列預(yù)測進行擬合,評估以及預(yù)測
讓我們開始吧
本教程分為三部分。它們是:
XGBoost集成
時間序列數(shù)據(jù)準備
時間預(yù)測中的XGBoost
XGBoost是 Extreme Gradient Boosting的縮寫。它是隨機梯度提升機器學習算法的有效實現(xiàn)。
隨機梯度提升算法,也叫做梯度提升機或者提升樹,是一種強大的機器學習技術(shù)。他在廣泛的有挑戰(zhàn)性的機器學習問題上有著好的,甚至是最好的表現(xiàn)。
提升樹以及在很多標準分類指標上表現(xiàn)出來最先進的結(jié)果
—— XGBoost: A Scalable Tree Boosting System, 2016.
它是一種決策樹集成算法,其中新的樹會去修正模型中已有的樹的誤差。樹會被一直添加進去直到模型表現(xiàn)沒有更多提升。
XGBoost為隨機梯度提升算法,以及為訪問整套模型超參數(shù)來控制模型訓(xùn)練過程提供了一種高效實現(xiàn)。
XGBoost成功的背后最重要的一點是全場景的規(guī)?;?。該系統(tǒng)運行速度超出現(xiàn)流行的單機方案十倍之上。它在分布式或者內(nèi)存有限的設(shè)定下,規(guī)??蛇_數(shù)十億例。
—— XGBoost: A Scalable Tree Boosting System, 2016.
XGBoost是為表格型數(shù)據(jù)的分類和回歸問題設(shè)計的,盡管它也可以用于時間序列預(yù)測。
關(guān)于更多的梯度提升和XGBoost實現(xiàn),參考下面教程:
A Gentle Introduction to the Gradient Boosting Algorithm for Machine Learning
首先,必須安裝XGBoost庫。
你可以通過pip安裝,如下
sudo pip install xgboost |
一旦安裝完成,你可以通過下面代碼確認下是否成功安裝以及你是否使用了新的版本。
# xgboost import xgboost print("xgboost", xgboost.__version__) |
運行這些代碼,你可以看到下面或者更高的版本號。
xgboost 1.0.1 |
盡管XGBoost庫有著自己的Python API,我們通過scikit-learn API中的XGBRegressor封裝類來使用XGBoost模型。
模型的實例可以像其他scikit-learn類一樣實例化和使用來進行模型評估。例如:
... # 模型定義 model = XGBRegressor() |
時間序列數(shù)據(jù)可以使用監(jiān)督學習來表述。
當給定一個時間序列數(shù)據(jù)集的數(shù)字序列,我們可以重新組織數(shù)據(jù)使之看起來像一個監(jiān)督學習問題。為了達到這種效果,我們把前幾步的數(shù)據(jù)作為輸入變量,下一步的作為輸出。
我用一個例子來支持這一點。想象一些我們有如下的時間序列:
time, measure 1, 100 2, 110 3, 108 4, 115 5, 120 |
我們可以通過前一個時間的值來預(yù)測下一個時間的值,從而將該時間序列數(shù)據(jù)集重組為一個監(jiān)督學習問題。
如上重組時間序列數(shù)據(jù)集后,數(shù)據(jù)看起來像下面這樣:
X, y ?, 100 100, 110 110, 108 108, 115 115, 120 120, ? |
注意到時間列被丟棄了,有些行的數(shù)據(jù)對模型訓(xùn)練是無用的,比如第一行和最后一行。
這種表述被稱為滑窗,因為輸入窗口和預(yù)計輸出是隨著時間向前滑動,從而創(chuàng)建了監(jiān)督學習模型的新“樣本”。
關(guān)于更多關(guān)于用滑窗方法準備時間序列預(yù)測數(shù)據(jù),可以看以下教程:
Time Series Forecasting as Supervised Learning
在給定輸入輸出序列長度時的時間序列問題中,我們使用Pandas中的shift()函數(shù)來自動創(chuàng)建窗口。
這是一個很有用的工具,它使得我們在使用機器學習算法時可以使用不同的窗口探索時間序列問題,來找出哪種可能下模型表現(xiàn)更好。
下面這個函數(shù)將時間序列作為一個單列或多列的Numpay數(shù)組時間序列,并將其轉(zhuǎn)換成一個特定輸入輸出數(shù)量的監(jiān)督學習問題。
# 將時間序列數(shù)據(jù)集轉(zhuǎn)換成監(jiān)督學習數(shù)據(jù)集 def series_to_supervised(data, n_in=1, n_out=1, dropnan=True): n_vars = 1 if type(data) is list else data.shape[1] df = DataFrame(data) cols = list() # 輸入序列 (t-n, ... t-1) for i in range(n_in, 0, -1): cols.append(df.shift(i)) # 預(yù)測序列 (t, t+1, ... t+n) for i in range(0, n_out): cols.append(df.shift(-i)) # 合并到一起 agg = concat(cols, axis=1) #丟棄含有NaN的行 if dropnan: agg.dropna(inplace=True) return agg.values |
我們使用該函數(shù)來準備XGBoost的時間序列數(shù)據(jù)集。
更多關(guān)于這個函數(shù)的一步步的開發(fā),可以看一下教程
How to Convert a Time Series to a Supervised Learning Problem in Python
一旦數(shù)據(jù)集準備好了,如何使用它們?nèi)M合和評估模型就要務(wù)必仔細。
比如,使用未來的數(shù)據(jù)擬合模型來預(yù)測過去的數(shù)據(jù)就是無效的。模型應(yīng)該是在過去的數(shù)據(jù)上訓(xùn)練,預(yù)測未來。
這意味著在模型評估時,一些隨機化數(shù)據(jù)集的方法,比如k折交叉驗證,就不能使用了。取而代之地,我們使用一種被稱為前進式驗證的技術(shù)。
在前進式驗證中,數(shù)據(jù)集首先通過選擇分割點,分為訓(xùn)練集和測試集。比如,除了過去12個月的所有數(shù)據(jù)被用來訓(xùn)練,而過去12個月的數(shù)據(jù)用作測試。
如果我們感興趣的是單步預(yù)測,比如,一個月,我們可以通過在訓(xùn)練集上訓(xùn)練,在測試集的第一步進行預(yù)測。然后我們將測試集中真實的觀察值加入訓(xùn)練集,重新擬合模型,然后在測試集的第二步上使用該模型預(yù)測。
對整個測試集重復(fù)該過程,就可以得到整個數(shù)據(jù)集上的單步預(yù)測?;谠擃A(yù)測計算的誤差可以用來評估模型的能力。
關(guān)于更多前進式驗證,可以看教程:
How To Backtest Machine Learning Models for Time Series Forecasting
以下函數(shù)可處理前進式驗證。
它的參數(shù)是整個監(jiān)督學習版的時間序列數(shù)據(jù)集和用作測試集的行數(shù)。
然后它開始處理測試集,調(diào)用 xgboost_forecast()函數(shù)來進行單步預(yù)測。它會返回計算所得的誤差度量和一些可供分析的細節(jié)。
# 單變量數(shù)據(jù)的前進式驗證 def walk_forward_validation(data, n_test): predictions = list() # 分割數(shù)據(jù)集 train, test = train_test_split(data, n_test) # 用訓(xùn)練集中的數(shù)據(jù)填充歷史 history = [x for x in train] # 遍歷測試集中的每個時間步 for i in range(len(test)): # 將測試行分為輸入和輸出列 testX, testy = test[i, :-1], test[i, -1] # 在歷史數(shù)據(jù)上擬合模型并做預(yù)測 yhat = xgboost_forecast(history, testX) # 在預(yù)測列表中儲存預(yù)測 predictions.append(yhat) # 為下一個循環(huán)在歷史中添加真實觀察 history.append(test[i]) # 進度總結(jié) print('>expected=%.1f, predicted=%.1f' % (testy, yhat)) # 估計預(yù)測誤差 error = mean_absolute_error(test[:, 1], predictions) return error, test[:, 1], predictions |
調(diào)用 train_test_split()將數(shù)據(jù)集分割成訓(xùn)練集和測試集
我們定義以下函數(shù)
# 將一個單變量數(shù)據(jù)集分割成訓(xùn)練/測試集 def train_test_split(data, n_test): return data[:-n_test, :], data[-n_test:, :] |
我們是用XGBRegressor類來進行但不預(yù)測。
xgboost_forecast()函數(shù)的實現(xiàn)如下,以訓(xùn)練集和測試輸入行作為輸入,擬合模型,然后進行單步預(yù)測。
# 擬合一個xgboost模型并進行單步預(yù)測 def xgboost_forecast(train, testX): # 將列表轉(zhuǎn)換為數(shù)組 train = asarray(train) # 分割為輸入和輸出列 trainX, trainy = train[:, :-1], train[:, -1] # 擬合模型 model = XGBRegressor(objective='reg:squarederror', n_estimators=1000) model.fit(trainX, trainy) # 進行單步預(yù)測 yhat = model.predict([testX]) return yhat[0] |
現(xiàn)在我們知道如何為預(yù)測準備時間序列數(shù)據(jù)和評估XGBoost模型。接下來我們看看如何在真實數(shù)據(jù)集上使用XGBoost。
本節(jié)中,我們將探索如何用XGBoost來進行時間序列預(yù)測。
我們使用一個標準的單變量時間序列數(shù)據(jù)集,并計劃使用該模型來進行單步預(yù)測。
你可以使用本節(jié)中的代碼作為你自己項目的出發(fā)點。你可以輕易的將它拓展為多變量輸入,多變量預(yù)測,以及多步預(yù)測。
我們使用每日女性出生數(shù)量數(shù)據(jù)集,包括三年來每個月的出生數(shù)。
你可以在這里下載數(shù)據(jù)集,文件名為 “daily-total-female-births.csv“ ,并放入你當前的工作路徑下。
數(shù)據(jù)集前幾行如下所示:
"Date","Births" "1959-01-01",35 "1959-01-02",32 "1959-01-03",30 "1959-01-04",31 "1959-01-05",44 ... |
首先,我們加載數(shù)據(jù)集并做圖。
完整的例如如下:
# 加載時間序列數(shù)據(jù)集并作圖 from pandas import read_csv from matplotlib import pyplot # 加載數(shù)據(jù)集 series = read_csv('daily-total-female-births.csv', header=0, index_col=0) values = series.values # 為數(shù)據(jù)集作圖 pyplot.plot(values) pyplot.show() |
運行例程,得到數(shù)據(jù)集的線圖。
我們可以看到?jīng)]有明顯的趨勢或季節(jié)性。
每月出生數(shù)時間序列數(shù)據(jù)集線圖
一個基線模型在預(yù)測最近12個月時可以得到6.7出生數(shù)的MAE。這可以作為模型性能的基準。比這更好的模型可以認為是更具備技巧的。
接下來我們通過在數(shù)據(jù)集上使用最近12個月數(shù)據(jù)進行單步預(yù)測來評估XGBoost模型。
我們將只用最近三個時間步作為模型輸入以及默認的模型超參數(shù),輸了我們將損失函數(shù)變?yōu)?‘reg:squarederror‘(避免警報),以及在集成中使用1000個樹(避免欠擬合)。
完整的例子如下:
# 使用xgboost預(yù)測每月出生數(shù) from numpy import asarray from pandas import read_csv from pandas import DataFrame from pandas import concat from sklearn.metrics import mean_absolute_error from xgboost import XGBRegressor from matplotlib import pyplot
# 將時間序列數(shù)據(jù)集轉(zhuǎn)換為監(jiān)督學習數(shù)據(jù)集 def series_to_supervised(data, n_in=1, n_out=1, dropnan=True): n_vars = 1 if type(data) is list else data.shape[1] df = DataFrame(data) cols = list() # 輸入序列 (t-n, ... t-1) for i in range(n_in, 0, -1): cols.append(df.shift(i)) # 預(yù)測序列 (t, t+1, ... t+n) for i in range(0, n_out): cols.append(df.shift(-i)) # 合并 agg = concat(cols, axis=1) # 丟棄 NaN if dropnan: agg.dropna(inplace=True) return agg.values
# 將單變量數(shù)據(jù)集分割為訓(xùn)練/測試數(shù)據(jù)集 def train_test_split(data, n_test): return data[:-n_test, :], data[-n_test:, :] # 擬合xgboost模型并進行單步預(yù)測 def xgboost_forecast(train, testX): # 將列表轉(zhuǎn)換為數(shù)組 train = asarray(train) # 分割為輸入和輸出列 trainX, trainy = train[:, :-1], train[:, -1] # 模型擬合 model = XGBRegressor(objective='reg:squarederror', n_estimators=1000) model.fit(trainX, trainy) # 進行單步預(yù)測 yhat = model.predict(asarray([testX])) return yhat[0]
# 單變量數(shù)據(jù)集的前進式驗證 def walk_forward_validation(data, n_test): predictions = list() # 數(shù)據(jù)集分割 train, test = train_test_split(data, n_test) # 將訓(xùn)練數(shù)據(jù)集填入歷史 history = [x for x in train] # 遍歷測試集中所有時間步 for i in range(len(test)): # 將測試行分割為輸入和輸出列 testX, testy = test[i, :-1], test[i, -1] # 擬合模型并預(yù)測 yhat = xgboost_forecast(history, testX) # 將預(yù)測保存在預(yù)測列表中 predictions.append(yhat) # 為下一循環(huán)將實際觀察加入歷史中 history.append(test[i]) # 過程總結(jié) print('>expected=%.1f, predicted=%.1f' % (testy, yhat)) # 估計預(yù)測誤差 error = mean_absolute_error(test[:, 1], predictions) return error, test[:, 1], predictions # 加載數(shù)據(jù)集 series = read_csv('daily-total-female-births.csv', header=0, index_col=0) values = series.values # 將時間序列數(shù)據(jù)集轉(zhuǎn)換為監(jiān)督學習 data = series_to_supervised(values, n_in=3) # 評估 mae, y, yhat = walk_forward_validation(data, 12) print('MAE: %.3f' % mae) # 作圖 期望 vs 預(yù)測 pyplot.plot(y, label='Expected') pyplot.plot(yhat, label='Predicted') pyplot.legend() pyplot.show() |
訓(xùn)練該例程,得到測試集中每一步的期和預(yù)測值,和所有預(yù)測值的MAE
我們看到模型表現(xiàn)好于基線模型,他的MAE為5.3,好于6.7.
你可以測試不同的XGBoost超參數(shù)和時間步長作為輸入,看看是不是可以活得更好的性能。在評論下分享你的結(jié)果。
>expected=42.0, predicted=48.3 >expected=53.0, predicted=43.0 >expected=39.0, predicted=41.0 >expected=40.0, predicted=34.9 >expected=38.0, predicted=48.9 >expected=44.0, predicted=43.3 >expected=34.0, predicted=43.5 >expected=37.0, predicted=40.1 >expected=52.0, predicted=42.8 >expected=48.0, predicted=37.2 >expected=55.0, predicted=48.6 >expected=50.0, predicted=48.9 MAE: 5.356 |
以下線圖比較了數(shù)據(jù)集中過去12個月期望值和預(yù)測值的序列。
這給我們一種模型在測試集上表現(xiàn)的幾何解讀。
XGBoost中期望vs預(yù)測出生數(shù)的線圖
一旦選擇好XGBoost最終的模型配置,就可以最終確定模型并在新數(shù)據(jù)上做預(yù)測。
這被稱作樣本外預(yù)測,比如,在訓(xùn)練集以外預(yù)測。這和在模型評價時做預(yù)測一樣:因為我們總是想使用和在新數(shù)據(jù)上預(yù)測時同樣的步驟來評估模型。
下面的例子展示了在所有的數(shù)據(jù)上擬合一個最終版的XGBoost模型,并在數(shù)據(jù)集之外做單步預(yù)測。
# 完成模型并使用xgboost為每月出生數(shù)做預(yù)測 from numpy import asarray from pandas import read_csv from pandas import DataFrame from pandas import concat from xgboost import XGBRegressor # 將時間序列數(shù)據(jù)集轉(zhuǎn)換為監(jiān)督學習數(shù)據(jù)集 def series_to_supervised(data, n_in=1, n_out=1, dropnan=True): n_vars = 1 if type(data) is list else data.shape[1] df = DataFrame(data) cols = list() # 輸入序列 (t-n, ... t-1) for i in range(n_in, 0, -1): cols.append(df.shift(i)) # 預(yù)測序列 (t, t+1, ... t+n) for i in range(0, n_out): cols.append(df.shift(-i)) # 合并 agg = concat(cols, axis=1) # 丟棄含有NaN的行 if dropnan: agg.dropna(inplace=True) return agg.values
# 加載數(shù)據(jù)集 series = read_csv('daily-total-female-births.csv', header=0, index_col=0) values = series.values # 將時間序列數(shù)據(jù)轉(zhuǎn)換成監(jiān)督學習 train = series_to_supervised(values, n_in=3) # 分為輸入和輸出列 trainX, trainy = train[:, :-1], train[:, -1] # 擬合模型 model = XGBRegressor(objective='reg:squarederror', n_estimators=1000) model.fit(trainX, trainy) # 為新預(yù)測建立輸入 row = values[-3:].flatten() # 單步預(yù)測 yhat = model.predict(asarray([row])) print('Input: %s, Predicted: %.3f' % (row, yhat[0])) |
運行以上例程,在所有數(shù)據(jù)上擬合XGBoost 模型。
用已知的的過去三個月數(shù)據(jù)作為一行新輸入,來預(yù)測數(shù)據(jù)集之外第一個月的數(shù)據(jù)。
Input: [48 55 50], Predicted: 46.736 |
如果你想再進一步了的話,本節(jié)提供了關(guān)于本主題相關(guān)的更多資料。
相關(guān)教程
A Gentle Introduction to the Gradient Boosting Algorithm for Machine Learning
How to Convert a Time Series to a Supervised Learning Problem in Python
How To Backtest Machine Learning Models for Time Series Forecasting
本教程中,你已經(jīng)發(fā)現(xiàn)了如何為時間序列預(yù)測開發(fā)一個XGBoost模型。
另外,你學習到了:
XGBoost是分類和回歸問題的梯度提升集成算法的實現(xiàn)。
時間序列數(shù)據(jù)集可以通過滑窗表示轉(zhuǎn)換成監(jiān)督學習。
如何使用XGBoost模型對時間序列預(yù)測進行擬合,評估以及預(yù)測。
雷鋒字幕組是由AI愛好者組成的志愿者翻譯團隊;團隊成員有大數(shù)據(jù)專家、算法工程師、圖像處理工程師、產(chǎn)品經(jīng)理、產(chǎn)品運營、IT咨詢?nèi)?、在校師生;志愿者們來自IBM、AVL、Adobe、阿里、百度等知名企業(yè),北大、清華、港大、中科院、南卡羅萊納大學、早稻田大學等海內(nèi)外高校研究所。
了解字幕組請聯(lián)系微信:tlacttlact
轉(zhuǎn)載請聯(lián)系字幕組微信并注明出處:雷鋒字幕組
雷鋒網(wǎng)雷鋒網(wǎng)
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。