🏧

atmaCup #16 参加記録

D2Cデータサイエンティストの吉井&市川です。

今年も12月に入り、アドベントカレンダーの時期が到来しました。近年、多くのブログ記事がアドベントカレンダー形式で公開されるようになり、情報が溢れる季節となりました。

弊社の技術ブログ「m-tech」も例外ではなく、アドベントカレンダー形式での記事公開を予定しています。私たちも参加を表明しましたが、12月になっても準備が進まず話題に困っていました。

そんな時、atma株式会社主催のデータコンペティション「atmaCup」の開催通知がconnpassから届きました。過去にもatmaCupに参加し楽しい体験をしていたため、今回も参加し、その体験をブログ記事にすることにしました。

この記事ではatmaCup#16への参加記録を綴ります。成績は市川が56位、吉井が132位(666人中)でした。成績はふるいませんでしたが、学びの多いコンペだったので、上位のソリューション+私たちの解法を紹介したいと思います。

atmaCupとは

atma株式会社が主催するオンサイトデータコンペティションです。第5回からはオフラインでも参加できるようになりました。短期間の開催で、ディスカッションが活発なのが特徴です。

atma株式会社とデータ提供者がデータ分析に精通しているため、面白いテーマとやりがいのあるコンペティションが魅力です。

コンペの概要・問題設定

今回は、株式会社リクルートとの共同開催で、「じゃらん net」のデータを用い、セッション内の行動ログから最終的にユーザが宿泊する宿を予測する内容でした。タスクとしてはセッションベースのレコメンドで評価指標はMAP@10です。

データは行動ログとしてセッション内で閲覧した宿のIDとその順番が与えられ、正解ラベルとしては宿IDが1つ付与されます。他に宿IDに紐づく情報がマスタデータとして与えられています。詳細はコンペティションのページでご覧いただけます。

https://www.guruguru.science/competitions/22/data-sources

上位ソリューションまとめ

前処理

  • データのドメインシフト対策: 上位ソリューションのほとんどでtrainとtestのドメインシフトに対応するための前処理が行われています。例えば、trainとtestそれぞれのデータソースで特徴量を作成したり、共起行列を作成する際にtestの重みを大きくしたりしていました
  • セッションの長さが1のときに同一の閲覧中の宿(=特徴量が同じ)に対して異なる正解ラベルが付与される問題(Noisyなラベル)に対し、付与するラベルを修正することで対処されている方もおられました

レコメンド候補の選出

多くの解法でreranking(正解となりそうな候補をあらかじめ選出しておき、機械学習モデルで候補内の順番を並び替える)の手法が使われていました。候補を選出するロジックを大まかに分類すると以下のようになります。

  • 共起関係: 宿と宿が同時にセッション内に出現する共起関係(この宿をみた人は他にこんな宿をみています)を用いて候補を選出する
  • 人気の宿: よく閲覧されている宿を優先する
  • 同一地域の宿: セッション内の宿と同一地域に所属する宿を優先する
  • Bayesian Personalized RankingやMatrix Factorizationを用いた推薦
  • Item2vecやProNE等のベクトル化手法と閲覧中の宿との類似度を用いた強調フィルタリング

閲覧している宿と同一地域の宿を予約するユーザがほとんどを占めていたこともあり、共起関係に基づいた候補選定が重要だったと考えられます。

特徴量エンジニアリング

rerankerとなる機械学習モデルに入力する際の特徴量の中で、特に重要であると思われるものをまとめます。

  • 共起関係に基づく特徴量: 閲覧中の宿と候補宿の共起回数や遷移確率
  • 閲覧宿と候補宿との類似度: Item2VecやProNEによるベクトルの類似度
  • ランキング特徴量: 候補生成手法に基づくランキング順位
  • セッション特徴量: 特徴量をセッション全体で集計したもの
  • セッション内の特徴量: セッション中に何回登場したか、登場順など

特徴量でも共起関係を表現することが重要でした。また、セッションの特定の順番に出現した宿が正解となることが多かったため、セッション内の特徴量も重要だったと思われます。

モデリング

  • LightGBM: 定番手法なことに加え、損失関数としてlambdalankも利用可能だったのが大きかったと思われます
  • CatBoost: カテゴリ特徴量が多かったことに加え、YetiRankを損失関数に利用できるのがよかったと思われます
  • Matrix Factorization: 共起関係を捉えるのが重要なコンペであったため、Matrix Factorization単体でもよいスコアを得られるとのことでした
  • ルールベース: セッション中の特定の宿を推薦するとよかったり、共起関係を作り込んだソリューションが上位にくるなど、ルールベースによる推薦が重要なユニークなコンペだったと思います

後処理

  • trainに登場し、testに登場しない宿を候補から除外

吉井がやったこと

私自身、レコメンド形式のコンペは初めての挑戦でした。主に週末に取り組み、ディスカッションや過去のkaggleコンペを参考にしながら戦略を立てました。

データ分析

ディスカッションでも述べられているように、EDAを行ったところ以下のことが分かりました。

  • 長さが2以上のセッションでは閲覧履歴内に登場した宿がターゲットとして現れることが多い
  • セッション数が偶数のものは偶数番目に、奇数のものは奇数番目の宿が選ばれることが多い

上の特性より次のような方針で進めることとしました

  1. ルールベースのものをベースに、補助的に機械学習モデルを使う
  2. セッションの長さが1のものと2以上のもので別の方法でターゲットを予測する

レコメンド候補の選出

Item2Vecを使って宿のベクトルを算出し、セッション中の宿と類似度が近いものを20件選出しました。

モデリング

  • ルールベースとしてTrain/Testを合わせたデータの共起関係を計算し推薦を行う
  • 残りの部分をLGBMモデルの予測結果で埋める

特徴量

宿のマスターデータから取得できるものをそのまま利用しました。

結果

上記の方法でPrivate: 0.4199 (Public: 0.4231)までなんとかスコアを上げられたものの、時間切れで終了となりました。

市川がやったこと

ディスカッションで取り上げられていたモデルを改良して挑みました。

レコメンド候補の選出

  • 同一セッション内に登場する宿の共起関係をグラフ構造で表したときに、現在閲覧している宿から3つ先までの宿を推薦候補とする

モデリング

  • Graph Convolutional Network 10層 (Transformer Conv Blockを利用)
  • 損失関数としてpairwise hinge lossを利用
  • AdaBelief Optimizerを利用
  • 5fold GroupKFold Ensemble
  • 残りの推薦候補はセッション内の宿と同一地域のものを人気順に推薦する

特徴量

ディスカッションのモデルと同じものを利用しました。

ノード特徴量

  • 宿のマスターデータから得られる特徴量
  • 閲覧回数
  • セッション内か外かを表す特徴量
  • セッション内での閲覧回数
  • セッション内での閲覧順に関する特徴量

エッジ特徴量

  • 共起回数
  • セッション内か外を表す特徴量

結果

スコアはPrivate: 0.4338 (Public: 0.4384)でした。train/testのドメインシフトを考慮できなかったこと、宿と宿の類似性などの有用な特徴量を作れなかったのがスコアが伸びなかった原因だと思われます。

最後に

今回のコンペ自体も大変有意義で楽しめました。次の機会にも積極的に参加したいと思っています。リーダーボードでお会いした際は、よろしくお願いします。

D2C m-tech

Discussion