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