728x90
반응형
SMALL
사용자기반 협업 필터링 (User-based Filtering)
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
from sklearn.metrics import mean_squared_error
from datetime import datetime
%matplotlib inline
movies = pd.read_csv('movies.csv') # 영화 정보
ratings = pd.read_csv('ratings.csv') # 사용자가 영화에 대해 남긴 평점 데이터
print(movies.shape)
print(ratings.shape)
movies.head()
# 제목으로 영화 찾기
movies[movies.title.str.contains("Die", case = False)]
# 영화 장르 리스트
{j for i in movies.genres.str.split('|') for j in i}
ratings.head()
# 사용자 수와 사용자 당 평점 횟수
ratings.userId.nunique(), ratings.shape[0] / ratings.userId.nunique()
# 평점 데이터가 일부 위치에만 존재하는 sparse 행렬
ratings.pivot_table('rating', index='userId', columns='movieId').iloc[212:222, 808:817].fillna("")
plt.figure(figsize=(20,20))
df = ratings.pivot_table('rating', index='userId', columns='movieId', fill_value=0)
sns.heatmap(df, cmap='YlGnBu')
plt.show()
# Density level (%)
density = ratings.shape[0] / (ratings.userId.nunique() * ratings.movieId.nunique())
f'{round(density*100,2)}%'
# 평점 분포
print(ratings.describe().rating)
sns.histplot(ratings.rating, bins=10, kde=True); plt.show()
# 사용자 ID
myId = int(input("사용자 id 입력 : "))
print("제시되는 영화에 대해 10개까지 평점(1~5점)을 입력")
print("잘 모르는 영화일 경우 평점을 낮게 주거거나 Enter키")
movies_for_rating = pd.read_csv('movies_for_rating.csv')
my_ratings = []
count = 0
df = movies_for_rating.sample(frac=1)
for i in range(df.shape[0]):
my_rating = input(f"{df.iloc[i].title}: ")
try:
score = int(my_rating)
if score < 1 or score > 5:
continue
my_ratings.append((myId, df.iloc[i].movieId, score, int(datetime.now().timestamp())))
count += 1
except:
continue
if count >= 10:
break
my_ratings = pd.DataFrame(my_ratings, columns=ratings.columns)
my_ratings.to_csv('my_ratings.csv', index=False)
print("\nMy rating summary:\n", my_ratings.merge(df)[['title', 'genre', 'rating']])
ratings = pd.concat([ratings, my_ratings]).reset_index(drop=True)
# title 컬럼을 얻기 이해 movies와 조인 수행
rating_movies = pd.merge(ratings, movies, on='movieId')
# 행은 userID, 열은 title로 pivoting 수행. rating이 없는 값(NaN)은 모두 0으로 변환
ratings_matrix = rating_movies.pivot_table('rating', index='userId', columns='title', fill_value=0)
print(ratings_matrix.shape)
ratings_matrix.head()
from sklearn.metrics.pairwise import cosine_similarity
# cosine_similarity()는 행을 기준으로 유사도를 계산
user_sim = cosine_similarity(ratings_matrix, ratings_matrix)
# cosine_similarity()로 반환된 numpy 행렬에 영화명을 매핑하기 위해 DataFrame으로 변환
user_sim = pd.DataFrame(user_sim, ratings_matrix.index, ratings_matrix.index)
print(user_sim.shape)
user_sim.head()
# 나와 유사도가 높은 상위 5명 리스트
user_sim.loc[myId].sort_values(ascending=False)[1:6]
# 유사도가 가장 높은 이웃의 수 설정
K = int(input("유사도가 높은 이웃의 수 설정 : "))
%%time
# 위의 평점예측 수식을 아래와 같이 구현함
R, S = ratings_matrix.values, user_sim.values
# 사용자-아이템 평점 행렬 크기만큼 0으로 채운 예측 행렬 초기화
ratings_pred = np.zeros(R.shape)
# 사용자-아이템 평점 행렬의 열 크기만큼 Loop 수행.
for u in range(R.shape[0]):
# 유사도 행렬에서 유사도가 큰 순으로 n개 데이터 행렬의 index 반환
top_k = np.argsort(S[:, u])[::-1][1:K+1]
# 개인화된 예측 평점을 계산
for i in range(R.shape[1]):
ratings_pred[u, i] = S[u, :][top_k].dot(R[:,i][top_k].T)
ratings_pred[u, i] /= np.sum(np.abs(S[u, :][top_k]))
ratings_pred = pd.DataFrame(ratings_pred, ratings_matrix.index, ratings_matrix.columns)
ratings_pred
# 추천 영화의 수 (Top-K) & 추천 대상 설정
N = int(input("추천 영화의 수 설정 : "))
uid = myId
# 내가 좋아하는 영화
like_movies = ratings.query('userId == @uid and rating >= 4').movieId
movies.query('movieId in @like_movies')
# id로 지정된 사용자의 모든 영화정보 추출하여 Series로 반환함
# 반환된 user_rating은 영화명(title)을 index로 가지는 Series 객체임
user_rating = ratings_matrix.loc[uid,:]
# user_rating이 0보다 크면 기존에 관람한 영화임. 대상 index를 추출하여 list로 만듬
already_seen = user_rating[user_rating > 0].index.tolist()
# list comprehension으로 already_seen에 해당하는 movie는 movies_list에서 제외함
unseen_list = [movie for movie in ratings_matrix.columns.tolist() if movie not in already_seen]
# unseen_list에서 가장 평점이 높은 N개의 영화를 추천함
recomm_items = ratings_pred.loc[uid, unseen_list].sort_values(ascending=False)[:N]
list(recomm_items.index)
# 사용자가 평점을 부여한 영화에 대해서만 예측 성능 평가 RMSE를 구함
actual, pred = ratings_matrix.values, ratings_pred.values
pred = pred[actual.nonzero()].flatten()
actual = actual[actual.nonzero()].flatten()
rmse = np.sqrt(mean_squared_error(pred, actual))
print(f'RMSE:', rmse)
728x90
반응형
LIST
'Learning-driven Methodology > ML (Machine Learning)' 카테고리의 다른 글
[LightGBM] 매개변수 조정 (Parameters Tuning) (3) (0) | 2023.07.03 |
---|---|
[Machine Learning] K겹 교차 검증 (K-fold cross validation) (0) | 2023.04.27 |
[Machine Learning] 추천 시스템 (Recommender System) (0) | 2022.12.07 |
[Machine Learning] 의사 결정 트리 : 붓꽃 (Iris) (0) | 2022.11.29 |
[Machine Learning] 이상 탐지 (Anomaly Detection) (0) | 2022.11.17 |