<実践>「過去の閲覧履歴から最適な街コンを勧める」システムのコンペに参加してみた

AIエンジニア(データサイエンティスト?)として働き出して1ヶ月。
なんだかんだ勉強して1年。
いろんなアルゴリズムも触ったし、いちど自分の実力を試してみたいなと思い、データサイエンスのコンペを探していました。

探したのは

そして、signateでいいコンペを見つけたので参加することにしました。
できるだけ、AI・機械学習界隈の人でなくてもわかるように書いていきます。

目次

  1. コンペの概要
  2. 取組み
    • 2-1. 取組みの流れ(ざっくり)
    • 2-2. 使用した機械学習アルゴリズム
    • 2-3. 前処理(preprocession)
    • 2-4. パラメタチューニング
  3. 結果
  4. 感想
  5. 告知

1. コンペの概要

コレに参加しました。
signate.jp

概要を箇条書きで書きます。

  • 目的

    • ユーザーに最適な街コンを勧める。以下のようなイメージです。 f:id:kurupical:20180522190400p:plain
  • 評価基準

    • 概要

      • 2017/9/24までのデータを基に、9/25〜9/31に開催される街コンをおすすめする
      • ユーザごとに「おすすめ街コンランキング」を20位まで提案する
    • 評価

      • nDCG(具体的な計算式は上記サイト参照)
        • 提案した街コンについて、9/25〜9/31に実際に「参加した=7点、ブックマークした=3点、見た=1点」として、自分が提案したランキングの上から計算
        • ランキングの上位のほうが多く得点が与えられる。 例:(1位=参加、2位=不参加、3位=見た) > (1位=不参加、2位=参加、3位=見た)
        • 理想の提案の得点を1としたときの自分の提案の得点がスコアになる。 詳しく知りたい方は  レコメンドつれづれ ~第3回 レコメンド精度の評価方法を学ぶ~ - Platinum Data Blog by BrainPad
  • 与えられるデータ

    • ユーザーの属性
      • 年齢
      • 住所
    • 過去開催されたイベントの詳細
      • 都道府県
      • 開催日時
      • 女性/男性の参加可能年齢範囲
      • イベントジャンル
    • ユーザーの閲覧ログ
      • どのユーザーが
      • どのイベントに
      • (参加した/ブックマークした/見た)
    • 評価対象のユーザー一覧(2886件)
      • ユーザーID
  • 提出データ

    • ユーザーごとのおすすめイベント
      • ユーザー数(2886)×20イベント

2. 取組み

2-1. 取組みの流れ

今回、以下のような流れで取り組みました。 * データの前処理 * パラメタチューニング

2-2. 使用した機械学習アルゴリズム

教師なし学習であるNearest Neighborを使いました。
ざっくり言うと、

  • データを与えると、
  • そのデータと似たものを出力する

アルゴリズムです。

簡単に例を挙げます。

f:id:kurupical:20180522215526p:plain:w500

やや雑ですが、食べ物を「甘いー辛い」属性、「洋食ー和食」属性の2軸にとりました。

ここで、「エビフライが好きな人が好きな食べ物は何か?」をNearestNeighborを使って解決します

1.データ「エビフライ」を与え、座標上に点を描きます。
f:id:kurupical:20180522220455p:plain:w500

2.エビフライの近くにあるものが答えです。(つまり、ここでは「オムライス」と「グラタン」。)
f:id:kurupical:20180522220535p:plain:w500

実際の食べ物の趣向は、2軸では表現できません。重いー軽い、高いー安いなど、人によって何個も判断基準があると思います。
実際、NearestNeighborでは、2次元に限らず、3次元以上のデータも扱えます。

このNearestNeighborを、婚活データに適用してみようと思いました。

2-3. 前処理

NearestNeighborを婚活データに適用します。
大きな方針は、「ユーザーの属性」を過去の参加履歴から計算し、開催されるイベントと属性が近いもの順にリコメンドしていくこととしました。

