Pythonによる勾配ブースティング(GBDT)の実行方法
機械学習手法「勾配ブースティング」は、データ分析コンペティション「Kaggle」で良い性能を出す事が多く、一気に多用されるようになりました。
個人の主観としても「数量データ分析における最強の機械学習手法」ではないかと考えており(後述します)、機械学習の手法に迷ったら何はともあれ適用してみたい手法です。
本記事では、そんな勾配ブースティングをPythonで実装する方法をご紹介します。
勾配ブースティングとは
勾配ブースティング(Gradient Boosting Decision Tree, GBDT)は教師あり学習のひとつです。
方式としては決定木を沢山作って、それらの結果を総合的に評価します。
ランダムフォレストと似ていますが、ランダムフォレストは使うデータや使う変数をちょっとずつ変えた決定木をたくさん作り、最終的に多数決を取ります。
一方、勾配ブースティングはまず代表となる決定木を作成して、その結果を踏まえて木を少しずつ更新していきます。
最終結果をたくさんの決定木から総合的に評価することは同じですが、それが「並列」的か、「直列」的か、という所が大きな違いです。
決定木系の手法の便利なところは、そもそも値の大小関係にしか注目しないので、数値の標準化・正規化などの変換が不要なこと。
そして、データに欠損値があってもそのまま計算できること。
加えて、回帰問題も分類問題も解く事ができること。
そして勾配ブースティングは、それに加えて大した学習時間も掛からず、高い性能が出る事が多いという素晴らしい手法です。
つまり、データをそんなにいじらなくても、それなりのものが出来てしまう事が多いのです。
無論、そこからハイパーパラメータ調整や特徴量エンジニアリングを行うことにより更に性能は伸びていきます。
・・・とはいえ、いつなん時でも勾配ブースティングが優れるという訳でもありませんので、他の手法との性能比較などは相変わらず必要です。
あくまで、「これだけ知っていれば良い手法」という意味ではなく、「まず適用してみたい手法」であるとご理解ください。
Pythonによる勾配ブースティングの実装
さて、上述したように非常に強力な手法なのですが、実装は非常に簡単です。
勾配ブースティングを実装するためのライブラリにはXGBoost、lightgbm、catboostなどがありますが、今回は最も使用例が多いと思われるXGBoostを用いてみます。
データの準備
今回は、scikit-learnのサンプルデータのうちの1つbreast_cancerを用いて、「乳がんか、そうでないか」の予測をさせてみます。
データの読み込み部分は以下のようになります。
1 2 3 4 5 6 7 8 |
#データ読み込み from sklearn.datasets import load_breast_cancer import numpy as np cancer = load_breast_cancer() X = cancer.data y = cancer.target X_cols = cancer.feature_names |
Xが説明変数の2次元リスト、yが目的変数のリスト、X_colsが説明変数の名称リストとなっています。
勾配ブースティングによる学習モデルの作成
まずはXGBoostをimportします。
その後、解きたい問題が何かによって呼び出すクラスと引数が変わってきます。
大抵の場合は以下の3パターンのいずれかから選ぶことになります。
2クラス分類タスク | XGBClassifier(objective=”binary:logistic”) |
---|---|
多クラス分類タスク | XGBClassifier(objective=”multi:softmax”) |
回帰タスク(数値予測) | XGBRegressor(objective=”reg:squarederror”) |
今回は2値分類なので、XGBClassifier(objective=”binary:logistic”)を呼び出すことになります。
引数にも色々指定できますが、設定しないとエラーを起こす可能性があるのは上述したobjectiveのみです。
その他、以下のようなパラメータもあります。
木の深さ | max_depth(デフォルト=6) |
---|---|
サンプリングするデータ数の割合 | subsample(デフォルト=1.0) |
サンプリングするカラム数の割合 | colsample_bytree(デフォルト=1.0) |
もっとたくさんありますが、体感としては最も性能に響いてくるのは上記3つです。
このあたりは主観となってしまいますがmax_depthは5〜15あたり、subsampleとcolsample_bytreeは0.8〜1あたりで調整してみるのが良さそうです。
・・・また、今回は更に高みを目指して(?)、交差検証も行ってみます。分割数は5にします。
性能指標ですが、分類タスク(予測するものがカテゴリ)なので、「accuracy」「precision_macro」「recall_macro」「f1_macro」の4つを出してみます。
これらの意味や使い分けについては混同行列の記事もご参照ください。
回帰タスク(予測するものが数値)ならば、「max_error」「neg_mean_squared_error」などの指標を選択します。
これらの意味や使い分けについては誤差指標の記事もご参照ください。
・・・ということで、今回の場合、以下のように学習モデルを定義することになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#学習 import xgboost as xgb from sklearn.model_selection import cross_validate,cross_val_predict, StratifiedKFold splits = 5 skf = StratifiedKFold(n_splits=splits, shuffle=True, random_state=42) score_funcs = ["accuracy","precision_macro","recall_macro","f1_macro"] clf = xgb.XGBClassifier(objective="binary:logistic") score = cross_validate(clf, X, y, cv=skf, scoring=score_funcs,return_estimator=True) print(score["test_accuracy"].mean()) print(score["test_precision_macro"].mean()) print(score["test_recall_macro"].mean()) print(score["test_f1_macro"].mean()) |
しばらくすると、以下のように結果が出力されます。
1 2 3 4 |
0.9613081954597924 0.9605032686950473 0.9566712939133509 0.9584412931360962 |
どの指標を見ても非常に高い性能が出ていると分かります。
ちなみに、cross_validateの実行時に「return_estimator=True」を指定することにより、重要視している変数などモデルの中身の情報を取り出すことができます。
重要変数の確認
さて、これで学習モデルが完成しました。
では、勾配ブースティングが、分類に深く関わってくるのは変数はどれと判断したのか確認してみます。
1 2 3 4 5 6 7 8 9 10 11 |
#重要変数 import pandas as pd sum_score = np.zeros(len(X_cols ),) for i in range(splits): sum_score += score["estimator"][i].feature_importances_ df_score = pd.DataFrame(sum_score/splits,index=X_cols,columns=["score"]) df_score.sort_values("score",ascending=False) #影響が大きい順に表示 |
交差検証を行ったので、分割した5つの分類器それぞれで結果が出ています。
なので、すべての結果を平均して、最後にソートして大きい順に並び替えました。
実行すると・・・
最も重要な説明変数は「worst perimeter」と判断しているようです。
こういった情報が簡単に取れるのも有難いですね。
カテゴリ予測
最後に、作成した学習モデルを使って予測してみましょう。
1 2 3 4 |
#予測 sample = X[0] + np.random.rand(len(X[0])) #適当なデータを作成 score["estimator"][0].predict([sample]) |
入力データの0番目に適当な数値を足し算したダミーデータを作り、カテゴリを予測させてみました。
分類器は5個あるので、予測する場合はどれか1つ選ぶことになります。(多数決で決める方法もあります)
今回はscore[“estimator”][0]と、0番目のものを選んでいます。
結果は・・・
1 |
array([0]) |
「0」、つまりこのデータの患者は乳がんでは無いと判断したようです。
おわりに
以上が、勾配ブースティングの実装方法でした。
優秀な上に実装も簡単なので、確実に抑えておきたい機械学習のひとつです。