XGBoost:学習曲線と検証曲線

概要

学習曲線とは学習の進行過程を数量的にプロットしたもの。DeepLearning等の 勾配法を利用した機械学習アルゴリズムを利用する際に、ステップ数毎の評価をするために使われる。同様に、検証データに対しては検証曲線(validation curve)と言われる。そこで、XGBoostでクロスバリデーションデータに対するcross validation curveをプロットしてみたいと考えた。しかし、調べてみても記事があまりなかったので実装してみる。

環境

macOS Mojave 10.14.5
python 3.7.4
xgboost 0.90

データ、モデルの準備

モデルはデフォルトのパラメータを使う。xgboost v.0.90ではデフォルトでobjective='reg:linear'になっているが、v.1.00では代わりにobjective='reg:squarederror'になっている。そのため、そのままで実行するとwarningがうるさいのでobjectiveのみパラメータをセットする。v.1.00以降の人は何もしなくていいだろう。データはボストンの価格予測を使う。

from sklearn import datasets
from sklearn.model_selection import train_test_split, KFold

data = datasets.load_boston()

#split train, test
x_train, x_test, y_train, y_test = train_test_split(data['data'], data['target'], test_size=0.2, random_state=0)

#create model
params = {'objective': 'reg:squarederror'}
model = xgb.XGBRegressor()
model.set_params(**params)

クロスバリデーション

sklearnのKFoldを使って5 fold cross validationを行う。学習の際にeval_setを指定するとステップ毎の評価を.evals_result()で取り出せるようになる。それらの値を平均する。

#cross validation
kf = KFold(n_splits=5, shuffle=False, random_state=0)
eval_metric = 'rmse'
evals_li = []
for i_train, i_test in kf.split(x_train):
    x_cv_train = x_train[i_train]
    y_cv_train = y_train[i_train]
    x_cv_test = x_train[i_test]
    y_cv_test = y_train[i_test]
    eval_set = [(x_cv_test, y_cv_test)]
    model.fit(x_cv_train, y_cv_train, eval_set=eval_set, eval_metric=eval_metric, verbose=False)
    evals_result = model.evals_result()
    evals_li.append(evals_result)
result = np.zeros(100)
for i in range(5):
    result += evals_li[i]['validation_0'][eval_metric]
ave_cv_evals = result/5

学習と予測

先ほどと同様にしてeval_setを指定する。今度はクロスバリデーションをしないで全ての訓練データで学習し評価する。

eval_set = [(x_train, y_train), (x_test, y_test)]
model.fit(x_train, y_train, eval_set=eval_set, 
        eval_metric=my_cv_score, verbose=False)
evals_result = model.evals_result()
train_evals = evals_result['validation_0'][eval_metric]
test_evals = evals_result['validation_1'][eval_metric]

プロット

learning curve, cross validation curveとついでにテストデータに対してもプロットしてみた。

import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.subplot(111)
x = range(len(train_evals))
plt.plot(x, train_evals, label='train')
plt.plot(x, test_evals, label='test')
plt.plot(x, ave_cv_evals, label='validation')
plt.grid()
plt.legend()
plt.show()

f:id:oosakik:20191106002716p:plain

評価関数の作成

上記コードではeval_metric='rmse'としたが、評価指標はrmse以外にもrmsle, mae, loglossなどがある。詳しくは公式を参照。しかし、使いたい評価関数がないときもあるため、今回自作してみた。ピアソンの相関係数で評価してみる。

from scipy.stats import peasonr

def my_cv_score(y_pred, d_matrix_data):
    y_data = d_matrix_data.get_label()
    r, p = pearsonr(y_pred, y_data)
    return 'my_score', r

あとは、eval_metric='my_score'とし、model.fit()eval_metricmy_score関数をしてしてあげればよい。

#cross validation
eval_metric = 'my_score'
evals_li = []
for i_train, i_test in kf.split(x_train):
    x_cv_train = x_train[i_train]
    y_cv_train = y_train[i_train]
    x_cv_test = x_train[i_test]
    y_cv_test = y_train[i_test]
    eval_set = [(x_cv_test, y_cv_test)]
    model.fit(x_cv_train, y_cv_train, eval_set=eval_set, eval_metric=my_score, verbose=False)
    evals_result = model.evals_result()
    evals_li.append(evals_result)
result = np.zeros(100)
for i in range(5):
    result += evals_li[i]['validation_0'][eval_metric]
ave_cv_evals = result/5

#training
eval_set = [(x_train, y_train), (x_test, y_test)]
model.fit(x_train, y_train, eval_set=eval_set, eval_metric=my_score, verbose=False)
evals_result = model.evals_result()
train_evals = evals_result['validation_0'][eval_metric]
test_evals = evals_result['validation_1'][eval_metric]

#plot evals
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.subplot(111)
x = range(len(train_evals))
plt.plot(x, train_evals, label='train')
plt.plot(x, test_evals, label='test')
plt.plot(x, ave_cv_evals, label='validation')
plt.grid()
plt.legend()
plt.show()

f:id:oosakik:20191024235542p:plain