XGBoost:股价预测进阶

2019-11-22 09:04:35 浏览数 (1)

前言

公众号之前发表过一篇文章:

严谨解决5种机器学习算法在预测股价的应用(代码 数据)

我们已经对XGBoost进行了验证,但在本文中,我们将更详细地研究XGBoost在股票价格预测问题中的性能。这篇文章和上篇文章的主要区别如下:

1、在上篇文章中,我们只预测了1天,本篇文章中我们预测了未来21天(大约一个月)。为此,我们使用了一种称为递归预测的技术。

2、在上篇文章中,我们使用了一个简单的训练-验证-测试,本篇文章中我们使用了移动窗口验证的方法来执行超参数调优。

3、在上篇文章中,我们只使用前N天的价格作为特征,但是在这里,我们引入了更多的特征。

数据准备

我们的目标是预测Vanguard Total Stock Market ETF(VTI)的每日复权收盘价,使用前N天的数据。在这个例子中,我们将使用VTI在2013-01-02到2018-12-28这6年的历史价格,数据集如下:

收盘价

为了有效地评估XGBoost的性能,仅在一个日期运行一个预测是不够的。相反,我们将在此数据集中的不同日期执行各种预测,并对结果进行平均。

为了评估我们的方法的有效性,我们将使用均方根误差(RMSE),平均绝对百分比误差(MAPE)和平均绝对误差(MAE)指标。对于所有指标,值越低,预测效果越好。与上一篇文章类似,我们将使用Last Value方法来对结果进行基准测试。

探索性数据分析(EDA)

EDA是机器学习项目的重要组成部分,它可以帮助我们获得对数据集的良好“感知”。正如我们将在下面看到的,EDA过程涉及到创建可视化来帮助大家更好地理解数据集。

下图显示了每个月复权收盘价法人均值。可以根据数据集推断,就平均值而言,后几个月的值比前几个月的值高。

下面的图显示了该月复权收盘价每一天均值。平均而言,有一个向上倾斜的趋势,即月底的价格高于前几天。

下面的图显示了一周中收盘价每一天均值。平均而言,复权后的周四和周五收盘价高于一周中的其它日期。

下面的热力图显示了经复权后的前几日收盘价与当日收盘价的相关性。很明显,经复权后的收盘价越接近当日,它们之间的相关性就越高。因此,在预测中应该使用与前10天复权收盘价相关的特征。

基于上面的EDA,我们推断与日期相关的特征可能对模型有帮助。此外,复权后的前10天收盘价与目标变量高度相关。这些都是我们将用于下面的特征工程的重要信息。

特征工程

特征工程是一个创造性的过程,是任何机器学习项目中最重要的部分之一。为了强调特征工程的重要性,Andrew Ng有一句很好的名言值得分享:

Coming up with features is difficult, time-consuming, requires expert knowledge. “Applied machine learning” is basically feature engineering.

Andrew Ng, Machine Learning and AI via Brain simulations

在本文中,我们将生成以下特征:

1、过去10天的复权收盘价

2、year 3、month 4、week 5、dayofmonth 6、dayofweek 7、dayofyear 8、is_month_end 9、is_month_start 10、is_quarter_end 11、is_quarter_start 12、is_year_end 13、is_year_start

使用fastai包很容易生成与日期相关的特征,比如:

代码语言:javascript复制
from fastai.tabular import add_datepart

add_datepart(df, 'date', drop=False)
df.drop('Elapsed', axis=1, inplace=True)

使用上面的代码后,dataframe看起来如下所示。 列adj_close将是目标列。为简洁起见,我们省略了过去N天调整后的收盘价的相关信息。

下面的热力图显示了这些特征与目标列之间的相关性。特征year与复权收盘价格高度相关。这并不奇怪,因为在我们的数据集中,有一个向上倾斜的趋势,年份越大,复权收盘价越高。其他特征与目标变量没有高度的相关性。从下面,我们还发现,is_year_start有空值。这是因为每年中的第一天从来都不是交易日,所以我们从模型中移除了这个特征。

下面的条形图,显示了前10个最重要特征的重要性得分。这是对2017-01-03的预测得到的,而其他日期的预测对特征重要性的排名可能不同。正如预期的那样,复权的前一天收盘价格是最重要的特征。

