如何使用XGBoost模型进行时间序列预测
- 2020 年 8 月 17 日
- AI
字幕组双语原文:如何使用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“ ,并放入你当前的工作路径下。
数据集前几行如下所示:
“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
-
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、阿里、百度等知名企业,北大、清华、港大、中科院、南卡罗莱纳大学、早稻田大学等海内外高校研究所。
了解字幕组请联系微信:tlacttlact
转载请联系字幕组微信并注明出处:雷锋字幕组
雷锋网雷锋网