推薦システムとimplicitライブラリの利用方法

推薦システムは、ユーザーの嗜好や行動を分析し、個別に最適なアイテムを推薦するシステムである。その中で、Pythonのライブラリであるimplicitは特に有名であり、効率的な計算と使いやすさが特徴である。ここでは、implicitライブラリの使い方と、movielens-100kデータセットを利用した具体例について説明する。

ソースコード

この記事で利用するソースコードは以下の通りである。

github

  • jupyter notebook形式のファイルはこちら

google colaboratory

  • google colaboratory で実行する場合はこちら

実行環境

OSはmacOSである。LinuxやUnixのコマンドとはオプションが異なりますので注意していただきたい。

!sw_vers
ProductName:		macOS
ProductVersion:		13.5.1
BuildVersion:		22G90
!python -V
Python 3.9.17

基本的なライブラリをインポートし watermark を利用してそのバージョンを確認する。 ついでに乱数のseedの設定する。

%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import random
import numpy as np
import pandas as pd

import implicit

seed = 123
random_state = 123

random.seed(seed)
np.random.seed(seed)

from watermark import watermark

print(watermark(python=True, watermark=True, iversions=True, globals_=globals()))
Python implementation: CPython
Python version       : 3.9.17
IPython version      : 8.17.2

numpy   : 1.25.2
pandas  : 2.0.3
implicit: 0.7.0

Watermark: 2.4.3

推薦システムで利用されるimplicitの実装例

推薦システムとは

推薦システムとは、ユーザーの嗜好に基づいてアイテムを推薦するシステムである。例えば、Netflixではユーザーが視聴した映画に基づいて新しい映画を推薦する。推薦システムの種類には、大きく分けて協調フィルタリングとコンテンツベースフィルタリングがある。

協調フィルタリング

協調フィルタリングは、ユーザーの過去の行動や評価に基づいてアイテムを推薦する手法である。具体的には、ユーザー行動行列を用いる。

コンテンツベースフィルタリング

コンテンツベースフィルタリングは、アイテムの特徴や属性に基づいてアイテムを推薦する手法である。

implicitライブラリの概要

implicitはPythonで書かれたライブラリであり、特に協調フィルタリングのアルゴリズムを実装するために用いられる。implicitは主に以下のアルゴリズムをサポートしている。

  • ALS(Alternating Least Squares)
  • BPR(Bayesian Personalized Ranking)

Movielens-100kデータセットの概要

Movielens-100kは映画の評価データセットであり、100,000件の評価データが含まれている。このデータセットを用いることで、推薦システムの性能を評価することができる。

ALSアルゴリズムの詳細と実装

ALS(交互最小二乗法)は、ユーザーとアイテムの行列を因子分解する手法である。ALSでは、ユーザー行列とアイテム行列を交互に更新することで、予測行列を近似する。

ALSの表式

implicitのALSでは、非ゼロの観測値$r_{ui}$から嗜好$p_{ui}$と信頼度$c_{ui}$を次のように定める。

$$ p_{ui}=\mathbf{1}[r_{ui}>0], \qquad c_{ui}=1+\alpha r_{ui} $$

ユーザー因子$\mathbf{x}_u$とアイテム因子$\mathbf{y}_i$は、次の最小化問題を交互に解いて求める。

$$ \min_{\mathbf{X},\mathbf{Y}} \sum_{u,i} c_{ui}\left(p_{ui}-\mathbf{x}_u^T\mathbf{y}_i\right)^2

  • \lambda\left(\sum_u|\mathbf{x}_u|^2+\sum_i|\mathbf{y}_i|^2\right) $$

ここで、$\alpha$は信頼度の重み、$\lambda$は正則化パラメータである。

ALSの実装

次に、implicitライブラリを用いたALSの実装例を示す。 MovieLensの評価は明示的フィードバックなので、ここでは評価4以上を暗黙的な正例として扱う。

import implicit
from scipy.sparse import coo_matrix
from pprint import pprint

# データの読み込みと前処理
df = pd.read_csv("./ml-100k/u.data", sep="\t", names=["user_id", "item_id", "rating", "timestamp"])
positive_df = df[df["rating"] >= 4]
rows = positive_df["user_id"].to_numpy() - 1
cols = positive_df["item_id"].to_numpy() - 1
values = np.ones(len(positive_df), dtype=np.float32)

df.head()
user_iditem_idratingtimestamp
01962423881250949
11863023891717742
2223771878887116
3244512880606923
41663461886397596
# 評価行列を作成
R = coo_matrix((values, (rows, cols)), shape=(df["user_id"].max(), df["item_id"].max()))

# coo_matrixをcsr_matrixに変換
R = R.tocsr()

# ALSモデルの訓練
model = implicit.als.AlternatingLeastSquares(factors=20, regularization=0.1, iterations=50)
model.fit(R)

# ユーザーとアイテムの行列
U = model.user_factors
I = model.item_factors

# 結果の表示
pprint(U.round(2))
pprint(I.round(2))

BPRアルゴリズムの詳細と実装

BPRは、ランキングを最適化するための手法である。BPRは、ユーザーのpairwiseな選好を最大化することを目的とする。

BPRの数式

BPRは、ユーザーがあるアイテムを他のアイテムよりも好む確率を最大化する。具体的には、次の対数尤度関数を最大化する。

$$ \sum_{(u,i,j) \in D} \ln \sigma (\hat{x}_{u,i} - \hat{x}_{u,j}) - \lambda |\Theta|^2 $$