训练、验证和测试

要进行预测,我们需要训练和验证数据。我们将使用3年的数据作为训练集,这相当于756天,因为一年中大约有252个交易日(252*3 = 756)。我们将使用接下来1年的数据来执行验证,相当于252天。换句话说,对于做出的每个预测,我们需要756 252 = 1008天的数据来进行模型训练和验证。模型将使用训练集进行训练,而模型超参数将使用验证集进行调优。要调优超参数,我们将使用移动窗口验证方法。

下面举例说明了训练规模为756天、验证规模为40天和预测周期为40天的情况。

在时间序列预测中,训练、验证、策略必须按时序进行,这一点非常重要!如果不按照此流程去做,将导致模型中的“信息泄漏”。

接下来,我们将使用XGBoost在我们的测试集中进行几天的预测,即:

2017–01–03、2017–03–06、2017–05–04、2017–07–05、2017–09–01、2017–11–01、2018–01–03、2018–03–06、2018–05–04、2018–07–05、2018–09–04、2018–11–01

对于上述12个预测,我们将使用21天的预测周期。我们将使用紧接预测日期之前的1008天作为训练和验证集(756:252)。

特征缩放

特征缩放在这里很重要,因为,如果你看上面的复权收盘价,按时间顺序分割的训练和测试集几乎总是会导复权收盘价格比训练价格更高。 具体看这篇文章:严谨解决5种机器学习算法在预测股价的应用(代码 数据)

对每个样本复权收盘价的每个特征组,我们将其缩放为均值0和方差1。例如,如果我们对第T天进行预测,我们将采用最近N天(从第T天到第T天)的复权收盘价,并将其调整为均值0和方差1。在训练、验证和测试集上对滞后特征执行相同的操作。日期特征没有缩放。然后我们使用这些比例lag特征和日期特征来进行预测。预测值也将被缩放,然后我们使用它们相应的均值和方差对它们进行逆变换。

超参数调整

我们在验证集上执行超参数调优。对于XGBoost,有几个超参数可以调优,包括n_estimators、max_depth、learning_rate、min_child_weight、subsample、gamma、colsample_bytree和colsample_bylevel。有关这些超参数的定义,请参见这里:

https://xgboost.readthedocs.io/en/latest/python/python_api.html#module-xgboost.sklearn

要查看超参数调优的有效性,我们可以查看验证集对2018-11-01年的预测。下面显示的预测没有超参数调优,我们只是使用了包中的默认值:

下面显示了在超参数调优之后在相同验证集上的预测。你可以看到1月18日的预测更加稳定了。

调优前后的超参数:

显然,调优后的超参数与默认值有很大不同。此外,在对验证的RMSE、MAPE和MAE进行调优之后,验证结果如预期一样下降。例如,RMSE从3.395下降到2.984。

模型应用

在执行了上述的步骤后,我们现在准备在测试集上执行预测。在这种情况下,我们的预测周期是21天,这意味着我们需要为每个预测生成21个预测。我们不能一次生成所有21个预测,因为在生成第T天的预测之后,我们需要将这个预测反馈到我们的模型中,以生成第T 1天的预测,以此类推,直到我们得到所有21个预测。这就是所谓的递归预测。因此,我们实现了如下流程图的逻辑:

对于预测范围内的每一天,我们需要预测,取消预测的规模,计算最后N个值的新平均值和标准偏差,调整最近N天的收盘价,然后再次预测。

结果

下面显示了每个预测的RMSE、MAPE和MAE,以及使用各自验证集调整的相应最佳超参数。

使用移动窗口验证方法在测试集上应用 XGBoost 的结果如下所示:

另一种可视化预测的方法是将每个预测与其实际值绘制图。如果我们预测的完美,每个预测应该在对角线 y=x 线上。

最后,以下是我们的模型对照Last Value方法得出的结果:

与Last Value方法相比,使用带有或不带有日期特征的XGBoost可以获得更好的性能。有趣的是,省略日期特征比包含日期特征(2.32 vs. 2.42)得到的RMSE稍微低一些。正如我们前面发现的,日期特征与目标变量的相关性很低,并且可能对模型没有太大帮助。

部分代码展示

由于代码太多,只展示部分,获取全部见文末:

0 人点赞