jiku log

データサイエンスの核心を掴む : 学びと発見の記録

「Pythonではじめるベイズ機械学習入門」を読む ~第4章 潜在変数モデル③(確率的行列分解)~

4.2 行列分解モデル

行列分解モデル(Matrix Factorization Model)は,観測値を表す行列を,より次元の小さい行列の積に分解することである。
ノイズを除外した本質的なデータの特徴を得られることや,欠損値を補完できることがその利点である。

4.2.4 モデル概要 : 確率的行列分解

レコメンデーションにおいて,協調フィルタリング(Collaborative Filtering)は最も一般的な手法である。
確率的行列分解は,協調フィルタリングの代表的な手法の1つである。


確率的行列分解では,ユーザおよびアイテムを,その潜在的な特徴を表す低次元の埋め込みベクトルで表現する。ユーザとアイテムの埋め込みベクトルの類似度を評価し,類似度が高いほど両者がマッチしている,と評価する。

具体的なモデル式について説明する。
ユーザの数を N,アイテムの数を M,ユーザ nのアイテム mに対する評価を R_{nm} \in \mathbb{R}とする。
このため,レーティング行列 Rは, R \in \mathbb{R}^{N \times M}となる。

ユーザの埋め込みベクトルを u_n \in \mathbb{R}^K,アイテムの埋め込みベクトルを v_m \in \mathbb{R}^Kとする。
さらに, u_nをまとめた行列 U U = (u_1, \cdots, u_N) v_nをまとめた行列 V V = (v_1, \cdots, v_M)とする。

 R, U, Vの関係を表すと下図のようになる。


次に確率モデルを考える。
ユーザはすべてのアイテムを評価しているわけではないので,ユーザ nがアイテム mを評価している場合に1,それ以外は0となる指示変数 I_{nm}を導入する。

レーティング行列 Rが従う確率分布を以下のように定義する。


 \begin{align}
p(R | U, V, \alpha) = \prod_{n=1}^{N} \prod_{m=1}^{M} \left [ \mathcal{N}(R_{nm} | u_n^T v_m, \alpha^{-1})  \right ] ^{I_{nm}}  \\
\end{align}

また, U, Vの事前分布は平均0のガウス分布とする。


 \begin{align}
p(U | \alpha_U) &= \prod_{n=1}^{N} \mathcal{N} (u_n | 0, \alpha_U^{-1} I )  \\  \\
p(V | \alpha_V) &= \prod_{m=1}^{M} \mathcal{N} (v_m | 0, \alpha_V^{-1} I )  \\ 
\end{align}

精度パラメータ \alpha, \alpha_U, \alpha_Vに事前分布を設定してもよいが,本節では簡単のため固定値とする。

4.2.5 実装:確率的行列分解によるレコメンデーション

サンプルコードを動かしながら,挙動を確認した。
github.com

データの準備

データは,GroupLensが公開しているMovieLens 100Kという,映画のレーティングに関するデータセットを題材とする。
http://files.grouplens.org/datasets/movielens/ml-100k/u.data

列は,ユーザID(user_id),映画ID(item_id),レーティング(rating)の順に並んでいる。

user_id item_id rating
0 196 242 3
1 186 302 3
2 22 377 1
3 244 51 2
4 166 346 1


このデータは,

  • ユーザ数:943人
  • 映画:1682本
  • レーティングがついていない割合:94%

という,欠損値が非常に多いデータである。

本節では,MovieLens 100Kのデータを学習データとテストデータに分割し,確率的行列分解によるレーティングの予測性能を評価する。
なおテストデータには,ランダムに選択した10%を用いる。

評価

評価指標には,二乗平均平方誤差(Root Mean Squared Error; RMSE)を用いる。
また予測結果と比較するために,ユーザごとの平均レーティング・映画ごとの平均レーティング・全体の平均レーティングの3つの平均値の平均をベースラインとする。
なお,ベースラインのRMSEは1.02であった。

モデルの定義

4.2.4節で示したようなモデルを定義する。
ただし, U, V標準偏差は,それぞれユーザ・アイテム(映画)の標準偏差を平均値に固定する。

MCMCによる事後分布からのサンプリング

MCMCによるサンプリングを行なう。2024年12月現在,PyMC3ではなくPyMCを使うので,ライブラリのインポート設定は以下のようになる。

#import pymc3 as pm
import pymc as pm

本節において,サンプリングにはHMCを用いるが,サンプルの自己相関が高めだったため,MCMCで得られる5つのサンプルごとに1つだけ取り出す(間引き(thinning))。


 U, Vは大きい行列であるため,各パラメータのトレースプロットを確認することは,膨大なパラメータを確認する必要があり難しい。
そのため,各ステップにおける U, Vのフロベニウスノルムを可視化する。なおフロベニウスノルムは,


 \begin{align}
\lVert U \rVert _F = \sqrt{ \sum_{n=1}^{N} \sum_{k=1}^{K} U_{nk}^2  }   \\
\end{align}

のように定義する。

フロベニウスノルムの推移は下図の通りである。

確認したところ,フロベニウスノルムは安定して推移しているように見える。

レーティングの予測

得られた事後分布からのサンプルを用いて,予測性能の評価を行なう。
MCMCにより,ステップごとの U, Vのサンプルが得られるので,このサンプルを用いて Rの確率分布を定義し,この確率分布から得られるサンプルをRのサンプルとみなす。
またRのサンプルについて,①各時点でのサンプルの値と,②各時点までのサンプルの平均値 の2種類が考えられる。
これに学習データとテストデータを組合わせて,以下の4種類のRMSEを評価する。

  1. per-step-train : ある時点の Rの予測値と,学習データとのRMSE
  2. running-train : ある時点までの Rの予測値の平均と,学習データとのRMSE
  3. per-step-test : ある時点の Rの予測値と,テストデータとのRMSE
  4. running-test : ある時点までの Rの予測値の平均と,テストデータとのRMSE

MCMCのサンプルごとの各種RMSEの推移は下図のようになる。

per-step-trainとper-step-test,およびrunning-trainとrunning-testとを比較すると,いずれも学習データのRMSEが小さくなっているため過剰適合を起こしているが,ベースラインのRMSEである1.02よりも良い値(小さい値)が得られていることが確認できた。

まとめと感想

潜在変数モデルのうち,確率的行列分解について学んだ。

行列分解により,行列の潜在的な特徴が得られて,ユーザ間の類似度を計算できるようになるなど,様々な情報を得られることが分かった。
行列分解の手法や用途は他にもあると考えられるので,今後調べてみたい。

本記事を最後まで読んでくださり,どうもありがとうございました。

参考サイト

github.com