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 吧!

本文僅供參考之用,並不構成要約、招攬或邀請、誘使、任何不論種類或形式之申述或訂立任何建議及推薦,讀者務請運用個人獨立思考能力,自行作出投資決定,如因相關建議招致損失,概與作者無涉。

完整程式碼

延伸閱讀

相關連結

返回總覽頁
Procesing