XGBoost模型应用:构建苹果、亚马逊、Netflix、Nvidia和微软投资组合的交易策略
摘要

XGBoost 被称作奇迹制造者,它是机器学习爱好者以及比赛获胜者所选择的武器。据悉,开发 XGBoost 的目的是提升计算速度并优化模型性能。
我们在对 XGBoost 的特性和参数进行修改的时候,决定构建一个包含 5 家公司的投资组合,接着在这个投资组合上运用 XGBoost 模型,以此来创建一个交易策略。这 5 家公司分别是:苹果,也就是 Apple;亚马逊,即 Amazon;Netflix;Nvidia;以及微软,即 Microsoft。
目录什么是XGBoost
XGBoost 被称作极限梯度提升,它是在梯度提升框架下研发出来的。其名字的含义就是极限梯度提升算法。实际上,它给人的感觉更像是一辆超级跑车,而非机器学习的模型。
但这正是它所做的,提高了普通梯度提升模型的性能。
XGBoost 的作者陈天奇表示:“XGBoost 运用了更为规范的模型形式化方式,以此来对过度拟合进行控制,正因如此,它具备了更优良的性能。”
让我们分析一下这个名称,以了解 XGBoost 的功能。
什么是提升?
顺序集合方法创建了一系列模型,这种方法也被称为“增强”。这些模型试图在序列中纠正之前模型的错误。第一个模型是基于训练数据建立的。第二个模型对第一个模型进行了改进。第三个模型又对第二个模型进行了改进,以此类推。
在上述图像示例里,训练数据集被给到了分类器 1。黄色背景意味着分类器预测连字符,蓝色背景意味着分类器预测正。分类器 1 模型错误地对两个连字符和一个加号进行了预测。这些被圆圈突出显示出来。这些不正确的预测数据点的权重增大了,然后被发送到了下一个分类器,也就是分类器 2。分类器 2 正确地预测了分类器 1 无法预测的两个连字符。但是分类器 2 会引发一些别的错误。此过程仍在持续推进,我们拥有一个组合的最终分类器,它能够准确地对所有数据点进行预测。
可以添加分类器模型,直至能够正确预测训练数据集中的所有项目,或者添加到最大数量的分类器模型。通过超参数整定,能够确定训练分类器模型的最佳最大数目。
在这里稍作停顿。或许你并不知晓什么叫做“连续模型”。接着我们将会对其展开介绍。
简而言之就是机器学习
早些时候,我们编写某种逻辑,接着把输入输入到计算机程序里。程序会运用逻辑(也就是算法并给出输出)。这些都很不错,然而随着我们理解的提升,程序也在进步,直到我们察觉到,对于某些问题陈述来说,需要编程的参数太多了。
一些聪明人表示,我们应当仅仅给计算机(机器)提供问题以及解决方案的样本集,接着让机器进行学习。
在开发机器学习算法时,我们察觉到可以把机器学习问题大致划分成两类,分别是分类和回归。简单来讲,当给出一张动物的照片时,我们会尝试把它归为狗或猫(或其他某种动物),这就是分类问题。而如果要预测一个城市的温度,那就是回归问题,因为温度可以说是具有连续的数值,像 40 度、40.1 度等。
接着我们接着探讨决策树模型、贝叶斯以及聚类模型等。这些内容都很不错,然而当我们碰到另一个阻碍时,当仅使用一个模型时,某些问题陈述的预测率是让人失望的。并且,对于决策树,我们察觉到自己不得不承受模型里的偏差、方差和噪声。这引出了一个新的好想法,我们来探讨一下把模型结合起来吧。正所谓三个普通人的智慧合起来,能抵得上一个聪明人的智慧。这就是所谓的集成学习。不过在此处,我们能够运用多个模型去创建一个集合。而梯度提升就是这样一种集成学习的方式。
什么是梯度提升?
在组合模型的梯度提升过程中,通过梯度下降法来让损失函数达到最小。从技术层面来讲,损失函数可以被理解为一个误差,也就是预测值与实际值之间的差值。毫无疑问,误差越小,意味着机器学习模型就越好。
梯度提升是一种创建新模型的方式。这种新模型会预测先前模型的残差或误差。接着,会将这些残差或误差加在一起,以进行最终的预测。
XGBoost 模型的目标如下:
Obj = L + Ω
其中,L 起到控制预测功率的作用,它是一个损耗函数;Ω 则用于控制简单性以及过拟合情况,它是一个正则分量。
用于多类分类的 mlogloss 可以是需要优化的损失函数(L)。
正则化分量(Ω)与分配给叶片的预测得分有关。
称之为梯度提升,是因为运用了梯度下降法算法,这样在添加新模型时能将损失降到最低。梯度提升算法对回归和分类预测建模问题都予以支持。
如果你想了解梯度下降法,你可以在这里阅读。
我们已经理解了机器学习从简单模型演变为模型组合的过程。不知为何,人类不会一直满足。随着问题陈述愈发复杂,数据集越来越大,我们意识到应该更上一层楼。这使我们找到了 XGBoost。
为什么 XGBoost 这么好?
XgBoost 是由 C++编写而成的。仔细思量,它的计算速度极为迅速。XGBoost 的优势在于能够轻松地导入到 python 中,并且因为有 sklearn 包装器,我们能够使用在 python 包中所采用的相同参数名称。
xgost 的一个主要特点是它能够并行化助推算法的树构建组件,尽管实际的逻辑解释起来有些冗长。这使得处理时间显著增加,因为我们可以利用更多的 CPU 核心,甚至还能继续使用云计算。
机器学习算法支持调优且能与外部程序协同工作,而 XgBoost 具备内置的规则化及交叉验证参数,这样能保证偏差和方差处于最小值。其内置参数的优势在于能够更迅速地达成目标。
Xgost 特性的重要性
简而言之,特征是用于预测目标变量的那些变量。有时,我们不只是想知道我们的机器学习模型有多好。我想知晓哪个特征具备更强的预测能力。知晓特征重要性能对我们有帮助,原因有很多。让我们罗列以下几点:
XGBoost 的好处在于它具备一个内置函数,能够用于计算特性的重要性,这样我们就无需为在模型中编写代码而担忧。在 XGBoost 的 python 代码部分之后,将要使用的示例代码如下:
使用 xgboost 可以进行绘制重要性的操作。
# Plot feature importance
plot_importance(model)
让我们在继续讨论代码之前,先确保我们的系统上都有 XGBoost。
如何在Anaconda中安装 XGBoost?
Anaconda 是一种 Python 环境。它能让我们编写 python 代码变得极为简单。同时,它还可以处理与代码相关的所有细节。正因如此,我明确了在阿纳康达中安装 XgBoost 的步骤。实际上,这些步骤仅仅是一行代码。
您可以打开 Anaconda 提示符,然后进行如下操作:输入 pip install XGBoost 。
Anaconda 环境将下载所需的安装文件并为您安装它。
这是全部的内容。现在我们开始查看真实的事物,也就是 XGBoost 的 Python 代码。
Python中的XGBoost
在开始深入研究 XGBoost 机器学习模型之前,让我先来做一个总结。我们运用了美国科技股的股票数据,像苹果、亚马逊、Netflix、Nvidia 和微软等,这些数据是过去 16 年的。我们利用这些数据来训练 XGBoost 模型,目的是预测第二天的回报是正面还是负面。
这些代码以可下载的 python 笔记本形式呈现,供您后续使用,它附在文章末尾。为便于更好地理解模型,我们把 XGBoost python 代码划分成以下几个部分:
导入库
我们在评论中对这个库的用法进行了介绍。比如,由于我们采用了 XGBoost python 库,所以我们会导入相同的代码,并把 # Import XGBoost 当作注释写进去。
导入警告并添加一个过滤器来忽略它们。
import warnings
执行简单过滤操作并忽略警告。
# Import XGBoost
import xgboost
# XGBoost Classifier
使用 XGBClassifier 是从 xgboost 库中导入的。
分类报告和混淆矩阵。分类报告用于展示不同类别样本的分类情况,包括准确率、召回率等指标。混淆矩阵则直观地呈现了预测结果与真实标签之间的对应关系,通过它可以清晰地看到各类别样本被误分类的情况。
在 sklearn.metrics 中包含了 classification_report 这个东西。
在 sklearn.metrics 这个库中包含了混淆矩阵相关的功能,其中有一个名为 confusion_matrix 的函数或方法。
# Cross validation
使用 sklearn 库中的 model_selection 模块来导入 KFold 类。
在 sklearn 模型选择模块中,可以获取交叉验证得分
使用 Pandas datareader 来获取数据。
从 pandas_datareader 中可以获取数据。
# To plot the graphs
引入 matplotlib 库的绘图模块 plt 。
import seaborn as sn
# For data manipulation
import pandas as pd
import numpy as np
到这一步,所有的库都已经导入。现在我们进入下一环节。
定义参数
我们已经定义了股票清单,开始日期和结束日期:
# Set the stock list
stock_list 包含 'AAPL' ,包含 'AMZN' ,包含 'NFLX' ,包含 'NVDA' ,包含 'MSFT' 。
设置起始日期和结束日期。
start_date = '2004-1-1'
end_date = '2020-1-28'
为了让事情变得有趣,我们会在苹果、亚马逊、Netflix、Nvidia 和 Microsoft 等公司上运用 XGBoost Python 模型。接着创建预测变量以及目标变量。
我们定义了一个预测指标的列表。这个列表将会从自身当中选择出最佳的预测指标。在此处,我们拥有以不同的时间段作为预测变量的百分比变化以及标准偏差。
您还可以尝试使用三个标签(像 1、0 和-1 那样)来创建目标变量,并且无需考虑位置和短职位。
让我们立即查看代码。
创建一个用于存储股票数据的占位符。
stock_data_dictionary = {}
for stock_name in stock_list:
# Get the data
df 等于 data 获取数据 yahoo 时传入股票名称、开始日期和结束日期所得到的结果
计算每日的百分比变化。
df 中的['daily_pct_change']等于 df 中的['Adj Close']进行 pct_change()操作
# create the predictors
predictor_list = []
for r in range(10, 60, 5):
该新列的值是 df 的 daily_pct_change 列进行滚动求和操作,滚动窗口大小为 r
df 中的['std_'+str(r)]这一列,是通过 df 的 daily_pct_change 这一列进行滚动计算得到的,滚动窗口大小为 r,计算的是滚动标准差,即 df.daily_pct_change.rolling(r).std()
predictor_list 会添加 'pct_change_' 加上字符串形式的 r 这个元素。
predictor_list 被添加了 'std_' 加上字符串形式的 r
# Target Variable
df 中的 daily_pct_change 进行 shift(-1)操作后赋值给 df['return_next_day']
如果 df.return_next_day 大于 0,那么 df['actual_signal'] 等于 1;否则,df['actual_signal'] 等于 -1。
df = df.dropna()
# Add the data to dictionary
stock_data_dictionary 会将 {stock_name: df} 进行更新。 即把 df 与 stock_name 组成的键值对更新到 stock_data_dictionary 中。 它实现了对 stock_data_dictionary 中特定 stock_name 对应数据的更新操作,将 df 赋予该 stock_name 。
在继续讨论 XGBoost python 模型的实现之前,我们首先来绘制存储在字典里的 Apple 的每日返回值,查看是否一切正常。
# Set the figure size
plt.figure(figsize=(10, 7))
从字典中访问 AAPL 的数据框。
然后计算并绘制收益。
先获取 stock_data_dictionary 中 'AAPL' 的 daily_pct_change,将其加 1 后,再进行 cumprod 操作,最后对结果进行 plot 绘制。
设置标题,设置轴标签,绘制网格。
plt.title('AAPL Returns')
plt 的 y 轴标签为“累积回报率”
plt.grid()
plt.show()
您将得到如下输出:
看起来很精确。
将数据分割成训练集和测试集
XGBoost 毕竟是一个机器学习模型,所以我们要把数据集划分成测试集和训练集。
创建用于训练和测试分割数据的占位符。
X_train = pd.DataFrame()
X_test = pd.DataFrame()
y_train = pd.Series()
y_test = pd.Series()
for stock_name in stock_list:
# Get predictor variables
X 等于 stock_data_dictionary 中 stock_name 对应的部分以及 predictor_list 对应的部分
# Get the target variable
y 等于 stock_data_dictionary 中 stock_name 对应的 actual_signal
将数据集划分成训练集和测试集。
获取 X 的长度,将其乘以 0.80 后取整得到 train_length 的值。
X_train 进行了添加操作,添加的内容是 X 中从开始到 train_length 位置的部分,即 X_train 被添加了 X[:train_length] 。
X_test 会将 X 中从 train_length 位置开始到末尾的部分添加进来。即 X_test 等于 X_test 加上 X 中从 train_length 位置开始到末尾的部分。
y_train 进行了一个操作,这个操作是将 y 中从开始到 train_length 位置的部分添加进去,最终结果是 y_train 被更新了,即 y_train 等于原来的 y_train 加上 y 中从开始到 train_length 位置的部分。
y_test 进行了追加操作,追加的内容是 y 中从 train_length 位置开始到末尾的部分。即 y_test 等于原来的 y_test 再加上 y 中从 train_length 位置开始到末尾的这部分数据。
初始化 XGBoost 机器学习模型
我们会初始化分类器模型。接着,我们会设置两个超参数,一个是 max_deep,另一个是 n_估计量。并且这些超参数都被设置在较低的水平,目的是为了减少过拟合现象。
初始化模型并设置超参数值。
XGBClassifier 的最大深度为 2,估计器数量为 30,其模型为 model
model
输出如下:
训练数据集的交叉验证
初始化 KFold 的参数。首先确定要进行交叉验证的折数,例如设置为 5 折。然后可以指定随机种子,以确保每次运行时的随机性是可重复的。还可以选择是否打乱数据顺序等其他相关参数的设置。
定义了一个 KFold 对象,其 n_splits 参数被设置为 5,random_state 参数被设置为 7
进行 K 折交叉验证。具体来说,就是将数据集划分成 K 个互不相交的子集,然后每次用其中一个子集作为验证集,其余 K - 1 个子集作为训练集进行模型训练和评估,如此重复 K 次,最后综合各个验证集的评估结果来对模型进行评价和调优。
使用模型对训练数据进行交叉验证评分,其中模型为 model,训练数据的特征为 X_train,训练数据的标签为 y_train,交叉验证的折数为 kfold,得到的结果赋值给 results 。
# Print the average results
打印("准确率: %.2f%% (%.2f%%)" % (结果.mean()*100, 结果.std()*100))
产出如下:
准确度比半数稍微高一些。通过调整超参数以及把相似的股票组合到一起,能够进一步对其进行改进。
训练模型
我们将使用拟合方法训练 XGBoost 分类器。
# 符合模型
model.fit(X_train, y_train)
输出如下:
特征重要性
我们已经绘制了前7个特性,并根据其重要性进行了排序。
# Plot the top 7 features
使用 xgboost 绘制重要性图,传入的模型为 model,设置最多显示的特征数量为 7
# Show the plot
plt.show()
XGBoost 的 python 模型向我们表明,pct_change_40 在其他模型里是最为重要的特性。由于我们提及只需 7 个特性,所以我们得到了这个列表。这里有个有趣的想法,你为何不增加这个数字,看看其他功能在谈及它们的 f 值时是如何叠加的呢?你还可以删除不重要的特性,之后再重新训练模型。这会提高模型的准确性吗?我留给你去验证。
预测和分类报告
预测测试数据集上的交易信号。
模型对 X_test 进行预测,得到的结果是 y_pred 。
获取分类报告。
打印分类报告(y_test,y_pred)。
让我们看看 XGBoost 现在告诉我们什么:
长边的 f1 得分比短边的得分要强大很多。我们能够对这个模型进行修改,让它变成一个只专注于长线的策略。
让我们尝试另一种方法来表述 XGBoost 的执行情况。
混合矩阵
array 是通过计算 y_test 和 y_pred 得到的混淆矩阵。
df 是一个数据框,它由一个数组 array 构成,这个数据框的行索引为['Short', 'Long'],列索引为[ ]。
'Short', 'Long'])
plt.figure(figsize=(5, 4))
使用 sn.heatmap 函数绘制热力图,传入参数 df,设置 annot 为 True,cmap 为 'Greens',fmt 为 'g'
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
输出如下图所示:
这是一个简单的矩阵。它向我们展示了 XGBoost 预测“买入”或“卖出”准确与否的情况。比如,在预测“Long”时,XGBoost 正确预测的次数为 1926 次,错误预测的次数为 1608 次。
另一种解释为,XGBoost 更倾向于对“长期”进行预测,而相对较少地对“短期”进行预测。
个股表现
让我们来看一看基于 XGBoost 的策略收益率与正常的日收益率(买入并持有策略)相比是怎样的情况。我们要绘制一张比较图,把之前提到的所有公司的战略收益和日收益进行对比。代码如下:
创建一个空的数据框,用于存储单个股票的策略收益。
创建了一个名为 portfolio 的数据框,其列名为 stock_list 。
对于股票列表中的每一只股票,分别绘制策略收益和买入并持有收益的图表。
for stock_name in stock_list:
# Get the data
df 等于 stock_data_dictionary 中关于 stock_name 的内容。
将预测变量存储在 X 中。
X = df[predictor_list]
对训练数据集与测试数据集进行定义。
train_length = int(len(X)*0.80)
预测信号并将其存储在预测信号列中。
模型对 X 进行预测,然后将预测结果赋值给 df 中的 predicted_signal 列。
计算策略的收益。
df 的['strategy_returns']等于 df 的 return_next_day 乘以 df 的 predicted_signal
将策略收益添加到投资组合数据框中。
portfolio 中股票名称为[stock_name]的部分等于 df 的策略收益中从训练长度之后的部分
绘制股票策略以及买入并持有收益。
print(stock_name)
# Set the figure size
plt.figure(figsize=(10, 7))
计算累积策略收益并进行绘制。
在 train_length 之后的 df.strategy_returns 进行累加操作,然后再加 1,接着进行累积乘积操作,最后对累积乘积的结果进行绘图操作。
计算累积的买入并持有策略收益。
使用 stock_data_dictionary 中 stock_name 对应的股票数据,从 train_length 位置开始到末尾的 daily_pct_change 数据加上 1,然后对其进行累积乘积操作,最后绘制出累积乘积后的结果图。
设置网格。
plt 给(stock_name + ' Returns')设置标题
plt.ylabel('Cumulative Returns')
plt 有一个 legend 函数,这个函数的 labels 参数被设置为['Strategy Returns', 'Buy and Hold Returns']
plt.grid()
plt.show()
你觉得这个比较怎么样?请在评论中告诉小Q你的观点或想法~
投资组合表现
我们很享受这个过程,所以不能停留在主观层面。我们认为,若平等地投资于所有公司,且依据 XGBoost Python 模型采取行动,就会产生意想不到的效果。
# Drop missing values
将 portfolio 中的缺失值删除,设置 inplace=True 以在原数据上进行修改
# Set the figure size
plt.figure(figsize=(10, 7))
假设对股票进行等额分配,来计算投资组合的累计收益。
将 portfolio 的均值(沿着轴 1 进行计算)再加上 1,然后对其进行累积乘积操作,最后绘制出相应的图形。
设置图表的标题和标签。
plt 给图形设置标题为“Portfolio Strategy Returns”
plt.ylabel('Cumulative Returns')
plt.grid()
plt.show()
请记住,这些是累积回报。所以,它能够给您一个关于 XGBoost 模型性能的概念。
如果需要关于测试集的更详细的反馈,请尝试以下代码。
import pyfolio as pf
使用 pf 创建完整的资产负债表,该资产负债表是 portfolio 的平均值(沿着轴 1 进行计算)。
虽然生成的输出有些冗长,但我们附加了一个快照方便阅读:
能看到这里的都很勇敢!小 Q 认为你一定可以理解像 XGBoost 这样的增强型模型是怎样帮助我们生成信号以及创建交易策略的。
结论
我们从基础开始,这里的基础指的是机器学习算法的出现及其下一个层次,即集成学习。我们学习了梯度提升树,接着了解了它们在做出更好预测方面所起的作用。最后,我们得到了 XGBoost 机器学习模型,并且明白了它在哪些方面优于常规的增强算法。我们首先浏览了一个简单的 XGBoost python 代码。接着,依据该代码所创建的交易信号,我们创建了一个投资组合。在这个过程中,我们列出了 XGBoost 中所包含的特性重要性以及某些参数。