PythonでXGBoostをちゃんと理解する(2) ライブラリ作者から学ぶ
XGBoostについて調べてたら、開発者本人から学ぶ的な動画があったので観てみた。
時間にして約1時間半、英語が苦手でなくて時間がある方は直接見て頂くと面白いかも。
目次はこんな感じ。
・Introduction
・Basic Walkthrough
・Real World Application
・Model Specification
・Parameter Introduction
・Advanced Features
・Gaggle Winning Solution
前半は「まぁみんな知ってるよね」ってことが多かったが、Model SpecificationとParameter Introductionの中のParameter Tuning、あとAdvanced Featuresが面白かったのでメモ。
Model Specification
よく見る勾配ブースティングの説明とは違うように見えたので、面白くて動画を見ながらスライドの内容をメモってみました。
所詮スライドなので、動画内での口頭での補足があるとよりわかりやすいですが、ざっと眺めてもそれなりにわかりやすいのでご参考にどうぞ。
日本語訳が雑でごめんなさい。
動画内スライド引用 (24:00〜)
本の決定木があったとして、がその木からの予測値とすると、モデルは。(P31)
番目のデータ、の予測値は、であり、同様に番目のステップでの予測値は、となる(p32)。損失関数は、最小二乗法、2値分類と多クラス分類のためなどそれぞれ目的に応じて使う。また過学習を防ぐために正則化項を導入し、その式は
ここで、は葉の数、はj番目の葉における重みの値である(P34)。
損失関数と正則化項をまとめると下記のようになる。
XGboostでは、このを最適化するために、勾配降下法を用いる。
目的関数を下記のように置き直し、
1次導関数、2次導関数それぞれをそれぞれ下記のように求めると(P37)、
テイラー展開することで、
と近似できる。ここでは、
である(P38)。で、この目的関数を最適化させてを求めることがゴール。じゃあこのを出力するために、①決定木の形をどうやって求める?&②予測の値をどうやって出力させる?を考える(P43)。
①の問題が解決できてるとして、決定木は、で表される。ここでは、番目の葉にデータを当てはめる関数である。この式は予測値を返す過程を、
・データを葉に割り当てる
・対応する重みを割り当てるj番目の葉に割り当てられたデータにインデックスをに従って割り振る。
ここで、目的関数を書き換えると、
同じ葉にいる全てのデータは同じ予測値を共有するので、この式は葉ごとの予測値の総和を返す。
ここでは2次方程式となるので、を最適化するは簡単に求まり、
となるから、それに応じたの値は下記となる(P48)。
これで重みの値が求まるので、次にどのように木の形を決めるかを考える。
通常は木の決め方をジニ係数などでGainを計算するが、勾配ブースティングでは、
として、gainを計算する(P53)。
この式に従って木をMax_depthに達するまで茂らせていき、gainが負になる枝を剪定する。
この作業を指定の回数繰り返す。
Parameter Tunin(55:20〜)&Advanced Features(1:00:00〜)
パラメーターをチューニングするにあたっては、以下の3つに気をつけなさいと。
①Control Overfitting
過学習を抑えるために、パラメーターについては二つに分けて考えているようです。
・モデルの複雑さをコントロールするために
−max_depth, min_child_weight,gamma
・ノイズに対する堅牢さを高めるために
−sub_sample, colsample_bytree
まぁこの辺りは何も特別な事考えず、etaを加えて6個のパラメーターを結果を見ながら調整するんでいいんじゃないかなと思います。
②Deal with Imbalanced data
データのバランスをコントロールするために以下3つを試してみなさいと。
・scale_pos_weight使ってデータのバランスを調整
・AUCを評価指標に使う
・max_delta_stepを"1"辺りに設定する
③Trust the cross validation
動画の中でも、CVを信じなさいと言ってました。
で、CVを行ってnroundを決める場合には、十分な回数を指定しつつearly.stop.roundを使って終わらせる方法が取り上げられてました。
さらに、Overfittingが見られたら、etaを少なくして、nroundを大きくすることを同時にする。
また、個別のオススメの機能としては、xgb.cv()で"prediction = TRUE"にすることで、予測値のベクトルを返してくれるようになります。
長くなったので、「じゃあパラメーターチューニングは具体的にどうやる?」については次回にします。