XGBoost 演算法预测报酬(下)

xgboost
Photo Credits: Unsplash

本文重点概要

  • 文章难度:★★★★☆
  • 资料前处理
  • XGBoost 模型设定

前言

上一篇讲解了如何创立新环境并安装模组 XGBoost,环境的设定是基础,一开始出问题的话,后面会有许多奇奇怪怪的 Error,如果还没看过上一篇的话,可以点这这里,这一篇我们要对资料做一些处理,完成后再带入模型里让机器去学习,学习后可以去预测未来的报酬,也可以看哪一个因子对预测是最有效果的!

编辑环境及模组需求

本文使用 Mac OS 并以 Jupyter Notebook 作为编辑器

# basic
import numpy as np
import pandas as pd
# graphy
import matplotlib.pyplot as plt
%matplotlib inline
# machine learning
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
import xgboost as xgb
# TEJ
import tejapi
tejapi.ApiConfig.api_key = "Your Key"
tejapi.ApiConfig.ignoretz = True

资料库使用

资料前处理

我们会使用 2000~2015的所有上市柜公司的投资因子,用以预测2016~2017 月报酬率为正或是负。

df = tejapi.get('TWN/AFF_RAW',
                mdate={'gte': '2000-01-01', 'lte':'2015-12-31'},
                opts={'columns':['coid','mdate','pbr','per',
                      'div_yid','mom','str','ltr','profit','invest',
                      'dd_merton','dd_kmv','illiq','idiosyncratic',
                      'hhi','skew']},
                chinese_column_name = True,
                paginate = True)

Step 1. 检查有无缺失值

df.isnull().sum(axis=0)

如果有缺失值,直接丢入模型的话,会导致无法计算,不过 XGBoost 模型能处理稀疏矩阵,可以容许有缺失值的存在,不过如果我们能合理的填补缺失值,这有助于我们增强模型的配适度,常见的方法为填补「平均值」、「中位数」,或是直接填上 0,使用的语法是 fillna ,至于要填入什么的话,可以先对资料做一些 探索式资料分析(Exploratory Data Analysis,EDA),那这会是另一个重点,未来我们再另花篇幅去介绍!

Step 2. 为了避免前视误差,我们会用当月因子去预测下个月的报酬,所以要将当月与下个月报酬做一个配对, 故我们把资料都延后一个月,之后做资料合并时就可以使用

# 处理时间
from datetime import date, timedelta
import calendar

将月份都加上一个月

df['年月'] = df['年月'].apply(lambda x: x + timedelta(days=calendar.monthrange(x.year, x.month)[1]))

step 3. 标准化

一般来说机器学习时,对资料做标准化,会提高模型的预测力,但在 XGBoost 却不需要这一步,大略的解释为:标准化是处理连续特征,主要作用是进行数值缩放 ( 减去平均值、除以标准差 )。而数值缩放的目的是解决梯度下降时,等高线会是椭圆导致迭代次数增多的问题。但是上一篇提到 XGBoost是树模型,是不能进行梯度下降的,因为树模型是阶越的,不可做导数。反而是透过寻找特征的最优分裂点来完成优化的,由于标准化不会改变分裂点的位置,因此 XGBoost 不需要对资料进行标准化!

step 4. 处理标签资料

df_label = tejapi.get('TWN/APRCM',
                mdate={'gte': '2000-01-01', 'lte':'2015-12-31'},
                opts = {'columns':['coid','mdate','roi']},
                chinese_column_name = True,
                paginate = True)

如果是正报酬则设为 1,负报酬则为 0

df_label['报酬率%_月'] = df_label['报酬率%_月'].apply(lambda x: 1 if x>0 else 0)
df_label.rename(columns={'证券代码':'证券码'}, inplace=True)

step 5. 合并资料

data = pd.merge(df , df_label, on=['证券码', '年月'])

进行训练

step 1. 划分训练与标签

X, y = data.iloc[:,2:-1],data.iloc[:,-1]

step 2. 切割训练与测试资料。

通常在执行机器学习时,我们不会把所有资料都拿去做训练,因为这样做的话,我们很难判断他的学习效果是好还是不好,因此我们会切一部分出来,以下我们拆成 8:2 ,20% 的资料作为模型后续的评估

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

step 3. 资料丢入分类器

from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score

将分类器命为 model,后面那串代表我们已经自行将标签改成我们要的编码

model = XGBClassifier(use_label_encoder=False)

开始训练模型!

model.fit(X_train, y_train)

我们来检视这模型在测试集的预测准确度

y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))

预测 2330 的报酬率

step 1. 载入 2330 在 2015~2017 的投资因子

df_pred = tejapi.get('TWN/AFF_RAW',
                coid = '2330',
                mdate={'gte': '2015-12-01', 'lte':'2017-11-30'},
                opts={'columns': 如文章第一段}
                chinese_column_name = True,
                paginate = True)

step 2. 载入 2330 在 2016~2017 的月报酬率,并递延一个月

df_pred_label = tejapi.get('TWN/APRCM',
                coid = comp,
                mdate={'gte': '2016-01-01', 'lte':'2017-12-31'},
                opts = {'columns':['mdate','roi']},
                chinese_column_name = True,
                paginate = True)

step 3. 计算准确度

pred2 = model.predict(df_pred.iloc[:,2:])
df_pred_label['报酬率预测'] = pred2
accuracy = accuracy_score(df_pred_label['报酬率%_月'].apply(lambda x: 1 if x>0 else 0), pred2)
print("Accuracy: %.2f%%" % (accuracy * 100.0))

视觉化

step 1. 设定 Matplotlib 能显示中文

import matplotlib.pyplot as plt
import matplotlib.font_manager
plt.rcParams['font.sans-serif'] = 'Arial Unicode MS'
plt.rcParams['axes.unicode_minus'] = False

step 2. 视觉化决策树 (部分)

plt.figure(figsize=(30,10))
xgb.plot_tree(model,num_trees=0)
plt.rcParams['figure.figsize'] = [1300, 1000]
plt.show()

step 3. 视觉化特征重要度

plt.figure(figsize=(10,40))
xgb.plot_importance(model)
plt.rcParams['figure.figsize'] = [5, 5]
plt.show()

结论

今天的教学其实就是目前机器学习比赛常见的架构了,模型的开发其实都是很复杂的数学,而我们可以理解他的特质和性能来去使用它,并不用去深入了解他的数学计算,除非对这块很有兴趣,关于预测的准确度,其关键常在资料的前处理,包括遗失值、偏锋态、共线性等数据处理,或是从相关论文发现可以组合出有效的特征。

本篇因为 TEJ 已经整理好相关因子的数据,所以在前处理上相对轻松很多,但还是要强调一点是,由于金融上有非常多的不确定性,现在的准确度无法代表未来的准确度,但可以理解的一点是,这些因子都是目前金融正在寻找股价的特征,不过现实生活有很多数据可以拿来玩,现在赶快把资料丢进 XGBoost 吧!

本文仅供参考之用,并不构成要约、招揽或邀请、诱使、任何不论种类或形式之申述或订立任何建议及推荐,读者务请运用个人独立思考能力,自行作出投资决定,如因相关建议招致损失,概与作者无涉。

完整程式码

延伸阅读

相关连结

返回总览页