見出し画像

【38th solution】Kaggle M5 Forecasting -Accuracy~Team P 参戦記

※本稿はテックブログからの転載で、「Kaggleグローバルコンペに参加した」の記事(3/3)です。

・JDSCのKaggle参戦記、3チーム目のPチームの記事になります。
・前回、前々回の記事でJNチームとかJSチームとか何の略?と思った方もいるかもしれませんが、MBTIという性格診断の枠組みで使われる性格の特徴のことでした。
・JDSCではMBTIを利用して社員の個性の相互理解を図っています。外資、特に米系の会社でよく使われていたり、日系だとリクルートでも導入されていたと聞きますので、馴染みのある方もいらっしゃるのではないでしょうか。


・今回、Kaggleのチーム分けの際に「同じMBTI属性の人で分けたらどんなカオスが起きるのだろう。。。」という好奇心に負け、JNチーム、JSチーム、このPチームといった具合にカオスが編成されました。
・Pチームは臨機応変、悪く言えば行き当たりばったりを愛す人たちの集まりです。以下の解説を読んで私はムチ打ちになるくらい頷きました。

***
子供の頃のP型は夏休みの宿題をギリギリまで溜め込んでしまったり、母親に言われたことを怒られながらやる傾向にあるでしょう。大人であれば、余裕をかましてしまったり、締切日ギリギリまで仕事を行わないといったことがあるでしょう。

***
・予想されたとおり色々なトラブルに巻き込まれつつも、なんとか上位0.6%(あと少しで金!)のスコアで社内ダービーを制すことができたので、ソリューション、ドタバタ具合諸々こちらに残しておきます。

チームメンバー

・岡田さん(DS)
筋肉とプロテインがトレードマークのJDSCきっての肉体派。彼が入社してから「オフィス冷蔵庫の牛乳の減りが3倍になった」と専らの噂。JDSC外でも大学院の先生の研究を手伝ったり、大学の授業を受けたりしている。機械学習×セキュリティが好き。最近の悩みは「XLの服以外着れないこと」


・橋本さん(EN)
フルスタックエンジニアでありながら、気づくといつの間にかBERTを回していたり、昔はロボカップ出てたり、いつの間にか情シス業務までしてたり、お魚捌いてくれたり、オールマイティー過ぎて本職がなにか分からない弊社Tech Co-Founderの橋本さん。


・三栖さん(DSインターン)
東工大でバイオインフォを学びつつ、JDSCでインターン中。ややこしい実装お願いしてもいつの間にかなんとかしてくれる。ソフトバンクのAI奨学金選ばれたらしい。うらやましい。


・杉崎(DS)
新卒は総合商社だったが、データ分析が好きで通勤電車の中で5年間Qiitaを読み続けた結果、いつの間にかDSに転職していた人。
JDSCの社会人学術研究推奨制度を使って大学院に入り、今頃はキャンパスライフを満喫しているはずだったが、現実は家に缶詰でZoom講義をひたすら受ける日々で枕を濡らしている。

タイムライン

・3月(キックオフ)
既にこの時点で不穏な発言が。。。

画像1

キックオフランチを2回設定→2回とも流れる→コロナ
ということで、結局キックオフをしないまま3月が終了

・4月
何もせず終了(EDAのカーネルだけ読んだ)
・5月
止まっていた時間が(岡田さんだけ)動き出す

画像2

・6月前半〜中旬
- 岡田さん以外全く動けない日々が続く
- 杉崎→仕事+授業8コマ+研究室でのPRML輪読会の合わせ技で死亡
- 橋本さん→PJ業務+リモートで慣れない椅子に首を痛め死亡
- 三栖さん→研究室諸々で死亡
- 他のチームの進捗を見て、いかに前向きに負けるかを考え始める
- 戦いが始まる前に既に負けている(岡田さんと杉崎以外チームマージに失敗した)ことに気づく

画像3

最後(で最初)の追い込み

ようやく動き出したPチーム。最後の金夜〜土日で頑張りました。

画像4

・6/26 (金) 業務後〜深夜
- 「オリジナルの特徴量で1Sub」を目標に作業を始める
- SQL大好き芸人なので、Kernelには目もくれずBigqueryで特徴量テーブルを作りはじめる(詳細はSolutionにて)
- 張り切って作った特徴量テーブルのサイズが大きすぎて、使おうと思っていたサーバーのメモリに乗らないことに気づき絶望する(Dask使う?とか色々考え始める)