ここで、$\sigma$はシグモイド関数、$\hat{x}_{u,i}$はユーザー$u$がアイテム$i$に対して持つスコア、$D$は正例$i$と未観測例$j$からなる三つ組の集合、$\Theta$はモデルパラメータである。

BPRの実装

次に、implicitライブラリを用いたBPRの実装例を示す。

import implicit
from scipy.sparse import coo_matrix
from pprint import pprint

# データの読み込みと前処理
df = pd.read_csv("./ml-100k/u.data", sep="\t", names=["user_id", "item_id", "rating", "timestamp"])
positive_df = df[df["rating"] >= 4]
rows = positive_df["user_id"].to_numpy() - 1
cols = positive_df["item_id"].to_numpy() - 1
values = np.ones(len(positive_df), dtype=np.float32)

df.head()
user_iditem_idratingtimestamp
01962423881250949
11863023891717742
2223771878887116
3244512880606923
41663461886397596
# 評価行列を作成
R = coo_matrix((values, (rows, cols)), shape=(df["user_id"].max(), df["item_id"].max()))

# coo_matrixをcsr_matrixに変換
R = R.tocsr()

# BPRモデルの訓練
model = implicit.bpr.BayesianPersonalizedRanking(factors=20, regularization=0.1, iterations=50)
model.fit(R)

# ユーザーとアイテムの行列
U = model.user_factors
I = model.item_factors

# 結果の表示
pprint(U.round(2))
pprint(I.round(2))

実装例

具体的な実装例として、movielens-100kデータセットを用いて、ALSおよびBPRモデルを構築する。以下にその手順を示す。

データの準備

まず、データを読み込み、前処理を行う。

import implicit
import pandas as pd
import numpy as np

from scipy.sparse import coo_matrix
from implicit.evaluation import leave_k_out_split

# データの読み込みと前処理
df = pd.read_csv("./ml-100k/u.data", sep="\t", names=["user_id", "item_id", "rating", "timestamp"])

# 高評価を暗黙的な正例として評価行列を作成
positive_df = df[df["rating"] >= 4]
rows = positive_df["user_id"].to_numpy() - 1
cols = positive_df["item_id"].to_numpy() - 1
values = np.ones(len(positive_df), dtype=np.float32)
R = coo_matrix(
    (values, (rows, cols)),
    shape=(df["user_id"].max(), df["item_id"].max()),
).tocsr()

# 各対象ユーザーの正例を1件ずつテストデータに分割
train_matrix, test_matrix = leave_k_out_split(R, K=1, random_state=seed)

ALSモデルの訓練と評価

次に、ALSモデルを訓練し、評価する。

def get_precision(true_matrix, pred_items, k=10):
    """
    適合率を計算する関数

    Parameters:
    - true_matrix (csr_matrix): 実際の評価行列
    - pred_items (ndarray): 推薦されたアイテムID
    - k (int): 適合率を計算する際のtop_k itemの数

    Returns:
    - precision (float): 適合率
    """
    # 実際の評価行列をリストに変換
    true_items = true_matrix.tolil().rows

    # ユーザーごとの適合率を計算
    precisions = []
    for user_id in range(len(true_items)):
        true_set = set(true_items[user_id])
        pred_set = set(pred_items[user_id])

        if len(true_set) > 0:
            precision = len(true_set & pred_set) / k
            precisions.append(precision)

    # 平均適合率を計算
    return np.mean(precisions)
# ALSモデルの訓練
als_model = implicit.als.AlternatingLeastSquares(factors=20, regularization=0.1, iterations=50)
als_model.fit(train_matrix)

# 訓練データを使って推薦候補を生成
user_ids = np.arange(train_matrix.shape[0])
pred_items, _ = als_model.recommend(user_ids, train_matrix[user_ids], N=10)

precision = get_precision(test_matrix, pred_items)
print(f"ALSモデル Precision: {precision:.3f}")

BPRモデルの訓練と評価

同様に、BPRモデルを訓練し、評価する。

# BPRモデルの訓練
bpr_model = implicit.bpr.BayesianPersonalizedRanking(factors=20, regularization=0.1, iterations=50)
bpr_model.fit(train_matrix)

# 訓練データを使って推薦候補を生成
pred_items, _ = bpr_model.recommend(user_ids, train_matrix[user_ids], N=10)

# 精度の評価
precision = get_precision(test_matrix, pred_items)
print(f"BPRモデル Precision : {precision:.3f}")

結論

この記事では、implicitライブラリを用いてALSおよびBPRアルゴリズムを実装し、movielens-100kデータセットでの具体例を紹介した。 基本的には自分用のメモだが、誰かの参考になれば幸いである。

参考文献

  • “Collaborative Filtering for Implicit Feedback Datasets”, Hu, Y., Koren, Y., and Volinsky, C., 2008.
  • “BPR: Bayesian Personalized Ranking from Implicit Feedback”, Rendle, S., Freudenthaler, C., Gantner, Z., and Schmidt-Thieme, L., 2009.
  • Movielens Dataset: https://grouplens.org/datasets/movielens/100k/

メモ

LIL形式の疎行列を作成 (3x3の行列)

import numpy as np
from scipy.sparse import lil_matrix

# Numpy配列の作成
dense_array = np.array([[1, 0, 0], [0, 0, 3], [4, 0, 0]])

# Numpy配列をLIL形式の疎行列に変換
lil_matrix = lil_matrix(dense_array)

print(lil_matrix)
  (0, 0)	1
  (1, 2)	3
  (2, 0)	4