行動履歴をもとに協調フィルタリングとWord2Vecでレコメンドしてモデルの精度を評価する

行動履歴をもとに協調フィルタリングとWord2Vecでレコメンドしてモデルの精度を評価する

レコメンド関連の勉強のために使えるデータを探していたところ、Kaggleで丁度良いデータセットがあったので、今回はユーザの行動履歴をもとにアイテムをレコメンドする方法とそのレコメンドモデルを評価する方法を説明します。
使用するアルゴリズムは古典的なアイテムベース協調フィルタリングと、割と新しい手法であるWord2Vec(アイテムを分散表現するのでitem2vecとも呼ばれます)です。
Word2Vecを使ったレコメンドの実装は、リクルートの以下の発表を参考にしました。

ここで、ユーザの行動履歴とは、ECサイトで例えるとユーザが商品を閲覧/購買した履歴のことを意味します。
また、レコメンドモデルの評価にはオンライン評価とオフライン評価の2つがありますが、今回はオフラインでの評価を実装しました。

データセットの説明

Kaggle Job Recommendation Challengeというコンペのデータセットを使用します。
このデータセットは、CareerBuilder.comという求人検索エンジンをもつ企業が提供してくれたものになります。

提供されているデータセットにはいろいろなバリエーションがありますが、今回はユーザの求人への応募履歴(apps.tsv)のみにフォーカスします。
apps.tsvの以下の3カラムだけを使用します。

カラム名説明
UserIDユーザID
ApplicationDate求人への応募日時
JobID求人ID

Kaggleのコンペページからデータをダウンロードし、apps.tsvを読み込み、今回使うカラムの情報を確認します。
INPUT:

OUTPUT:

30万強のユーザや求人があることや、2012年4月〜6月における求人への応募データということがわかります。

ただ、各ユーザが求人への応募を2ヶ月に渡ってするのか?という疑問があるので、1ユーザあたりの応募期間の分布を確認してみます。

OUTPUT:

予想通り、大半のユーザは2週間以上に渡って応募行動をしていないようです。
おそらく数件求人に応募したらアクションが終了になるのではないかと思います。

次に1ユーザが同じ求人に応募していないか(重複)がないかを確認します。

結果は0なので、1ユーザが複数回同じ求人に応募していないことがわかりました。

前処理

後で構築するレコメンドモデルに学習データとして入力できるようにデータを整形・加工します。

まず、Word2Vecではユーザごとに時系列でJobIDがソートされている必要があるので、以下を実行します。

次に学習データとテストデータに分割します。
今回は応募日時(ApplicationDate)に応じて学習データとテストデータに分割します。

  • 学習データ:2012/4/1~2012/6/21
  • テストデータ:2012/6/21~2012/6/28

ここで、Word2Vecに入力するデータは、ユーザ単位でJobIDがlistになっている必要があります。
また、Word2Vecの学習データはJobIDのみで構成されていてUserIDの情報がないので、推論(most_similar)時に各レコメンド結果をUserIDと紐づけるためにも辞書を作成しておく必要があります。

レコメンドモデル構築

協調フィルタリング

Appleが開発した機械学習ライブラリのTuri Createを使ってアイテムベース協調フィルタリングによるレコメンドモデルを構築します。
user_idとitem_idを指定するだけで、サクッとアイテムベース協調フィルタリングによるレコメンドモデルを構築できます。

Word2Vec

gensim.Word2Vecを使ってモデルを構築します。
なお、今回はハイパーパラメータのmin_count以外はデフォルトにしています。
min_countを1にしている理由は、most_similarで合成ベクトルを作る際に、モデル空間に存在するかどうかを考慮しない(簡略化する)ためです。

推論

今回は、学習データとテストデータに共通して存在しているユーザを対象にレコメンドし、その結果を評価します。
まずは、学習データとテストデータに共通して存在しているユーザを抽出します。

OUTPUT:

この13,485人を対象にレコメンドします。

協調フィルタリング