画像5

・6/27 (土)
- 別のツテで使えたGPUサーバに環境構築を開始する
今度は空きDiskが足りず、デフォルトで用意されてたAnacondaの環境消しまくったり、要らないCUDA消したり→最終的にBigqueryから店舗別のChunkで読み込み、CSVではなくpklで保存することで解決
- 学習並列化とか、Subファイル作るための処理書いたりとか


・6/28(日)
- まさかの誕生日に一日中Kaggle
- GPUでしか発現しないLGBMのバグを踏んでしまい、時々学習が途中で落ちる事象と戦う
- 学習の都度モデルをpklに保存する処理書いて凌ぐ
- なんとか1Sub目を達成(Public: 0.65044 Private:0.58354)
- JDSCの他チームがPublic 0.5切りそうなところで戦ってるので凹む

画像6

・6/29(月)
- 特徴量を少し変えて、ハイパラいじったモデルで2Sub目(Public: 0.59785、Private:0.56255)
- 敵チーム永山さんの孔明の罠により焼肉に行ってしまい、業務後の作業時間が消失

▼この日食べた肉が美味すぎて、Kaggleのことは完全に忘れました

画像7

・6/30(火)
- Loss-weightいじったりとか、仕事の合間に少し悪あがきするものの、大して改善せず(0.57)。
- 時系列系手法やCatboostとのアンサンブルとかを試したかったが、新しいモデル作る余力はなかった(あと少しで金だったので、もう少し頑張ればよかったw)
- Publicでは私のモデルが岡田さんのモデルより良かったので、私のをFinal Submissionに。どうも0.5切りのモデルはCVが怪しい気がしたので、Shakeを期待して寝る。

・7/1(水)
朝起きたら思ってたより上にいた(38th/5558 : Silver)

▼朝起きたらいつの間にかめっちゃ上にいてビビるの巻

画像8

・孤軍奮闘の橋本さんは祭りのあとのLaterSubmissionで人外のスコアを叩き出していた

▼富士通のスパコンもびっくりの桁数

画像9

Solution

基本戦略

・Event系はEvaluation期間に特化した特徴量を作る
振り返ってみると常にPublicよりPrivateのほうがスコアが良かったので、この作戦はそこそこハマったと思います(もちろん元々の売上水準の話もありますが)
・Recursive Featureは使わない
1位の方はRecursive Featureありとなしでそれぞれモデル作ってアンサンブルさせていたようですが、Leakしないように特徴量作るのが結構面倒な処理になると思ったので割愛しました。
・ただし28日以前の特徴だけでモデルを作ると精度が悪くなるので、予測対象期間(F1〜F28)を1週間刻みで別のモデルにする)※4位の方のSolutionと同じ感じでした

画像10

・モデルはStore単位で回す(Dept毎やCat毎でも良かったかも)
・基本はLGBMを使う
Recursive Featureを使わない選択をしたので、時系列系のモデルやLSTMはFirst choiceから外すことに。作り込む時間があれば時系列系のモデルで抽出したトレンド成分や季節調整項を特徴量としてLGBMに食わせるとかはありだと思ってました。
・objectiveは、別件の調べ物でたまたま見つけたTweedieがM5にも使えそうだな、、、と思っていたら他のKernelで採用しているのを見かけたので、こちらでも採用。
・Loss-Functionは普通にRMSE(小細工しない)


学習対象データ

・(たしか)2013年以降を対象
2012以前は364日前の数字を使う系の特徴量が取れなかったり、店ごとの売上推移を見ていると、改装なのか売上の規模が今と結構変わっていたため
・各商品が「各店舗で最初に売れた日」以降のデータのみを対象
そもそも棚にないのにDemand:0と解釈されることを避けた

画像11

特徴量s

・移動平均系
7,28,364日移動平均
①予測対象店舗×該当item 、全店舗×予測対象item、予測対象店舗、該当Dept、などのメッシュで
②上記、平均を取る期間を7日前始まり〜28日前始まりまでWindowをずらして4モデル分
あとは前年比での売上トレンドの変化を抑えるために7日前(〜28日前)時点での7日移動平均と364日前(〜392日前)時点の7日移動平均の売上のratioを取ったり


