レコメンドの「模様」を描く〜Matrix Factorizationの因子数比較〜
※2020/03/08
本稿の記述には誤りがあります。
今回適用したアルゴリズムでは,正則化項は入れておらず,代わりにUser, Itemごとの平均的な評価を表すBias項が入っていました。
本日中に訂正します。
2020/03/08 13:20 修正しました。
にわかレコメンド屋さん,始めました。
協調性がないので,まずは協調フィルタリングから勉強しています。
今回のお題
さて,協調フィルタリングというと,最初にベクトル類似度に基づく近傍法,その次にMatrix Factorization(因子分解法ともいう)がくると思います。
こうしたレコメンドアルゴリズムでは,User-Item行列を元に各Userの各Itemに対する評価を推定して新たなレコメンド評価値を作成します。
このとき,入力の評価値とモデルの出力するレコメンド評価値は,どのように対応しているのでしょうか?
これを視覚的に捉えるために,User-Item行列と出力レコメンド評価値をヒートマップにして可視化してみました。
特に今回は,Matrix Factorizationを中心に扱い,Itemカテゴリ数に対応する重要なハイパーパラメータ集約次元数(と表す)を変えた時の振る舞いについて見ていきたいと思います。
計算・描画に用いたPythonコードは以下にアップしましたので,併せてご覧ください。
https://gist.github.com/tatamiya/439728c3e0b61bb1d0e9f59194031729
アルゴリズムの概要
Matrix Factorizationの一般的な話
ここではMatrix Factorizationについて簡単に説明します。
User-Item行列は全Userの,各Itemに対する評価を行列に表したものです。
したがって,User数を, Item数をとすると,は次元となります。
この行列を以下のように分解近似するのが,Matrix Factorizationの基本的な考え方になります:
ここで,は大きさ,はの行列で,整数はハイパーパラメータです。
は因子数で,上記の分解がうまく行った場合はItemカテゴリ数に相応すると考えられています。
つまり,行列は各Userの各カテゴリに対する評価・嗜好性,は各Itemのカテゴリ成分(映画なら「コメディ: 50%, ドキュメンタリ: 10%,アニメ: 40%」など) のように解釈が可能になります。
Funkの方法
今回扱うアルゴリズムは,レコメンドにおけるMatrix Factorizationの中でも,Netflix PrizeにてSimon Funkが用いて一般的に広まるきっかけとなった手法*1を元にしています。
上記で説明したものとの一番の違いは,Bias項といって,Userごと,Itemごとの平均値に相当するものを入れている点です。
これにより,あるUser の各Item に対するレコメンド評価値は,以下のように表されます:
は,それぞれ,
- : 全体の平均評価値
- : User の平均的な評価傾向
- : Item への,全Userの平均的な評価傾向
を表しています。
後半のは,分解後の行列の積です。
前述の因子数とカテゴリ数の関係をもとに考えると,この項はUserのカテゴリ嗜好性に基づいて算出された補正項と捉えられそうです。
以上から,レコメンド評価値は,
- バイアス項: User, Itemの平均的な評価値をもとに算出した予測値
- 行列分解項: ユーザーのカテゴリー嗜好性に基づく補正項
の2つから成ると考えることにしましょう。
そのほかにも,分解後の行列成分が大きくなりすぎないよう,正則化項を入れる場合もありますが,今回は割愛します。
ヒートマップによる可視化
可視化の前に,まず使用するデータについてです。
サンプルデータとしては,定番のMovieLensという,映画を0.5~5で数値評価したデータを用いたいと思います。*2
User数は610人,Item数は評価があるもので9,724個なので,User-Item行列はの大きさです。
全部で約600万成分ありますが,実際に評価が行われているのは100,836件なので,User-Item行列はほとんどの成分が空白な疎行列となっています。
これをもとに,Matrix Factorizationでモデルを作成し,全User, Itemのレコメンド評価値を算出したいと思います。
入力データ
まずはUser-Item行列を描いてみます。
色が濃いところほど評価が低く,明るいオレンジほど高評価になります。
白い部分はUserの評価がない部分です。
最適な因子数での比較
まず最初に,GridSearchで最適パラメータを探したところ,の時RMSEが最小になりました。
この時のレコメンド評価値をMatrixで表し,描画したのが以下です。
入力のUser-Item行列と比べ,未評価で白抜きだったところがべったり埋まっています。
全体的に縦と横の縞がタータンチェックのように並んでいますが, 色の濃い横縞をたどってみると,なんとなくUser-Item行列と一致していそうに見えます。ちなみにこの濃い横筋は,低評価をつけがちなUserを表しています。
縦縞についても,movieId 27370のあたりをみると,User-Item行列とレコメンド評価値の両方に色の薄い帯が伸びているのがわかります。
これらから,各Userの平均的な評価傾向と各Itemの平均評価を混ぜて全体をならしたような出力になっていると見られそうです。
パラメータを変えた場合
ではを1~10000の範囲で動かして試してみます。
因子数を増やすにつれて,だんだんとノイズが乗ったような図になっていきます。
ちなみに,これを10000まで増やすとこうなります。(めっちゃ時間かかった)
だいぶ跡形がないですね。
まとめ
因子数の解釈
Matrix Factorizationで最適な因子数を選んだ場合,出力されたレコメンド評価値はユーザーとアイテムそれぞれの平均的な評価傾向を組み合わせたようなパターンを持っていました。
これは,今回扱ったFunkの方法ではUser, Itemの平均評価値に相当するバイアス項が効いているためと考えられます。
一方,を大きくするにつれ,全体にぼやっとしたノイズが乗っていきました。
一般に,バイアス項のない通常の特異値分解では,因子数にあたるパラメータを増やすほど元の行列に近づいていき,最終的には厳密に入力と同じ値を復元できます。*3
これをもとに考えると,行列分解項は,が大きくなるにつれ入力評価値そのものを再現する作用を強めていくと考えられます。
バイアス項がUser-Item行列を縦横方向に平滑化し,行列分解項がUserの実際の購買履歴に近づけると考えると,因子数は購買履歴の再現度を調整するためのパラメータと考えられるかもしれません。
正則化項について
本記事を公開時点では,通常の特異値分解と今回扱ったFunkの方法との違いを,正則化項の有無として議論していました。
しかしながら,今回扱ったライブラリscikit-surpriseの仕様を改めて確認したところ,実際の計算には正則化項は含まれておらず代わりにバイアス項が含まれていることが判明しました。
これをもとに,記事を修正いたしました。
正則化項の有無にによるレコメンド結果の差ついては,通常の特異値分解とのアルゴリズム比較と併せて別の機会に議論したいと思います。