Kaggleに挑まない人でも非常に読む価値の高い本だった まず他の機械学習の本ではなかなか触れられないような実践周りのテクニックについてたくさん語られていた その分理論やアルゴリズムは深くは語られていなかったが、Python機械学習プログラミングなどの理論・アルゴリズム系の本と併用するとほぼ網羅できるのではないかとまで感じた
この本ならではの内容としては、時系列データのモデリングでどのように精度を出すか、ハイパラの調整法、バリデーション時にリークを出さないようにするにはどうすればいいか、アンサンブルの手法などである
また作成が最近ということもあり、GBDTに関して詳しく説明されていたことも価値があると感じた
ちなみにこの本のスコープは機械学習コンペなので画像やNLPはあまり触れられていない
1章 分析コンペの概要
分析コンペ(主にKaggle)ってなに?という説明 KaggleのKernelやDiscussionの活用、参加の仕方、チームの組み方などの内容
本題はあくまで2章から
2章 タスクと評価指標
目的変数としてどういったものがあるかについて(回帰、2値分類、多クラス分類)
次に評価指標 結構大事な話で、回帰ではRMSEやRMSLE(対数とってからたすやつ)MAE(差の絶対値平均)などで基本はRMSEだがRMSLEは比率に注目していてMAEは外れ値の影響低減などの効果もある
分類では単純な二択の場合は混同行列を元にしたprecisionやrecall、またこれを組み合わせたF1スコアやFβスコアなどで正例の確率を求めたい場合はloglossやAUCなど loglossはコスト関数として使われることも多い
多クラス分類の場合は前述のものをマルチに拡張したような指標を主に使う 他にはqwkなど
目的関数について、回帰モデルではRMSE、分類ではloglossを使うことが多いが、コンペで使われる評価指標と同じ目的関数を使ってやると都合がよく、モデルの評価指標や目的関数は自分でカスタムしたりできる
また目的関数や評価指標のカスタムのみでなく閾値の設定や予測確率の調整(データの数が少ないとかモデルがランダムフォレストとかだと歪むことがあるため)も重要 たとえば予測確率の範囲を0.1~99.9にするとか、スタッキングとか
MAEを目的関数に使いたい場合MAEは2階微分値が0なので近似関数を使う必要あり
最後にリークについて、バリデーション時にバリデーションの目的変数を学習に意図せず使っちゃうことによって発生(データの意味を正しく理解してないとうっかり発生しかねない)
3章 特徴量作成
①変数の変換②別データから作成・結合③次元削減や教師なし学習による特徴量④その他 などがある
①について
GBDTはほとんど何もしなくていいがNNや線形モデルはスケーリングとか欠損値処理とか必要 GBDTでもたとえばa,bよりa/bを特徴量にした方が強力みたいな例がある
まず欠損値について消すのはあんまよくない 欠損値を扱えないモデルなら-999にするとか代表値にするとかしよう 他にも予測による補完も強力 また欠損値であること自体を2値変数にするとか(欠損値の数を集計してもいい)データによっては-1を欠損値に戻すのも重要
標準化などの数値変換において、テストデータも取り入れて標準化することも可能(いずれにせよtrainとtestで同じように処理するのが大事)Min-Maxスケーリングは画像だけ 他にもグラフの分布を変えたいときは対数変換みたいな非線形変換とかも あとはclip関数による外れ値除去 数値データのbinningや順位への変換
カテゴリ変数について、テストにのみ存在するカテゴリがないかどうか(あったら欠損値扱いとかするとよい)
次に各種encodingだがonehot(n-1個で十分っぽいけどまあn個でよい、数が多い場合は低頻度のものはいっそその他にしちゃう)label(GBDTのみ相性が良い)あとはtargetで目的変数を利用するためリークのリスクが非常に高い、時系列には不向き しかしその分強力 バリデーションするときは本当にリークに気をつけよう また値の意味をしっかり読んでそのままencodingしていいかの判断をしよう(型番とか文字数に意味があるとか、そういったときにしっかり抽出しよう なぜならそれはGBDTの決定木にはできないことだから)
次に年数などの変数は周期性とか(GBDTなら気にしなくて良い)十分なデータがあるとか考慮点が多い 2年未満しかないときは月の情報に留意とか日データは月初から月末までの0~1データにするとか、月を四半期に丸めるとか、曜日祝日連休の何日目かとか特定基準からの経過日数とか
変数の組み合わせについて、GBDTだと各数値の乗除があると効きやすい
②について
各ユーザごとのログデータとかある場合、シンプルにユーザIDごとに各種統計量を取るだけでなく、時間的な統計量を撮ったり集計単位を変えたり条件を絞ったり色々工夫できる
時系列データについては結構難しく時間情報とIDが同じ軸にあるかどうか(wideかlongかなど)で変わってくる 大事なのは過去の情報だけ使うこと wideタイプのデータの場合ラグ特徴量が有効(目的変数以外のラグも使えたりする あとはグルーピングして平均をとるとか) 他にも重要なのはテストデータによって使えるtrainデータの時刻は場に違いがあること(めちゃ重要)なのでテストデータ個別にモデルを作るという力技もある
③について
PCAは軸を減らすための教師なし手法だが特徴量が正規分布に沿ってる前提なので注意 もちろん画像にはむいてない 教師ありだがLDAという手法で軸を減らすことも可能(削減後の特徴量数はクラス数より少なくなるので2値分類だと1次元データになる) 他にもNNを用いたオートエンコーダによる低次元への圧縮やクラスタリングのよる新しい特徴量作成など
④について
位置情報なら特定都市からの距離とか自然現象のメカニズム(日の出日の入り)、ドメイン知識、NLPの手法の応用(wordの数数えるやつとか頻度の多い一般的な単語の重要度を下げるやつとか埋め込みとか)
あとは匿名データだったら匿名前のデータを予測してみるとか、誤データを探して修正するとかも有効
4章 モデルの作成
5割〜8割は特徴量作成でハイパラの調整は終盤、モデルがGBDTでタスクによってはNNでアンサンブルも検討することもある バリデーションデータによって改善を繰り返す バリデーションはCVが普通
過学習防止や正則化、アーリーストッピング(バリデーションの途中経過を見ながらいい感じのところで止める)なども重要
バギングは乱数シードを変えて平均取るだけでも十分良い
次にどのモデルがいいかについてGBDTが安定、たまにNN、SVMはまずない、線形モデルは過学習のしやすい特殊なコンペでは有用
GBDTについて決定木を並列でなく、直列に使っていて最後に複合する 特徴量は数値である必要があるが、欠損値のままでよく変数間の相互作用が加味される onehotencodingが不要などなど現状非常に使いやすい
XGBTやLGBMが代表的でLGBMの方が速い(決定木の分岐がヒストグラムベース、つまり数値をまとまりでとらえることによる高速化)catboostは遅めだけど特徴量の相互作用を加味しやすい
GBDTで過学習を防止するためには学習率の調整や決定木の深さを浅めにするなど またGBDTはデータが一見多くても2値分類や疎の場合は分岐が少ないから意外と軽くなったりする
次にNNではReLUなどを用いて出力することを繰り返すことで非線形の表現に強くなる 勾配降下法は確率的勾配降下法が計算効率が良い
NNは欠損値はあつかえないしスケーリングが必要だしハイパラ調整の難易度が高いが、変数間の相互作用や非線形に強く多クラス分類にとてもむいてる あとGPU向き
層の構成やオプティマイザの設定の選択肢が多い 最近はRNNの構造のものが利用されるようになってきてる
線形モデルはあんまいいことないがL1正則化を特徴量選択に利用したりできる
その他としてはFFMがレコメンドタスクと相性良し
その他のモデル作成のテクニックとして、pseudolabeling(テストデータが学習データより多い時にテストデータへの予測値を特徴量にして再度用いちゃう)
また、筆者が実際に使ってるModelクラスのメソッドは参考になりそう
5章 モデルの評価(バリデーション周り)
バリデーションデータへの予測の精度をなんらかの評価指標で測ってモデルの汎化性能を評価していくことが重要
バリデーションの手法①がholdout法 事前に行をシャッフルした方が良い
これよりさらに良いのが②CVでn分割してn回holdout法をやる nは計算時間と精度評価のトレードオフで4か5がよいけどデータがとっても多いときは1か2で十分で計算時間短縮になる
CVの層化抽出(クラスの分布を等しくする)とかgroupk-fold(なにかのグループによってtrainとtestが分けられてしまってるとき、バリデーションもそのグループで分ける)
時系列データのバリデーション方法として、時系列でtrainとvalidを分けるholdout法してハイパラ・特徴量を利用して、最後にvalidも学習に含めてモデルを作ってtestに当てはめるのが良い(つまりtrainの中で一番新しいデータであるvalidを学習に使わないのは勿体無いということ)
ただやっぱりholdoutはデータを有効に使えていないので時系列独自のCVもある このとき各foldごとにtrainデータの量が異なることもありまた古すぎるfoldは学習として有用でない可能性
また時系列データといえども、近さだけ大事で流れはそんなに重要でないと判断したら過去と未来関係なく時系列データ以外同様にバリデーションしても問題ない(しかしリークには注意)
具体例としてはテストデータの日時と同じ曜日のみバリデーションにするとか
バリデーションのポイントとして、バリデーション時はコンペの評価指標に関わらずloglossやAUCを使うとか、あとはtrainとtestの分割を模倣してバリデーションを作るとか
そもそもtrainとtestが同じ母集団から同じ基準で取ってきたかどうかも重要で、分布が違う場合はadversarial validationの値が小さくなるような特徴量作成が大事(テストデータかどうかを目的変数とする2値分類のスコア)
PublicのテストデータとPrivateのテストデータの分布や量によって、PublicLBをどの程度参考にするか異なる
ランダム性でPublicLBがたまたま高く出てしまうこともあるので留意 CVの分割をハイパラチューニングとモデル評価の際で分けるとかも大事 また、とにかくテストデータの予測よりも有利な条件でバリデーションを予測してないかの確認はとっても大事
6章 パラメータチューニング
ハイパラの探し方は候補の総当たりのグリッドサーチとランダムサーチで、後者の方が効率は良い また以前のパラメータの結果に基づいて効率的探索を行うベイズ最適化 簡単さ分かりやすさならグリッドサーチで精度ならベイズ パラメータを自動でがりがりやる場合はバリデーション時とfold分割を変えるべき
パラメータの影響よりも乱数シードの影響の方が大きいなんてことにならないように、乱数を変えた時の結果をみることで注意する とはいえそもそもGBDTとかだとハイパラよりはるかに特徴量生成の方が大事
ベイズ最適化のライブラリも色々ある(hyperoptとか)
XGBTのハイパラだと、max_depthの調整が最も重要 上手い人はhyperoptか手動で調整
NNだと中間層の活性化関数や層数、ドロップアウト率など あとはオプティマイザの種類と学習率
線形だと正則化の種類と大きさ
次に特徴量の選択について、当然ない方がいい特徴量も多いのでどうやって選ぶか ただGBDTなら意味のない特徴量があってもまあ問題ないことやアンサンブルで過学習抑制できることから特徴選択はiしなこともある
選択方法①は目的変数との相関性や相互情報量などをみること (一応この場合もCVした方がいいにはいい)
②はGBDTなどから出てくる特徴量の重要度 特にGBDTではその特徴量に分岐で目的関数どれくらい減ったが大事 カテゴリ変数は分岐が多くなりやすいので注意 他にもpermutation importanceで列の中身をシャッフルしてどう変わるかといった指標や目的変数をシャッフルした時の変化
GBDTではノイズの悪影響より良い特徴量発見のメリットの方が大きいからとりあえず機械的にいっぱい作ってから削ぐというやり方も
③として反復して探す方法
クラスの分布が偏ってる場合の対応として、アンダーサンプリング(多い方のクラスの一部を使う)でモデルを作る(特徴量作成は全データを使う)とか、2値分類の閾値調整とかクラスごとのウエイト調整など
最後にベイズ最適化についての補足もあったがよくわからなかった、、
7章 アンサンブル
アンサンブルは複数モデルや同じモデルの別乱数シード版などで平均や加重平均、幾何平均をとる NNだとブレが大きいからシード取るのは有効 アンサンブルは過学習抑制になる
アンサンブルの一種であるスタッキングはモデルで予測したデータを特徴量(メタ特徴量)として加えて再度学習と予測を行う手法 2層でなく何層でもいいし複数のモデルを使ってもいい CVしないとリークになるので注意 これの応用で欠損の数を予測するモデルや回帰を分類と捉えたモデルなどによる予測値をメタデータにすることも
スタッキングはデータの多いコンペには有効、逆にtraintestの分布が異なるコンペではtrainに適合し過ぎてしまう
アンサンブル向きのモデルは多様性重視でGBDT、NN、線形、kNN、ランダムフォレストなど 同じモデルでもハイパラや特徴量を変えるとかも良い モデルの多様性を出すために各予測値の相関係数を出すと良い