今回はこのサイトのmovie recommender system(映画推奨システム)を試してみる。映画推奨システムとは、映画鑑賞者お気に入りの映画を参考にしてその映画に似たその鑑賞者が気に入りそうな映画を推奨してくれるシステムのことだ。
スポンサーリンク
環境設定¶
cd git
gitをクローンする。
!git clone https://github.com/xmuffin/cupcake.git
クローンしたgitフォルダに移動する。
cd cupcake
スポンサーリンク
データのダウンロード¶
下記のサイトから必要なデータをダウンロードして解凍する。
!curl -SOL http://files.grouplens.org/datasets/movielens/ml-latest-small.zip
!unzip ml-latest-small.zip
ダウンロードした書庫ファイルを消去する。
!rm -f ml-latest-small.zip
スポンサーリンク
Loading data¶
モジュールのインポートとデータのロード
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
movies = pd.DataFrame.from_csv('./ml-latest-small/movies.csv', index_col=None)
ratings = pd.DataFrame.from_csv('./ml-latest-small/ratings.csv', index_col=None)
ratings.drop(labels=['timestamp'], axis=1, inplace=True)
# Fixing movieIds to use them with userIds as indices
dict_norm_movieId = dict([(trueId, normId)
for normId, trueId in enumerate(np.sort(pd.unique(ratings['movieId'])))])
norm_movieId = list()
old_movieId = dict()
for rating in ratings.as_matrix():
norm_movieId.append(dict_norm_movieId[rating[1]])
old_movieId[dict_norm_movieId[rating[1]]] = rating[1]
ratings['movieId'] = norm_movieId
ratings['userId'] = ratings['userId'] - 1
ratings["rating"] = ratings["rating"].astype(np.float32)
def train_test_split(df, train_size=0.9, random_state=123):
df = df.iloc[np.random.permutation(df.shape[0])].reset_index(drop=True)
return np.array(df[:int(train_size * df.shape[0])]), np.array(df[int(train_size * df.shape[0]):])
X_train, X_test = train_test_split(ratings)
X_train.shape, X_test.shape
スポンサーリンク
Fitting BMF model¶
from cupcake.models import BMF
bmf = BMF(max_iter=500, device='GPU', verbose=1)
bmf.fit(X_train, X_test)
y_hat = bmf.predict(ratings['userId'].values, ratings['movieId'].values)
y_hat.shape
スポンサーリンク
Recommending movies¶
(推奨を作成するためのもっと複雑なメソッドが存在するが)、とりあえず上位Nの推論(推奨)映画だけを表示する。
I = pd.Index(sorted(pd.unique(ratings['userId'])), name='userId')
C = pd.Index([int(old_movieId[col]) for col in sorted(pd.unique(ratings['movieId']))], name="movieId")
y_hat = pd.DataFrame(y_hat, index=I, columns=C)
y_hat.head()
def recommend_movies(y_pred, userId, movies, ratings, top_n=5):
true_ratings = ratings.copy()
true_ratings['movieId'] = [int(old_movieId[movieId]) for movieId in ratings['movieId']]
# Let's sort ratings for given user and put into separate DataFrame
ratings_u_pred = y_pred.iloc[userId].sort_values(ascending=False)
ratings_u = true_ratings[true_ratings['userId'] == userId].merge(movies,
how='left',
left_on='movieId',
right_on='movieId').sort_values(['rating'],
ascending=False)
# Get information about top_n films
recommendations = movies[~movies['movieId'].isin(ratings_u['movieId'])].\
merge(pd.DataFrame(ratings_u_pred).reset_index(),
how='left',
left_on = 'movieId',
right_on = 'movieId').\
rename(columns={userId : 'predicted_rating'}).\
sort_values('predicted_rating', ascending = False).\
iloc[:top_n]
ratings_u.reset_index(drop=True, inplace=True)
recommendations.reset_index(drop=True, inplace=True)
ratings_u = ratings_u[['title', 'rating']]
ratings_u.columns = ['already_watched', 'rating']
recommendations = recommendations[['title', 'predicted_rating']]
recommendations.columns = ['RECOMMENDED_MOVIE', 'PREDICTED_RATING']
recommendations['PREDICTED_RATING'] = recommendations['PREDICTED_RATING'] * 5 / np.max(recommendations['PREDICTED_RATING'])
return pd.concat((ratings_u, recommendations), axis=1)
recommend_movies(y_hat, 100, movies, ratings, 50)
Inception(渡辺謙が出演した映画)とRun Lola Run (Lola rennt)はなかなか絶妙な推奨だと思うけど、後はどうかなってのが多い。
スポンサーリンク
スポンサーリンク