추천시스템

본 포스팅은 Minnesota대학교의 Intro to Recommender Systems코세라 강좌를 정리한 내용입니다.
https://www.coursera.org/learn/collaborative-filtering?specialization=recommender-systems
원본 코드 예제에서는 Excel로 코딩하게 되어있지만, 파이썬으로 코딩한 예제입니다.
사용자-사용자 협업필터링¶
정규화 없는 협업필터링¶
- 사용자-사용자 연관성 행렬을 완성하시오. 체크를 위해서, 사용자 1648과 사용자 5136의 연관성은 0.40298, 그리고 사용자 918과 사용자 2824의 연관성은 -0.31706이다. 사용자들 사이의 연관성은 -1에서 1사이이다.
- 사용자 3867과 사용자 89의 이웃을 각각 5명씩 구하시오. 만약 타겟 사용자가 3712라면 이웃들은: 2724 (연관성: 0.46291), 3867 (연관성: 0.400275), 5062 (연관성: 0.247693), 442 (연관성: 0.22713), 3853 (연관성: 0.19366)이다.
- 이웃 사용자 다섯명의 평점들을 통해 사용자 3867과 사용자 89의 모든 영화들에 대한 예상평점을 구하시고.
- 각 사용자들에 대한 예상평점을 구하고, 상위 3개의 영화들을 구하시오.
### 사용자-사용자 행렬 먼저 pandas라이브러리와 행렬 데이터를 가져옵니다.
import pandas as pd
user_movie = pd.read_csv('user.csv', delimiter="\t", index_col=0)
user_movie.head()
movie_user = pd.read_csv('movie.csv', delimiter='\t', index_col=0)
movie_user.head()
사용자를 Pivot으로 피어슨 연관성 행렬을 구합니다. Pandas라이브러리의 corr()기능을 사용하면 간단하게 구할 수 있습니다.
corr = movie_user.corr('pearson')
corr
사용자 3867과 사용자 89의 연관성¶
연관성 행렬에서 문제의 각 사용자들을 indexing을 하면 연관성값이 나옵니다.
corr['1648']['5136'], corr['918']['2824']
이웃5명 구하기¶
먼저 사용자 3712의 답이 나와있으니 구해보도록 하겠습니다.
각 사용자들에 대한 값을 정렬해준 뒤 상위 다섯개를 구해옵니다.
(index 0번은 사용자 3712 자신과의 연관성이고 값은 1이니 제외시켜줍니다.)
top_neigh = pd.DataFrame({c : corr[c].sort_values(ascending=False)[1:6].index.values for c in corr}, index=[1, 2, 3, 4, 5]).T
top_neigh.loc['3712']
다음은 정렬해준 행렬에서 사용자 3867과 사용자 89의 상위 5명의 이웃들입니다.
print(top_neigh.loc['3867'])
print(top_neigh.loc['89'])
각 사용자에 대한 예측값 찾기¶
각 사용자의 상위 3개로 예상되는 영화들을 찾아보겠습니다.
아래 print_predictions라는 함수를 작성했습니다. 먼저 해당 사용자의 이웃들을 구하고, 연관성들, 그리고 평점들을 구합니다. eliminater는 행렬에서 nan값들이 값에 영향을 주지 않도록, 값이 있는것들은 1을 곱해주고 값이 nan인 것들인 0을 곱해주어 영향을 주지 않게 하는 행렬입니다. 마지막으로 예측값을 구합니다. 예측값은 이전 포스팅들에서 나온 가중치가 없는 수식을 구현한 것입니다.
import numpy as np
def print_predictions(current_user, n=3):
neighbors = top_neigh.loc[current_user].astype('int64').values
correlations = np.asarray([corr[current_user][str(neighbor)] for neighbor in neighbors])
ratings = user_movie.loc[neighbors]
eliminater = ratings.T.where(np.isnan(ratings.T), 1, False).where(~np.isnan(ratings.T), 0, False)
predictions = (ratings.T * correlations).T.sum() / (eliminater * correlations).T.sum()
print(predictions.sort_values(ascending=False)[:n])
아래는 위 함수를 사용한 사용자 3867과 사용자 89의 상위 3개의 예측값입니다.
그리고 3712와 3525의 상위 3개 예측값도 구해보았습니다.
print_predictions('3867')
print()
print_predictions('89')
print_predictions('3712')
print_predictions('3525')
정규화를 더한 협업 필터링¶
아래는 위의 수식에서 정규화를 더한 함수입니다. 정규화된 수식 또한 이전 포스팅에 있는 수식을 사용하였습니다.
def print_normalized(current_user, n=3):
neighbors = top_neigh.loc[current_user].astype('int64').values
correlations = np.asarray([corr[current_user][str(neighbor)] for neighbor in neighbors])
ratings = user_movie.loc[neighbors]
eliminater = ratings.T.where(np.isnan(ratings.T), 1, False).where(~np.isnan(ratings.T), 0, False)
norm = ((ratings.T - ratings.T.mean()) * correlations).T.sum() / (eliminater * correlations).T.sum()
curr_ratings_mean = user_movie.loc[int(current_user)].mean()
predictions = curr_ratings_mean + norm
print(predictions.sort_values(ascending=False)[:n])
위 함수 역시 사용한 사용자 3867과 사용자 89의 상위 3개의 예측값을 구해보았습니다. 그리고 3712와 3525의 상위 3개 예측값도 구해보았습니다.
print_normalized('3867')
print()
print_normalized('89')
print_normalized('3712')
print_normalized('3525')
원본 소스를 확인하시려면 다음 링크로 가시면 됩니다: https://github.com/ydy1128/coursera-recommender-systems/tree/master/ex2
'아카이브 > 추천시스템(2019)' 카테고리의 다른 글
추천시스템 18 - 경사하강법 (0) | 2019.08.05 |
---|---|
추천시스템 17 - 행렬 분해 (0) | 2019.07.30 |
추천시스템 15 - 단항의 아이템 추천 (0) | 2019.07.07 |
추천시스템 14 - 아이템-아이템 협업필터링 (0) | 2019.07.07 |
추천시스템 13 - 사용자-사용자 협업필터링 (0) | 2019.07.01 |