TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

アニメデータセットでリコメンドを試す(NMF編)

少し古いがWEB+DB PRESS Vol.129のレコメンドエンジンの記事を読んでいて、勉強のために記事とは異なるデータセットで試したいと思った。

記事ではMovieLensのデータセットで使っているが、アニメレビューのデータセットを使って試してみた。

モチベーション

見たいアニメを探すときに、全体で人気の高い作品よりも、自分に似たユーザが高く評価している作品を探せると、より自分に合った作品を探すことができる。
そのような場合に、レコメンドエンジンを使うと、多数のユーザのレビューの情報から、自分に合った作品を探すことができる。

データセット

アニメレビューのデータセットを探したところ、Kaggleに「Anime Recommendations Database vol.2」というデータセットを見つけた。
Anime Recommendations Database vol.2 | Kaggle

MyAnimeList.netからスクレイピングして作成したデータセットのようだ。
作品ごとのレーティングと、ユーザごとの作品のレーティングが含まれる。

ユーザごとの作品のレーティングには、11,039,694件のデータがある。

アルゴリズム

レコメンドエンジンのアルゴリズムには、古典的には協調フィルタリングがあるが、データ数が多いと次元の呪いの問題に合い計算量が指数的に増加してしまう。

次元圧縮を行う方法に、行列分解により行列を近似する非負値行列因子分解(Non-negative Matrix Factorization; NMF)がある。
行列分解による方法は、2008年のNetflix Prizeで優勝したアルゴリズムで使われてた方法である。

テストデータ

データセットのデータで評価しても面白くないので、自分で選んだ作品を元に、新しい作品を推薦できるか試すことにした。

傾向が似ていそうな以下のアニメを選択し、これらのレーティングを10とした。

anime_id title
8769 Ore no Imouto ga Konnani Kawaii Wake ga Nai
5680 K-On! Music,Slice of Life,Comedy,School
1195 Zero no Tsukaima
21273 Gochuumon wa Usagi Desu ka?
31953 New Game!

実装

データ準備

データセットのユーザごとの作品のレーティングを読み込み、テストデータを追加する。
テストデータのユーザIDは使用されていない0とする。

import pandas as pd
import numpy as np

ratings = pd.read_csv('ratings.csv')
myratings = pd.DataFrame([{'user_id': 0, 'anime_id': anime_id, 'rating': 10} for anime_id in [31953, 8769, 5680, 1195, 21273]])
ratings = pd.concat([ratings, myratings])
疎行列作成
from scipy.sparse import csr_matrix

matrix_data = csr_matrix((ratings['rating'], (ratings['user_id'], ratings['anime_id'])))
NMFによる行列分解

潜在因子の次元に圧縮して因子行列を得る。

from sklearn.decomposition import NMF

latent = 50
nmf = NMF(n_components=latent)
# ユーザ因子行列
W = nmf.fit_transform(matrix_data)
# アイテム因子行列
H = nmf.components_

処理時間は、3分くらいかかった。

行列復元

因子行列を復元することでレコメンドのためのスコアデータを得る。

WH = np.dot(W, H)
レコメンド

テストデータ(ユーザID=0)の行をソートして、上位10件の作品を取得する。

top10 = np.argsort(WH[0])[::-1][:10]
animes[animes['anime_id'].isin(top10)]

結果

rank anime_id title rating
1 66 Azumanga Daioh 7.97
2 355 Shakugan no Shana 7.5
3 356 Fate/stay night 7.32
4 1195 Zero no Tsukaima 7.3
5 1691 Kaze no Stigma 7.24
6 1840 Zero no Tsukaima: Futatsuki no Kishi 7.47
7 1887 Lucky☆Star 7.76
8 2787 Shakugan no Shana II (Second) 7.6
9 2966 Ookami to Koushinryou 8.26
10 2993 Rosario to Vampire 6.82

テストデータに選んだ作品のシリーズや、ラノベ作品が比較的多く選ばれた。

テストデータ2

別のデータでも試してみた。

anime_id title
16498 Shingeki no Kyojin
6336 Mobile Suit Gundam Unicorn
30 Neon Genesis Evangelion
1575 Code Geass: Hangyaku no Lelouch
14719 JoJo no Kimyou na Bouken (TV)
結果

上位10件は、以下のような結果になった。

rank anime_id title rating
1 20 Naruto 7.92
2 30 Neon Genesis Evangelion 8.32
3 31 Neon Genesis Evangelion: Death & Rebirth 7.45
4 32 Neon Genesis Evangelion: The End of Evangelion 8.52
5 33 Kenpuu Denki Berserk 8.49
6 43 Koukaku Kidoutai 8.29
7 47 Akira 8.17
8 199 Sen to Chihiro no Kamikakushi 8.81
9 227 FLCL 8.03
10 269 Bleach 7.8

今度は、だいぶ作品の傾向が変わり、少年漫画系の作品が多く選ばれている。
単にレーティングが高い作品が選ばれているわけでないことが確認できた。

まとめ

アニメレビューのデータセットを使ってレコメンドを試してみた。
レコメンドエンジンのアルゴリズムには行列分解による方法(NMF)を使った。
自分でテストデータを作成して、傾向が似た作品が選ばれるかを確認したろこと、ある程度傾向が似た作品が選ばれることが確認できた。

次は、深層学習を使ったレコメンドを試したい。