工夫点は以下の通りです。

  • ユーザーの属性を平均化する。

    • 例:参加費4000円のイベントに1回、参加費8000円のイベントに1回参加→「参加費」属性は、6000円
  • 数値化する

    • 「距離を計算する」アルゴリズムのため、全ての項目は数字である必要があります。
      以下項目は数字項目ではないため、数字にしました。
      変換の際、「その項目の本質的な情報を抜く」ことが大事です。
      • 「日付」
        • 本質的な情報は、「参加時間帯」。(平日休みの人は平日昼間のイベントを見るはず・・・)
        • 「平日昼間」「平日夜(19:00〜)」「休日昼」「休日夜」の4属性に変換しました。
      • 都道府県」
        • 本質的な情報は、「位置」。(東京にいる人に大阪のイベントは勧めないが、神奈川のイベントは勧めるかも)
        • 「緯度」「経度」に変換しました。
  • 重み付け

    • 時系列重み付け
      • 例:参加費4000円のイベントに昨日、参加費8000円のイベントに1年前に参加→「参加費」属性は4500円(直近参加の4000円に寄せる)
      • 具体的に言うと、ログをさかのぼるたびに0.99を掛けることで、昔のイベントの「重み」を軽くしました。
    • ログ重み付け
      • 「参加したイベント」のログは大きい重み付け、「見ただけ」のログは小さい重み付けをそれぞれ行い、ユーザーの属性に反映しました。

2-4. パラメータチューニング

ユーザーの属性を計算したら、次は「どの項目を重要視するか?」を考慮します。(パラメータチューニング)
例えば、ユーザーの属性が(参加費4000円付近が多い、平日昼間に参加が多い、東京付近が多い)だとしたとき、次のどのイベントを勧めるのが一番見込みがありそうですか?

  1. 参加費4000円、平日夜間、大阪 (「参加費」を重要視)
  2. 参加費5000円、平日昼間、大阪 (「時間帯」を重要視)
  3. 参加費5000円、平日夜間、東京 (「場所」を重要視)

多くの人は3.を選択するでしょう。つまり、数ある項目のなかで「場所」を重要視しているということになります。(=「場所」に大きな重みをかけている

パラメータの決め方は以下の流れで行いました。

  1. ドメイン知識(=常識:場所は大事でしょ、等)を考慮
  2. 以下を繰り返す
  3. 常識を考慮してランダムにパラメータを設定
  4. 予想、性能評価を行う
  5. 手順2の結果を検証し、パラメータに当たりをつける
  6. 3.により「常識」をアップデートし、2.に戻る

3. 結果

29位/158でした。
https://signate.jp/competitions/67/leaderboard

4.感想

「仮説」と「検証」の粒度が荒い
ここでいう仮説と検証は、

  • 仮説とは、AすればBになる
  • 検証とは、Bになったかを確かめる

ですが、仮説を立てるための材料が揃えられませんでした。

  • 結果を評価するための材料が「スコア」という非常に荒い材料しかなかった
    ex. 年齢別、都道府県別など、項目ごとにスコアがどうなっているのかを確かめる、など
  • データの分布を見きれなかった(機械学習というブラックボックスに投げ過ぎた)
    ex. 20代の人は比較的参加費が安いものに参加している→何か予想に反映できないか、など

複数のアルゴリズムを試したかった
xgboostのpairwiseを少し試したのですが、使い方がわからずNearestNeighborの半分くらいのスコアしか出ませんでした。
いろいろ試してみたいものはありました

  • xgboost(pairwise)
  • catboost(pairwise)
  • DeepLearning(RankNet)
    qiita.com
  • DeepLearning(ListNet)
    qiita.com

次回同じ課題が来た時はリベンジします。

これは機械学習なのか・・・?
「AIというブラックボックスが全て判断してくれる」という考え方は駄目、だけど、今回はゴリゴリやり過ぎたような気がしなくもないです・・・。

10日という短納期にしては悪くない出来だったなと思っていますが、時間があればもっとこうしたかった!!というのが多いです。。。

5. 告知

誰かコレ一緒にやりませんか?
Competitions | Kaggle

kaggleでメダル取りたいです。週5時間程度の作業で大丈夫です。
興味ある方はkurupicalあっとGmailかブログコメントによろしくお願いしますm( )m
プログラムの心得と意欲があれば初心者でもOKです