・Lag系
7,14,21,28,364日前のDemand
①集計単位と②Windowの考え方は上と同様
そのほか364±7,14,21,28日前の売上を平均したりとか


・カレンダー系
コンペ終了まで時間がない、ということであまり手間掛けず
- Evaluation期間中に該当する、NBAFinal、Ramadan、Pesachだけを個別の特徴量として切り出し
- NBAはStartの日付とEndの日付があったので、開催期間に入っているか+7日前が開催期間に入っていたかのBoolean
- RamadanとPesachはそれぞれ開始日と終了日の片方しかカレンダーになかったので、開始日、終了日からの経過日数をintで
- 他のEventはevent_typeごとにフラグ立て(当日が該当するか+7日前が該当するかの2カラムずつ)※ここらへんは7日だけでなくwindowに合わせて複数作っておいたほうがよかったかも
- SNAPはStoreの所在地と一致するフラグのみに集約
- 月初月末も関係あると思ったので、year, wknum, day, wdayあたりを入れる


・価格
1w,4w,52w前との価格の比

時間があればやりたかったこと

・Stacking
同じ特徴量でCatboost、XGboost回したり、木の深さ変えたモデルを合わせるだけでまだ結構スコアの伸び代あったのではないかと。


・モデル作成単位
店舗毎で作りましたが、学習時間かけていいならCategory毎で作っても良かったかなと。あと、今回は時間方向には1週間ごとでしたが、特徴量とモデルを根気強く作る余裕があれば理論上は1日毎にモデルを作ることも可能で、それだけでも結構精度が上がるような気がします。(F1~7用のモデルとF22~28用のモデルだとRSMEベースで10%程度の差がありました)


・時系列系モデルで抽出したトレンド等をLGBMに食わせる
ある意味Stackingですが、季節調整項などの抽出は時系列系モデルのほうが優れているイメージなので、Prophetあたりを回した結果を上手くモデルに組み込めればなと思ってました。


・ハイパラチューニングとちゃんとしたCV
今回そんなに実験回す時間がなかったのでナイーブにCV切りましたが、ちゃんとCV切ってハイパラもう少し詰められていれば、、というのはあります。(橋本さんがlater submissionで検証したところ、私の特徴量+Catboost+JNチームのハイパラで回したら更に10位くらい順位が上がってましたので、改めて金圏惜しかったなと。)


・手元でのWRMSSEの計算
Public Kernelに落ちていたみたいですが、試す余力はなく、Submissionしないとスコアがわからないという原始人みたいな手法でやってました。ちゃんと序盤にパイプライン作っておくべきだと思います。


・External Data
今回Evaluation期間中にTXで台風だか洪水があったというのは認識してたのですが、CV期間との兼ね合いで簡単にはモデルに入れられなそうだったので断念しました。


・学習Weightの調整
最終日に「5,6月とか2015年のWeight上げたらより直近の傾向反映するのでは?」と思って調整したものの効果出ず。今回はデータ数が十分あったので、weightを上げるのではなくdownsampling的に古いデータのweightを下げたほうが良かったのかもしれないです。

総括

・(コンペ期間中ずっと大学院+仕事で死にそうだったとはいえ)無計画すぎて夏休み最終日に死ぬ小学生のような進行でした。
・とはいえ、Kaggle初参戦で上位0.6%というのは悪くない成果だったかなと思います。次回はもう少し計画的にやってGoldを目指したい。。
・コンペ後の他チームとの感想戦がとても楽しかったので、また会社全体、今回みたいにエンジニアやコンサルメンバーを巻き込んで何かのコンペに出れるといいなあと思いました。
・Pチームはその無計画性をいじられることが多かったので(いやホント反省しないといけないのですが)、Pもやるときはやるぞというのを見せられてよかったです。
・業務外で勝手にやってただけなのですが、JDSCではKaggleでメダル取得すると報奨金がもらえる素敵な制度があるので、みんなで万札を握りしめて美味しい焼肉で祝勝会します。幸せ。

▼PはポンコツのPと言われなくてよかった

画像12

JDSCでは社会にパルプンテを起こせる仲間を募集しています。
Pの方もJの方もぜひ一度遊びに来てください!


この記事が気に入ったらサポートをしてみませんか?