字幕組雙語原文:如何使用XGBoost模型進行時間序列預測
英語原文:How to Use XGBoost for Time Series Forecasting
翻譯:雷鋒字幕組(Shangru)
XGBoost是在有效解決分類和迴歸問題的一種梯度提升方法。
在廣泛的預測模型任務中,它快且有效,性能好。它在諸如Kaggle等數據科學競賽的獲勝者中最受歡迎。XGBoost也可以被用於時間序列預測,儘管它需要將時間序列數據集先轉換成監督學習問題。它需要用到一種被稱為前進式驗證的特殊方法來評估模型,因為使用k折驗證來評估模型容易導致偏向樂觀的結果。本教程中,你將探索如何為時間序列預測開發一個XGBoost模型。
完成本教程後,你將瞭解:
XGBoost是對分類和迴歸問題的梯度提升集成算法的實現
時間序列數據集可以通過滑窗表示轉換成監督學習。
如何使用XGBoost模型對時間序列預測進行擬合,評估以及預測
讓我們開始吧
教程總覽
本教程分為三部分。它們是:
XGBoost集成
時間序列數據準備
時間預測中的XGBoost
XGBoost集成
XGBoost是 Extreme Gradient Boosting的縮寫。它是隨機梯度提升機器學習算法的有效實現。
隨機梯度提升算法,也叫做梯度提升機或者提升樹,是一種強大的機器學習技術。他在廣泛的有挑戰性的機器學習問題上有着好的,甚至是最好的表現。
提升樹以及在很多標準分類指標上表現出來最先進的結果
—— XGBoost: A Scalable Tree Boosting System, 2016.
它是一種決策樹集成算法,其中新的樹會去修正模型中已有的樹的誤差。樹會被一直添加進去直到模型表現沒有更多提升。
XGBoost為隨機梯度提升算法,以及為訪問整套模型超參數來控制模型訓練過程提供了一種高效實現。
XGBoost成功的背後最重要的一點是全場景的規模化。該系統運行速度超出現流行的單機方案十倍之上。它在分佈式或者內存有限的設定下,規模可達數十億例。
—— XGBoost: A Scalable Tree Boosting System, 2016.
XGBoost是為表格型數據的分類和迴歸問題設計的,儘管它也可以用於時間序列預測。
關於更多的梯度提升和XGBoost實現,參考下面教程:
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()
時間序列數據準備
時間序列數據可以使用監督學習來表述。
當給定一個時間序列數據集的數字序列,我們可以重新組織數據使之看起來像一個監督學習問題。為了達到這種效果,我們把前幾步的數據作為輸入變量,下一步的作為輸出。
我用一個例子來支持這一點。想象一些我們有如下的時間序列:
time, measure
1, 100
2, 110
3, 108
4, 115
5, 120
我們可以通過前一個時間的值來預測下一個時間的值,從而將該時間序列數據集重組為一個監督學習問題。
如上重組時間序列數據集後,數據看起來像下面這樣:
X, y
?, 100
100, 110
110, 108
108, 115
115, 120
120, ?
注意到時間列被丟棄了,有些行的數據對模型訓練是無用的,比如第一行和最後一行。
這種表述被稱為滑窗,因為輸入窗口和預計輸出是隨着時間向前滑動,從而創建了監督學習模型的新“樣本”。
關於更多關於用滑窗方法準備時間序列預測數據,可以看以下教程:
Time Series Forecasting as Supervised Learning
在給定輸入輸出序列長度時的時間序列問題中,我們使用Pandas中的shift()函數來自動創建窗口。
這是一個很有用的工具,它使得我們在使用機器學習算法時可以使用不同的窗口探索時間序列問題,來找出哪種可能下模型表現更好。
下面這個函數將時間序列作為一個單列或多列的Numpay數組時間序列,並將其轉換成一個特定輸入輸出數量的監督學習問題。
# 將時間序列數據集轉換成監督學習數據集
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))
# 預測序列 (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
我們使用該函數來準備XGBoost的時間序列數據集。
更多關於這個函數的一步步的開發,可以看一下教程
How to Convert a Time Series to a Supervised Learning Problem in Python
一旦數據集準備好了,如何使用它們去擬合和評估模型就要務必仔細。
比如,使用未來的數據擬合模型來預測過去的數據就是無效的。模型應該是在過去的數據上訓練,預測未來。
這意味着在模型評估時,一些隨機化數據集的方法,比如k折交叉驗證,就不能使用了。取而代之地,我們使用一種被稱為前進式驗證的技術。
在前進式驗證中,數據集首先通過選擇分割點,分為訓練集和測試集。比如,除了過去12個月的所有數據被用來訓練,而過去12個月的數據用作測試。
如果我們感興趣的是單步預測,比如,一個月,我們可以通過在訓練集上訓練,在測試集的第一步進行預測。然後我們將測試集中真實的觀察值加入訓練集,重新擬合模型,然後在測試集的第二步上使用該模型預測。
對整個測試集重複該過程,就可以得到整個數據集上的單步預測。基於該預測計算的誤差可以用來評估模型的能力。
關於更多前進式驗證,可以看教程:
How To Backtest Machine Learning Models for Time Series Forecasting
以下函數可處理前進式驗證。
它的參數是整個監督學習版的時間序列數據集和用作測試集的行數。
然後它開始處理測試集,調用 xgboost_forecast()函數來進行單步預測。它會返回計算所得的誤差度量和一些可供分析的細節。
# 單變量數據的前進式驗證
def walk_forward_validation(data, n_test):
predictions = list()
# 分割數據集
train, test = train_test_split(data, n_test)
# 用訓練集中的數據填充歷史
history = [x for x in train]
# 遍歷測試集中的每個時間步
for i in range(len(test)):
# 將測試行分為輸入和輸出列
testX, testy = test[i, :-1], test[i, -1]
# 在歷史數據上擬合模型並做預測
yhat = xgboost_forecast(history, testX)
# 在預測列表中儲存預測
predictions.append(yhat)
# 為下一個循環在歷史中添加真實觀察
history.append(test[i])
# 進度總結
print('>expected=%.1f, predicted=%.1f' % (testy, yhat))
# 估計預測誤差
error = mean_absolute_error(test[:, 1], predictions)
return error, test[:, 1], predictions
調用 train_test_split()將數據集分割成訓練集和測試集
我們定義以下函數
# 將一個單變量數據集分割成訓練/測試集
def train_test_split(data, n_test):
return data[:-n_test, :], data[-n_test:, :]
我們是用XGBRegressor類來進行但不預測。
xgboost_forecast()函數的實現如下,以訓練集和測試輸入行作為輸入,擬合模型,然後進行單步預測。
# 擬合一個xgboost模型並進行單步預測
def xgboost_forecast(train, testX):
# 將列表轉換為數組
train = asarray(train)
# 分割為輸入和輸出列
trainX, trainy = train[:, :-1], train[:, -1]
# 擬合模型
model = XGBRegressor(objective='reg:squarederror', n_estimators=1000)
model.fit(trainX, trainy)
# 進行單步預測
yhat = model.predict([testX])
return yhat[0]
現在我們知道如何為預測準備時間序列數據和評估XGBoost模型。接下來我們看看如何在真實數據集上使用XGBoost。
時間序列預測中的XGBoost
本節中,我們將探索如何用XGBoost來進行時間序列預測。
我們使用一個標準的單變量時間序列數據集,並計劃使用該模型來進行單步預測。
你可以使用本節中的代碼作為你自己項目的出發點。你可以輕易的將它拓展為多變量輸入,多變量預測,以及多步預測。
我們使用每日女性出生數量數據集,包括三年來每個月的出生數。
你可以在這裏下載數據集,文件名為 “daily-total-female-births.csv“ ,並放入你當前的工作路徑下。
數據集 (daily-total-female-births.csv)
描述 (daily-total-female-births.names)
數據集前幾行如下所示:
"Date","Births"
"1959-01-01",35
"1959-01-02",32
"1959-01-03",30
"1959-01-04",31
"1959-01-05",44
...
首先,我們加載數據集並做圖。
完整的例如如下:
# 加載時間序列數據集並作圖
from pandas import read_csv
from matplotlib import pyplot
# 加載數據集
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# 為數據集作圖
pyplot.plot(values)
pyplot.show()
運行例程,得到數據集的線圖。
我們可以看到沒有明顯的趨勢或季節性。
每月出生數時間序列數據集線圖
一個基線模型在預測最近12個月時可以得到6.7出生數的MAE。這可以作為模型性能的基準。比這更好的模型可以認為是更具備技巧的。
接下來我們通過在數據集上使用最近12個月數據進行單步預測來評估XGBoost模型。
我們將只用最近三個時間步作為模型輸入以及默認的模型超參數,輸了我們將損失函數變為 ‘reg:squarederror‘(避免警報),以及在集成中使用1000個樹(避免欠擬合)。
完整的例子如下:
# 使用xgboost預測每月出生數
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
# 將時間序列數據集轉換為監督學習數據集
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))
# 預測序列 (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
# 將單變量數據集分割為訓練/測試數據集
def train_test_split(data, n_test):
return data[:-n_test, :], data[-n_test:, :]
# 擬合xgboost模型並進行單步預測
def xgboost_forecast(train, testX):
# 將列表轉換為數組
train = asarray(train)
# 分割為輸入和輸出列
trainX, trainy = train[:, :-1], train[:, -1]
# 模型擬合
model = XGBRegressor(objective='reg:squarederror', n_estimators=1000)
model.fit(trainX, trainy)
# 進行單步預測
yhat = model.predict(asarray([testX]))
return yhat[0]
# 單變量數據集的前進式驗證
def walk_forward_validation(data, n_test):
predictions = list()
# 數據集分割
train, test = train_test_split(data, n_test)
# 將訓練數據集填入歷史
history = [x for x in train]
# 遍歷測試集中所有時間步
for i in range(len(test)):
# 將測試行分割為輸入和輸出列
testX, testy = test[i, :-1], test[i, -1]
# 擬合模型並預測
yhat = xgboost_forecast(history, testX)
# 將預測保存在預測列表中
predictions.append(yhat)
# 為下一循環將實際觀察加入歷史中
history.append(test[i])
# 過程總結
print('>expected=%.1f, predicted=%.1f' % (testy, yhat))
# 估計預測誤差
error = mean_absolute_error(test[:, 1], predictions)
return error, test[:, 1], predictions
# 加載數據集
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# 將時間序列數據集轉換為監督學習
data = series_to_supervised(values, n_in=3)
# 評估
mae, y, yhat = walk_forward_validation(data, 12)
print('MAE: %.3f' % mae)
# 作圖 期望 vs 預測
pyplot.plot(y, label='Expected')
pyplot.plot(yhat, label='Predicted')
pyplot.legend()
pyplot.show()
訓練該例程,得到測試集中每一步的期和預測值,和所有預測值的MAE
我們看到模型表現好於基線模型,他的MAE為5.3,好於6.7.
你能做更好嗎?
你可以測試不同的XGBoost超參數和時間步長作為輸入,看看是不是可以活得更好的性能。在評論下分享你的結果。
>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
以下線圖比較了數據集中過去12個月期望值和預測值的序列。
這給我們一種模型在測試集上表現的幾何解讀。
XGBoost中期望vs預測出生數的線圖
一旦選擇好XGBoost最終的模型配置,就可以最終確定模型並在新數據上做預測。
這被稱作樣本外預測,比如,在訓練集以外預測。這和在模型評價時做預測一樣:因為我們總是想使用和在新數據上預測時同樣的步驟來評估模型。
下面的例子展示了在所有的數據上擬合一個最終版的XGBoost模型,並在數據集之外做單步預測。
# 完成模型並使用xgboost為每月出生數做預測
from numpy import asarray
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from xgboost import XGBRegressor
# 將時間序列數據集轉換為監督學習數據集
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))
# 預測序列 (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
# 加載數據集
series = read_csv('daily-total-female-births.csv', header=0, index_col=0)
values = series.values
# 將時間序列數據轉換成監督學習
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)
# 為新預測建立輸入
row = values[-3:].flatten()
# 單步預測
yhat = model.predict(asarray([row]))
print('Input: %s, Predicted: %.3f' % (row, yhat[0]))
運行以上例程,在所有數據上擬合XGBoost 模型。
用已知的的過去三個月數據作為一行新輸入,來預測數據集之外第一個月的數據。
Input: [48 55 50], Predicted: 46.736 延伸閲讀
如果你想再進一步了的話,本節提供了關於本主題相關的更多資料。
相關教程
A Gentle Introduction to the Gradient Boosting Algorithm for Machine Learning
Time Series Forecasting as Supervised Learning
How to Convert a Time Series to a Supervised Learning Problem in Python
How To Backtest Machine Learning Models for Time Series Forecasting
小結
本教程中,你已經發現瞭如何為時間序列預測開發一個XGBoost模型。
另外,你學習到了:
XGBoost是分類和迴歸問題的梯度提升集成算法的實現。
時間序列數據集可以通過滑窗表示轉換成監督學習。
如何使用XGBoost模型對時間序列預測進行擬合,評估以及預測。
雷鋒字幕組是由AI愛好者組成的志願者翻譯團隊;團隊成員有大數據專家、算法工程師、圖像處理工程師、產品經理、產品運營、IT諮詢人、在校師生;志願者們來自IBM、AVL、Adobe、阿里、百度等知名企業,北大、清華、港大、中科院、南卡羅萊納大學、早稻田大學等海內外高校研究所。
【來源:雷鋒網】
聲明:轉載此文是出於傳遞更多信息之目的。若有來源標註錯誤或侵犯了您的合法權益,請作者持權屬證明與本網聯繫,我們將及時更正、刪除,謝謝。 郵箱地址:[email protected]