[推奨システム]CF/MFに基づく推奨システムモデリング実践
n/a.ターゲット
コラボレーションフィルタリングベース、マトリクス分解ベースの推奨モデルの理解と実装
訓練モデルの結果を説明し,結果を評価した.
データの読み込み
import pandas as pd
rating_url = 'https://raw.githubusercontent.com/yoonkt200/python-data-analysis/master/data/ml-1m/ratings.dat'
rating_df = pd.io.parsers.read_csv(rating_url, names=['user_id', 'movie_id', 'rating', 'time'], delimiter='::', engine ='python')
rating_df.head()
movie_url = 'https://raw.githubusercontent.com/yoonkt200/python-data-analysis/master/data/ml-1m/movies.dat'
movie_df = pd.io.parsers.read_csv(movie_url, names=['movie_id', 'title', 'genre'], delimiter='::', engine ='python', encoding='ISO-8859-1')
movie_df.head()
各データフレームには、次の情報が含まれます.
import pandas as pd
rating_url = 'https://raw.githubusercontent.com/yoonkt200/python-data-analysis/master/data/ml-1m/ratings.dat'
rating_df = pd.io.parsers.read_csv(rating_url, names=['user_id', 'movie_id', 'rating', 'time'], delimiter='::', engine ='python')
rating_df.head()
movie_url = 'https://raw.githubusercontent.com/yoonkt200/python-data-analysis/master/data/ml-1m/movies.dat'
movie_df = pd.io.parsers.read_csv(movie_url, names=['movie_id', 'title', 'genre'], delimiter='::', engine ='python', encoding='ISO-8859-1')
movie_df.head()
rating_df
user id:映画を見るユーザid
映画id:映画id
評価:映画に対するユーザーの評価
time:ユーザーが映画を見る時間
movie_df
映画id:映画id
映画タイトル
タイプ:ムービータイプ
EDA
print("고유 아이디 수:", len(rating_df["user_id"].unique()))
print("영화의 개수:", len(rating_df["movie_id"].unique()))
>>> 고유 아이디 수: 6040
>>> 영화의 개수: 3706
import seaborn as sns
sns.countplot(rating_df["rating"])
object_cnt = rating_df["rating"].value_counts()
for x,y,z in zip(object_cnt.index, object_cnt.values, object_cnt.values/object_cnt.sum()*100):
plt.annotate(f"{y}\n({round(z,2)}%)", xy=(x-1,y+70), textcoords="data", ha="center")
4点の最多は348971点、1点の最小は56174点だった.
Rating Matrix
Rating Matrixは、ユーザを行、ItemをColumn、ValueをRatingとする行列である.
Ratingのタイプには、Explicit FeedbackとImplicit Feedbackがあります.Explicit Feedbackとは、映画点数、評論点数、賛など、ユーザーが直接評価の良し悪しを明確にするデータであり、Implicit Feedbackとは、ユーザーが閲覧、視聴、購入、コメントなどの単純なマトリクスや使用するデータを指す.
推奨モデルとしてRating Matrixを用いた方法としては,コラボレーションフィルタリング(CF)とマトリックス分解(MF)がある.
Colaborative Filtering Modeling
1つの方法は、お客様の好みと興味の表現に基づいて、好みと興味の中から似たようなパターンを持つお客様を見つけることです.趣味が合うお客様には、まだ購入していない商品は、クロス推薦や分類されたお客様の好みや生活形態に応じて、関連商品を推薦する形式のサービスを提供することができます.
User-based CF / Item-based CF
ユーザーベースの広告:似たような好みの顧客評価の点数に基づいて、どんな商品を推薦するかを予測します.一般的な方法
Item-based CFに基づく:商品と商品の類似度を基準として推奨する.新しく登場した商品には適用しにくい欠点がある.
CFに基づくKNNモデル学習
from surprise import Dataset, Reader
from surprise.model_selection import train_test_split
# Reader, Dataset 오브젝트로 학습용 데이터셋 생성 및 분리
reader = Reader(rating_scale=(1,5)) #1~5점 사이의 rating점수가 있다는 것을 알려줌
data = Dataset.load_from_df(rating_df[["user_id", "movie_id", "rating"]], reader)
trainset, testset = train_test_split(data, test_size=0.25)
# KNNBasic 모델 학습
from surprise import KNNBasic
# k: 주변 샘플을 몇 개까지 참조할 것인지, cosine: 가장 일반적인 유사도 계산 방식
algo = KNNBasic(k=40, min_k=1, sim_options={"user_based":True, "name":"cosine"})
algo.fit(trainset)
predictions = algo.test(testset)
# 모델 평가
from surprise import accuracy
acc = accuracy.rmse(predictions)
acc
RMSE: 0.9591
0.9591293463391027
テスト結果の確認
prediction[:5]
[Prediction(uid=2691, iid=912, r_ui=5.0, est=5, details={'was_impossible': False}),
Prediction(uid=3648, iid=2166, r_ui=2.0, est=2.9331766731573703, details={'was_impossible': False}),
Prediction(uid=4279, iid=1974, r_ui=4.0, est=3.7635448815576646, details={'was_impossible': False}),
Prediction(uid=5767, iid=2288, r_ui=5.0, est=3.7394892080225373, details={'was_impossible': False}),
Prediction(uid=5767, iid=2144, r_ui=4.0, est=4.01071767527927, details={'was_impossible': False})]
uid:ユーザID,iid:映画ID,r ui:実績スコア,est:予測スコアMatrix Factorization Modeling
MFベースSVDモデルの学習
from surprise import SVD
param_list = [10, 50, 100, 150, 200]
rmse_list_by_factors = []
ttime_list_by_factors = []
# n_factor depth에 따른 RMSE 확인
for n in param_list:
train_start = time.time()
algo = SVD(n_factors=n)
algo.fit(trainset)
train_end = time.time()
print("training time of model: %.2f seconds" % (train_end-train_start))
print(f"RMSE of test dataset in SVD model, n_factors={n}")
predictions = algo.test(testset)
rmse_list_by_factors.append(accuracy.mse(predictions))
ttime_list_by_factors.append(train_end-train_start)
print("-"*20)
print("searching n_factors is finish.")
n factorでのRMSE可視化
# plt의 plot 함수로 결과 시각화
import matplotlib.pyplot as plt
plt.plot(param_list, rmse_list_by_factors)
plt.title("RMSE by n_factors of SVD", fontsize=14)
plt.xticks(param_list)
plt.xlabel("n_factors", fontsize=12)
plt.ylabel("RMSE", fontsize=12)
for x, y in zip(param_list, rmse_list_by_factors):
plt.annotate(f'{round(y,4)}', xy=(x+15,y), textcoords="data", ha="center")
n_factor=50
時RMSE最小、再増加時と適宜時RMSE上昇.最終RMSE評価
algo = SVD(n_factors=50)
algo.fit(trainset)
predictions = algo.test(testset)
acc = accuracy.rmse(predictions)
acc
RMSE: 0.8737
0.873735086939124
評価時間の検討
CF、MFベースの推奨システムの限界(仮定)
時間に基づいてSVDモデルを学習する
rating_df['time'].quantile(q=0.8, interpolation='nearest') # 8:2로 나눌 수 있는 시간 기준탐색 --> 975768738
train_df = rating_df[rating_df["time"]< 975768738][["user_id", "movie_id", "rating"]]
test_df = rating_df[rating_df["time"]>= 975768738][["user_id", "movie_id", "rating"]]
# 추출한 학습 데이터셋으로 SVD 모델 학습
data = Dataset.load_from_df(train_df, reader=reader)
train_data = data.build_full_trainset()
algo = SVD(n_factors=50)
algo.fit(train_data)
テストと評価
推奨システムでの評価
CF、MFベースの推奨システムは、通常MAPを使用する.
推奨システムでは、各ユーザのPrecisionを計算し、すべての推奨ユーザに拡張し、平均指標を計算します.
# 예측할 부분 (rating이 없는) 데이터만 추출
test_data = train_data.build_anti_testset()
# test
predictions = algo.test(testset)
predictions = algo.test(test_data)
# test 평가를 위해 시청하지 않은 영화의 예상 점수를 dictionary 형태로 추출
estimated_unwatched_dict = {}
for uid, iid, _, predicted_rating, _ in predictions:
if uid in estimated_unwatched_dict:
estimated_unwatched_dict[uid].append((iid, predicted_rating))
else:
estimated_unwatched_dict[uid] = [(iid, predicted_rating)]
使用build_anti_testset
評価されていないデータをテストデータとして抽出できます.estimated_unwatched_dict
ディックシャナに格納されている.kパラメータによる推奨結果の評価と可視化
def get_map_topk(k):
user_metric = []
for user in estimated_unwatched_dict:
estimated_list = estimated_unwatched_dict[user].copy()
estimated_list.sort(key=lambda tup: tup[1], reverse=True)
try:
top_k_prefer_list = [movie[0] for movie in estimated_list[:k]]
actual_watch_list = user_watch_dict_list_test[user_watch_dict_list_test.index==user].values.tolist()[0]
user_metric.append((user, top_k_prefer_list, actual_watch_list))
except:
pass
# MAP: 유저들의 precision 평균으로 구함
precision_list = []
for user in user_metric:
predictive_values = user[1]
actual_values = set(user[2])
tp = [pv for pv in predictive_values if pv in actual_values]
precision = len(tp) / len(predictive_values)
precision_list.append(precision)
return sum(precision_list) / len(precision_list)
k_param_list = range(1,30)
map_list = []
for k in k_param_list:
map_list.append(get_map_topk(k))
plt.plot(k_param_list, map_list)
plt.title('MAP by top k recommendation')
plt.ylabel('MAP', fontsize=12)
plt.xlabel('k', fontsize=12)
plt.show()
Reference
この問題について([推奨システム]CF/MFに基づく推奨システムモデリング実践), 我々は、より多くの情報をここで見つけました https://velog.io/@joniekwon/추천시스템-CFMF-based-추천시스템-모델링テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol