- 製造業出身のデータサイエンティストがお送りする記事
- 今回は勾配ブースティング決定木(XGBoost, LightGBM, CatBoost)でOptunaを使ってみました。
##はじめに
勾配ブースティング木に関しては、過去に記事を書いておりますのでそちらを参照して頂けますと幸いです。
##XGBoostの実装
まずは、XGBoostをOptunaでハイパラチューニングを実装してみます。
今回もUCI Machine Learning Repositoryで公開されているボストン住宅の価格データを用いて予測モデルを構築します。
# ライブラリーのインポート
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import plotly
%matplotlib inline
# ボストンの住宅価格データ
from sklearn.datasets import load_boston
# 前処理
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# XGBoost
import xgboost as xgb
# Optuna
import optuna
from optuna.samplers import TPESampler
# 評価指標
from sklearn.metrics import r2_score
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
warnings.simplefilter(action="ignore", category=pd.core.common.SettingWithCopyWarning)
# データセットの読込み
boston = load_boston()
# 説明変数の格納
df = pd.DataFrame(boston.data, columns = boston.feature_names)
# 目的変数の追加
df['MEDV'] = boston.target
# データの中身を確認
df.head()
次にoptunaの事前準備をします。
# ランダムシード値
RANDOM_STATE = 10
# 学習データと評価データの割合
TEST_SIZE = 0.2
# 学習データと評価データを作成
x_train, x_test, y_train, y_test = train_test_split(
df.iloc[:, 0 : df.shape[1] - 1],
df.iloc[:, df.shape[1] - 1],
test_size=TEST_SIZE,
random_state=RANDOM_STATE,
)
# trainのデータセットの2割をモデル学習時のバリデーションデータとして利用する
x_train, x_valid, y_train, y_valid = train_test_split(
x_train, y_train, test_size=TEST_SIZE, random_state=RANDOM_STATE
)
def objective(trial):
param = {
"eta": trial.suggest_loguniform("eta", 1e-8, 1.0),
"gamma": trial.suggest_loguniform("gamma", 1e-8, 1.0),
"max_depth": trial.suggest_int("max_depth", 3, 8),
"min_child_weight": trial.suggest_loguniform("min_child_weight", 1, 40),
"max_delta_step": trial.suggest_loguniform("max_delta_step", 1e-8, 1.0),
"subsample": trial.suggest_uniform("subsample", 0.0, 1.0),
"reg_lambda": trial.suggest_uniform("reg_lambda", 0.0, 1000.0),
"reg_alpha": trial.suggest_uniform("reg_alpha", 0.0, 1000.0),
}
model = xgb.XGBRegressor(**param)
model.fit(
x_train,
y_train,
eval_set=[(x_valid, y_valid)],
early_stopping_rounds=50,
verbose=False,
)
preds = model.predict(x_valid)
mae = mean_absolute_error(y_valid, preds)
return mae
各パラメータについては、公式文章を参照してください。
次にoptunaで最適なハイパーパラメータを見つけます。
# optunaで最適値を見つける
# create_studyメソッドの引数"sampler"にサンプラーと乱数シードを指定
study = optuna.create_study(direction='minimize', sampler=TPESampler(seed=RANDOM_STATE))
study.optimize(objective, n_trials=500)
あとは、チューニング結果のハイパーパラメータを使ってモデルの学習と予測を行います。
# チューニングしたハイパーパラメーターをフィット
best_params = study.best_params
best_params["random_state"] = RANDOM_STATE
# チューニングしたハイパーパラメーターをフィット
optimised_model = xgb.XGBRegressor(**(best_params))
optimised_model.fit(x_train, y_train)
# XGBoost推論
y_pred = optimised_model.predict(x_test)
# 評価
def calculate_scores(true, pred):
"""全ての評価指標を計算する
Parameters
----------
true (np.array) : 実測値
pred (np.array) : 予測値
Returns
-------
scores (pd.DataFrame) : 各評価指標を纏めた結果
"""
scores = {}
scores = pd.DataFrame({'R2': r2_score(true, pred),
'MAE': mean_absolute_error(true, pred),
'MSE': mean_squared_error(true, pred),
'RMSE': np.sqrt(mean_squared_error(true, pred))},
index = ['scores'])
return scores
scores = calculate_scores(y_test, y_pred)
print(scores)
出力結果は下記のようになります。
R2 MAE MSE RMSE
scores 0.768409 3.302701 24.21993 4.921375
##LightGBMの実装
LightGBMは下記に実装サンプルがありますので、そちらの記事を参考にしてください。
##CatBoostの実装
最後に、CatBoostを実装します。
# ライブラリーのインポート
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import plotly
%matplotlib inline
# ボストンの住宅価格データ
from sklearn.datasets import load_boston
# 前処理
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# CatBoost
import catboost as cb
from catboost import CatBoost, Pool
# Optuna
import optuna
from optuna.samplers import TPESampler
# 評価指標
from sklearn.metrics import r2_score
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
warnings.simplefilter(action="ignore", category=pd.core.common.SettingWithCopyWarning)
# データセットの読込み
boston = load_boston()
# 説明変数の格納
df = pd.DataFrame(boston.data, columns = boston.feature_names)
# 目的変数の追加
df['MEDV'] = boston.target
# データの中身を確認
df.head()
次にoptunaの事前準備をします。
# ランダムシード値
RANDOM_STATE = 10
# 学習データと評価データの割合
TEST_SIZE = 0.2
# 学習データと評価データを作成
x_train, x_test, y_train, y_test = train_test_split(
df.iloc[:, 0 : df.shape[1] - 1],
df.iloc[:, df.shape[1] - 1],
test_size=TEST_SIZE,
random_state=RANDOM_STATE,
)
# trainのデータセットの2割をモデル学習時のバリデーションデータとして利用する
x_train, x_valid, y_train, y_valid = train_test_split(
x_train, y_train, test_size=TEST_SIZE, random_state=RANDOM_STATE
)
def objective(trial):
param = {
"iterations": trial.suggest_int("iterations", 50, 300),
"depth": trial.suggest_int("depth", 4, 10),
"learning_rate": trial.suggest_loguniform("learning_rate", 0.01, 0.3),
"random_strength": trial.suggest_int("random_strength", 0, 100),
"bagging_temperature": trial.suggest_loguniform(
"bagging_temperature", 0.01, 100.00
),
"od_type": trial.suggest_categorical("od_type", ["IncToDec", "Iter"]),
"od_wait": trial.suggest_int("od_wait", 10, 50),
}
model = cb.CatBoostRegressor(**param)
model.fit(
x_train,
y_train,
eval_set=[(x_valid, y_valid)],
early_stopping_rounds=100,
verbose=False,
)
preds = model.predict(x_valid)
mae = mean_absolute_error(y_valid, preds)
return mae
次にoptunaで最適なハイパーパラメータを見つけます。
# optunaで最適値を見つける
# create_studyメソッドの引数"sampler"にサンプラーと乱数シードを指定
study = optuna.create_study(direction='minimize', sampler=TPESampler(seed=RANDOM_STATE))
study.optimize(objective, n_trials=50)
あとは、チューニング結果のハイパーパラメータを使ってモデルの学習と予測を行います。
best_params = study.best_params
best_params["random_state"] = RANDOM_STATE
# チューニングしたハイパーパラメーターをフィット
optimised_model = cb.CatBoostRegressor(**(best_params))
optimised_model.fit(x_train, y_train)
# CatBoost推論
y_pred = optimised_model.predict(x_test)
# 評価
def calculate_scores(true, pred):
"""全ての評価指標を計算する
Parameters
----------
true (np.array) : 実測値
pred (np.array) : 予測値
Returns
-------
scores (pd.DataFrame) : 各評価指標を纏めた結果
"""
scores = {}
scores = pd.DataFrame({'R2': r2_score(true, pred),
'MAE': mean_absolute_error(true, pred),
'MSE': mean_squared_error(true, pred),
'RMSE': np.sqrt(mean_squared_error(true, pred))},
index = ['scores'])
return scores
scores = calculate_scores(y_test, y_pred)
print(scores)
出力結果は下記のようになります。
R2 MAE MSE RMSE
scores 0.863433 2.596167 14.282276 3.77919
##さいごに
最後まで読んで頂き、ありがとうございました。
今回は勾配ブースティング決定木の3つのアルゴリズム(XGBoost, LightGBM, CatBoost)でOptunaを使ってみました。
訂正要望がありましたら、ご連絡頂けますと幸いです。