はじめに
こちらは、ABEJAアドベントカレンダー2023の13日目の記事です。
こんにちは!ABEJAでデータサイエンティストをしております松村です。2021年の入社時から地元広島からフルリモートで働いており、早いものでもうすぐ3年が経過します。
今回は、データサイエンティスト誰もが一度は直面するリーク問題について考えてみました!
リークって何?
「機械学習におけるリークとは何か?」について一言で言うと、本来使うことのできない情報をモデルの学習に使ってしまうことを指します。
この説明だけだと少しわかりにくいので、日常の例に置き換えて考えてみます。
みなさんは高校時代に期末テストの勉強をする時に、どのように勉強していたでしょうか?おそらく具体的にどんな問題がテストで出るかはわからないため、答えを丸暗記するのではなく、教科書の内容を理解して類似の問題にも応用が効くように勉強していたかと思います。
機械学習におけるリークも上記例に近い話です。モデルが学習時にデータのパターンや規則から汎用的に使える情報を学ぶべきところを、本来であれば手に入らない答えや未来の情報が学習データに入り込んでしまっていることで、そういった情報を過剰に学習してしまい、手元で検証している時にはうまくいっているように見えても、実際にモデルを使ってみた時に思うような精度が出ない原因となってしまいます。
リークの例
好き好んでリークしているモデルを作ろうとするデータサイエンティストはいないと思います。すごく精度が高いモデルができているように見えても、実際に業務に使う時に期待した精度が出てくれないと意味はないですよね。
とはいえ、どれだけ最新の注意をしていてもリークが起きてしまうケースはあります。私自身も前職の事業会社,ABEJAでの実務、コンペで何度も痛い目に合いました。。
今回は架空のテーマを用いて、実際に起きてしまう可能性のあるリークに関する具体的な例を挙げてみようと思います。
テーマ概要
野球チームからこれまでデータ活用ができていなかったが、うちでも始めてみたい!と依頼があり、データサイエンティストが勝敗予測モデルを作ることになりました。担当者の方から、データの蓄積はしているので使ってくださいと言われ、3年分のExcelデータをもらえたとします。
使用できるデータ,手法
データについて、過去3年分の以下情報が蓄積されているものとします。
・試合情報
・球場情報
・天候
・選手情報
ダミーのテーブルイメージを添付しておきます。ここに加えて、選手の詳細成績(打率,HR数・・・)が使えるものとします。
今回は具体的なソースコードや実際のモデリング結果詳細は割愛しますが、手法としてはテーブルデータでは割と定番のLightGBMを使ってモデリングをする方針にします。
例
上記テーマにてモデリング、評価を進めているなかで起きそうなリークについていくつか触れてみます。
例1.運用時に使えない情報を使ってしまう
先発投手が誰か?誰がスタメンで出ているのか?という出場選手の情報が勝敗予測に寄与すると考え、対戦相手の先発投手とスタメンに関する情報を特徴量に使うことにします。
有効な特徴量だと思って追加した結果、確かに手元での検証では仮説通り精度はかなり向上しているように見えましたが、運用時には精度が出ませんでした。なぜでしょうか?
要因としては、スタメンに関する情報は予測を実施するタイミングでは使えなかったため、全て"不明"となってしまったということでした。
モデルの結果をどう活用するのか確認すると、「スタメンの決定に使いたい。予測結果についてあくまで参考結果とし、スタメンの最終決定は監督が考えた上で実施するため、予測は試合当日の朝には終わっていて欲しい」という返答がありました。そのため、前日には発表されている先発投手に関する情報は使えるが、当日の試合直前に発表される対戦相手のスタメン情報は予測においては使えないということでした。
例2.更新された情報を使ってしまう
天気に関する情報が有効ではないか?と仮説が立ちます。例えば、屋外の球場をホームにしているチームであれば、寒すぎる日や暑すぎる日の試合でも慣れているのでパフォーマンスが落ちにくい可能性があります。
そこで、天気予報の最高気温,最低気温を特徴量に使うことにしました。あくまで予報の情報を使うのであれば、例2であげたような失敗は起きないはずです。
有効な特徴量だと思って追加した結果、確かに手元での検証では仮説通り精度はかなり向上しているように見えましたが、運用時には精度が出ませんでした。なぜでしょうか?
「予報」だと思って使っていた気温に関する情報が、「実績」だったことが要因でした。天気情報に関するテーブルは、未来の日時については「予報」の値が入りますが、過去分については「実績」に置き換わるような仕様になっていることが判明しました。
結果として予測時点ではわからない天気の「実績」に関する情報を用いて手元での検証をしていたため、不当に高く精度が出てしまっていました。
その他例
今回のテーマで起こりうるリークのパターンについて、簡単なものを2つ例をあげましたが、それ以外にもKaggleのコンペや論文などでも様々なリークが起きてしまっています。例えば、データ拡張によって生成した画像をtestデータに使ってしまう、時系列データのtrain,test分割時にランダム分割してしまう、id列が目的変数と強い相関がある状態になっているなどがあります。
リークを回避するためには?
ここまでいくつかリークの例を挙げてきました。では、どうすれば回避できるのでしょうか?個人的な見解をいくつか書き出してみます。
ドメイン知識をもとにした確認
ドメイン知識がある領域の場合、実運用を意識した際に本当にその特徴量を使って問題ないのか見直すという対策ができると思います。
また、自分では判断がつかなくても、周囲のドメイン知識のある方に率直な意見を聞いてみるというのは一つの手だと思います。
今回の例1で挙げた、運用時に使えない情報を使ってしまう問題についても、どのように運用されるのかを事前にちゃんと話し、前日時点で公表されている対戦相手の先発投手情報なら使えそうだということが頭に入っていれば防げたかもしれません。
データを正しく理解する
事前にデータの取得元がどこなのか、どういった意味の情報なのか、いつ時点の情報なのかなどデータの定義をしっかり確認をします。
そんなこと当たり前じゃん!と思われるかもしれませんが、個人的にはここが一番大事です。実務ではデータを準備する人と使う人が異なるケースも多く、「このデータは〇〇という意味のはず」と先入観を持って判断しないこと、データを準備する方は、データサイエンティストがそのデータをどう使うのかイメージがついていないことも多いので、その前提で丁寧にコミュニケーションをすることが必要です。
今回の例2で挙げた、天気予報だと思ったら実績だったという問題についても、ちゃんと担当者とコミュニケーションをとってデータの定義をちゃんと理解していれば防げたはずです。
重要特徴量からの判断
featureimportanceやSHAPをみて、上位に来ている特徴量が自分の感覚通りになっているかを確認するという手段が考えられます。
理由がよくわからない特徴量が上位にきてしまっている場合、前処理でどこか実装ミスがないかなど確認することでリーク発生を事前に防ぐことができます。
特徴量作成後の可視化
作成した特徴量と目的変数での可視化をして、明らかに何か違和感がある結果になっていないかみることも個人的にはよくやっています。
データを受領したタイミングで最初にEDAをするのは当然として、そこから加工,集約等した状態で改めて可視化をしてみると何か気づくこともあります。雑にpandas-profilingで可視化して眺めてみるだけでもだいぶ違うのかなと思います。
自分がやったことを信用しすぎない
考え方的な話にはなりますが、自分が作ったモデルがめちゃくちゃ精度が高い時ほど疑ってかかるべきだと思います。うまく行った時ほどテンションが上がり疎かになりがちですが、そんな時ほど本当にこの結果大丈夫だよね?と確認をするという意識を持っておく必要がありそうです。
まとめ
今回は比較的極端な例を挙げて、リークとその回避策についてまとめました。リーク発生を完璧に防ぐ方法はないですが、本記事内であげたいくつかの観点をはじめとしたアンチパターンを意識すること、リークしていないかの確認プロセスを挟むことで、リーク発生のリスクを一定抑えることはできそうです。あとは、実務やコンペで数をこなしてどれだけその見極めの精度を上げることができるのか?が重要かなと思っています。
We Are Hiring!
ABEJAは、テクノロジーの社会実装に取り組んでいます。
技術はもちろん、技術をどのようにして社会やビジネスに組み込んでいくかを考えるのが好きな方は、下記採用ページからエントリーください!
(新卒の方のエントリーもお待ちしております)