recommendメソッドでお手軽にレコメンドを実行できます。
rank(評価点)を引数に入れない場合、item_base_collaborative filtering(アイテムベース協調フィルタリング)を実行します。

Word2Vec

アイテムベース協調フィルタリングの場合とは異なり、Word2Vecのmost_similar結果には学習時に使用したアイテム(つまり過去に応募したJobID)が含まれてしまう場合があるため、やや工夫が必要です。
応募済みのJobIDをレコメンドしないために、各ユーザに対して以下の工程を行います。

  1. ユーザが応募したJobIDベクトルを全て合成し、類似度上位100件を取得
  2. 類似度上位100件の中で過去に応募したJobIDがあれば削除

ここで、アイテムベース協調フィルタリングと同じ30件ではなく100件を抽出している理由は、応募したJobIDを削除した後でもJobIDが30件以上必ず残したいためであり、なんとなく100件に指定しているだけです。

レコメンド結果のオフライン評価

協調フィルタリング、Word2Vecを使ったレコメンド結果を評価していきます。
レコメンドの評価にはオンライン評価、オフライン評価の2通りの評価方法が存在しますが、今回はオフライン評価を行います。
オンライン評価、オフライン評価を説明すると以下になります。

分類説明
オンライン評価レコメンド結果を実際にユーザに提示して、ユーザのコンバージョン率などを評価します。例)A/Bテスト
オフライン評価過去のある時点における実績をもとにレコメンドし、ユーザの実際の行動をどれくらい予測できるかなどを評価します。例)Precision@K, Recall@K

オンライン評価、オフライン評価を詳しく知りたい方はブレインパッドさんのブログが大変参考になります。

さて、まずはオフライン評価で代表的なPrecision@KとRecall@Kを測定するメソッドを定義します。

指標説明
Precision@Kレコメンドしたアイテムのうち、どれくらいユーザの行動を予測できていたかを測る指標
Recall@Kユーザの実際の行動のうち、どれくらいレコメンド結果と一致するかを測る指標

では、定義したメソッドを使って、協調フィルタリングとWord2Vecのレコメンドの評価を行います。

オフライン評価で見た場合、Word2Vecよりも協調フィルタリングの方がユーザの実際の行動を補足できていることがわかります。
さすがに差がありすぎてWord2Vecが可哀想なので、カバレッジ(coverage)についても評価してみます。
ちなみに、カバレッジ(coverage)は、レコメンドしたアイテムが極端に偏っていないかを測る指標です。カバレッジが大きいほど満遍なくレコメンドができていて、小さいほどレコメンドされるアイテムに偏りがあることになります。


min_count=1にしているせいか、Word2Vecのカバレッジが90%を超えています。
一方、協調フィルタリングはカバレッジが20%を下回っていて、レコメンドするアイテムにかなり偏りがあることがわかります。

まとめ

今回はオフライン評価指標のPrecision@K(適合率)、Recall@K(再現率)、Coverage(カバレッジ)でレコメンドモデルの精度を比較しましたが、この他にもたくさんの評価指標があります。
オフライン評価指標はユーザに実際にレコメンドした結果に基づいたものではなく、あくまでユーザにレコメンドしたと仮定し、それがユーザの行動をどれくらい予測したものなのかを測定するものです。
たとえオフライン評価で精度が良くても、オンライン評価(CVRのA/Bテストなど)では精度が悪くなる場合もあります。
結局、結果が重要なのだからオンライン評価だけを使えばいいではないかという声が聞こえてきそうですが、レコメンドで使えるモデルは今回紹介したもの以外にもたくさんあり、Word2Vecのハイパーパラメータでさえしっかりチューニングしようとすると限りなくA/Bテストのパターンを作る必要があります。
オンライン評価はオフライン評価に比べて格段に工数や時間がかかるため、ここぞというモデルの比較に使うべきでしょう。
目的に応じてどのオンライン評価指標やオフライン評価指標を使うのか、よ〜く議論が必要です。