ktrのブログ

だいたい体験談と勉強したことのアウトプット

SIGNATE公園コンペの反省

KaggleのRコンペでリークが見つかり呆然としているときに、SIGNATEでデータ量もそれほど多くないテーブルコンペが開催されたので初日から参加しました。結構本気で取り組みましたがフォーラムなし+時系列タスク+コンペ参加2回目ということもあって大分苦労しました。

結果は17位なので役に立つ情報はありませんが、自身への備忘録と反面教師的に参考になればと思います。

コンペの概要

  • 開催期間 2018/10/24 - 2018/12/13
  • 8つの国立公園周辺の宿泊者予測。
  • 訓練データに2015年と2016年の日次データが与えられる。

モデリングの概要

  • 特徴量
    最終提出に使用した特徴量は天気データ、路線検索結果、SNSデータ、そしてターゲットを1日シフトさせたラグ変数 。
  • 交差検証
    2015年を訓練データとして2016年を検証データ使用。結果的にはCVの変動とLBの変動が一致しなかった。

詳細

特徴量

提供データの結合
  • 天気データ
    公園名ではなく地名でデータをもっていたので単純に公園と1:1では結合しなかった。なので公園をググって地名と公園が結びつくようしました。天気データは予測時点では使用できないので前日の値をシフト。
  • 路線検索データ
    検索結果の到着地と出発地が県名だったので公園の場所をググって紐付けを行った(公園が複数の県にまたがっているような場合もあり)。
    対象公園外からの到着検索と対象公園からの出発検索の二つに分けて集計。
    検索実行日時で集計は行わず到着(出発)指定日時で集計を行えば、未来の情報として役に立つと思ったが、一部の公園でターゲットの推移と一致しないことが終盤になって判明しました。
  • SNSデータ
    公園に関連しそうな単語のSNS投稿件数のデータ。公園に関連しそうな単語は勝手に選定がされていたので、抽出方法が恣意的な感じがして気持ちが悪かったが、それをいい塩梅で処理する方法が浮かばなかったので、こちらも「単語 国立公園」でググってすべての単語を公園と紐付け。
ラグ

時系列予測ではターゲット変数をシフトさせて(ラグをとる)説明変数とするのが常套手段みたいです。1

ラグが有効だと感じていたし、公園ごとにコレログラムが異なっていたので、ターゲットを7日までシフトさせてそれぞれの公園で一番CVが良いラグの組み合わせで予測を行うようにしましたが、結局改善しませんでした。今考えるとCVがLBと一致しなかったんだからCVが下がるように特徴量を選定してもLBに反映されないのは当たり前です(泣)。

結局ラグ1で落ち着きました...

モデリング

学習器にはLightGBMを使用。理由は同時期に参加していたKaggleのRコンペで使用していた為でとくに深い意味なし。最後にXGBoostも試したが結局LightGBMの方がスコアはよかった。

予測には公園一つずつの訓練データを使用する方法と、すべての公園を訓練データとしてぶち込む2通りがありました。直感的にはそれぞれの公園にそれぞれモデルをこしらえら方が良さそうだが、後者の方がスコアが良かったです。おそらく全体の傾向をみて、平均的な予測する方が効果的だった印象。2

交差検証の設定

時系列予測で単純なk-foldが通用しないことは目に見えていたので、コンペの予測タスクと同じように2015年を訓練データとして2016年を検証データすることにした。 しかし、特徴量を追加したり、ハイパーパラメータチューニングするとCVが下がるが、LBが悪化するという乖離状態に落ち入り、悲惨な結果を辿る事に.....

その他

定常性

ツリーベースの学習器は基本的にデータを外挿することができず、徐々に増加したりするトレンド予測ができないないことは知っていたので、前日の差分をとってトレンド除去をして予測を試みましたが、差分を戻した際にうまくいかなかったので使用しませんでした。

シフト365日

時系列だし新しいデータほど価値のあるでは?という考えから365日分のラグを取れば2015年と2016年同時に特徴が見れていいじゃん!と思って追加したがLBで大幅に悪化した。

反省点

とにかくCVとLBの一致できなかったが大きな反省点です。参考にできるフォーラムもなかったのでまるで暗闇を手探りで歩いている感覚でした。

窓関数を使った移動平均などを特徴量に追加するときに訓練データは問題ないですが、テストデータは予測結果を当てはめて、その結果もって予測中に計算する必要があります。これが結構面倒で、実験速度の低下になりました。自分の実装スキルのなさが露呈したと思います。

Kaggleのような公開カーネルが存在しなかったので、最初から最後までをすべて自分の頭で考えて、それをコードに落とし込む必要がありました。なので実装スキルは確実にアップしたと思います。 初めてやり通したコンペとなったので非常に良い経験となりました。ぜひ皆さんの解法も共有いただきたいです。


  1. https://mlcourse.ai/notebooks/blob/master/jupyter_english/topic09_time_series/topic9_part1_time_series_python.ipynb?flush_cache=true

  2. signate「国立公園の観光宿泊者数予測」コンペで10位でした - u++の備忘録 によると、公園ごとに予測した方が結果がよかったみたいなので、やはり個別に予測するほうが良いのかもしれません。