- 협업 필터링은 다른 사용자들을 통해 현 사용자의 취향을 추측한다.
- 협업 필터링은 사용자 기반 필터링과 아이템 기반 필터링으로 나뉘어진다.
- 먼저 사용자 기반 협업 필터링을 사용해보겠다.
데이터 불러오고 처리하기
import pandas as pd
import numpy as np
ratings = pd.read_csv('../data/ratings.csv')
movies = pd.read_csv('../data/movies.csv')
pd.set_option('display.max_columns', 6)
pd.set_option('display.width', 300)
movie_ratings = pd.merge(ratings, movies, on='movieId')
print(movie_ratings)
- https://www.kaggle.com/sengzhaotoo/movielens-small?select=ratings.csv
- movies 데이터와 ratings 데이터를 불러와 movieId값을 기준으로 merge한다.
- 그렇게 합쳐진 movie_ratings의 데이터프레임은 위와 같이 나타난다.
title_user = movie_ratings.pivot_table('rating', index='userId', columns='title')
title_user.fillna(0, inplace=True)
- pivot_table을 이용해 유저의 영화별 평점을 담은 데이터프레임을 만든다.(title_user)
- 결측치는 0으로 처리한다.
유사도 측정 및 비슷한 유저 찾기
from sklearn.metrics.pairwise import cosine_similarity
# 유저와 유저 간의 유사도
user_based_collab = cosine_similarity(title_user, title_user)
user_based_collab = pd.DataFrame(user_based_collab, index=title_user.index, columns=title_user.index)
print(user_based_collab[1].sort_values(ascending=False)[:10])
userId
1 1.000000
325 0.371852
634 0.194093
341 0.162819
310 0.157524
207 0.152746
35 0.130585
195 0.122647
485 0.114021
130 0.112817
Name: 1, dtype: float64
- 방금 만들어놓은 유저의 영화별 평점 데이터프레임(title_user)을 활용해 각 유저간 유사도를 측정한다
- 유저 수 X 유저 수 크기의 유저간 유사도 데이터프레임이 생성된다.(user_based_collab)
- 해당 유사도는 2차원 리스트형태로 되어 있다. 따라서 이를 사용하기 용이하도록 데이터프레임 형태로 바꿨다.
- 첫번째 유저를 뽑아 내림차순으로 정리하고, 그 중 상위 10개를 가져왔다.
가장 비슷한 유저가 감상한 영화 추천
# 가장 유사한 유저를 뽑아서 해당 유저가 본 영화 추천
user = user_based_collab[1].sort_values(ascending=False)[:10].index[1]
print(title_user.loc[user].sort_values(ascending=False))
title
Dangerous Minds (1995) 4.5
Beverly Hills Cop (1984) 4.5
Brady Bunch Movie, The (1995) 4.0
My Best Friend's Wedding (1997) 4.0
Star Trek: The Motion Picture (1979) 3.5
...
Patriot Games (1992) 0.0
Patriot, The (2000) 0.0
Patton (1970) 0.0
Paul (2011) 0.0
"Great Performances" Cats (1998) 0.0
Name: 325, Length: 9064, dtype: float64
별점 예측하기
# 1번 유저와 유사한 유저들 9명을 뽑아서, 그 유저들이 어떤 영화에 대해서 부여한 평점에
# 유사도만큼의 가중치를 부여해서 이걸 토대로 1번 유저가 부여할 평점을 계산/예측
# 가중치 -> 유저 9명 유사도의 합 중에서 해당 유저가 차지하는 유사도
user_index_list = user_based_collab[1].sort_values(ascending=False)[:10].index.tolist()
user_weight_list = user_based_collab[1].sort_values(ascending=False)[:10].tolist()
- 유저간 유사도를 담고있는 user_based_collab에서 첫번째 유저의 다른 유저들에 대한 유사도들을 내림차순으로 정렬하고, 이 인덱스를 뽑아 리스트화 한다. (즉, 각 유저의 ID, [1, 325, 634, 341, 310, 207, 35, 195, 485, 130])
- 유사도도 내림차순으로 정렬후 리스트화한다. (즉, 각 유저와의 유사도, [1.0, 0.3718515795200445, 0.19409305170790575, 0.16281928881328767, 0.1575243302750048, 0.15274612900892096, 0.13058496348265256, 0.12264701454037472, 0.11402063453702121, 0.11281730419223501])
- 여기서 'sum(user_weight_list)-1'를 한다면 이는 곧 첫번째 유저와 유사한 유저들의 유사도를 전부 더한 것이 된다.
# 유사한 유저들조차도 평점을 부여하지 않았다면
# 1번 유저가 부여할 평점을 예측할 수 없다...
movie_title = 'Dark Knight, The (2008)'
weighted_sum = []
for i in range(1, 10):
weighted_sum.append(title_user[movie_title][user_index_list[i]] * user_weight_list[i]/(sum(user_weight_list)-1))
print(sum(weighted_sum))
- 'Dark Knight, The (2008)'에 대한 예측 별점을 측정하고자한다.
- weighted_sum에 (각 유저의 해당영화에 대한 평점) * (첫번째 유저와의 유사도) / (전체 유사도합) 을 더한뒤
- 마지막에 sum으로 값을 출력한다.
- 결과는 0.0이 나온다. 왜 그렇게 될까?
- 첫번째 유저와 마찬가지로 첫번째 유저와 유사한 9명의 유저들도 'Dark Knight, The (2008)'를 보지 않았기 때문이다. (평점이 0)
- 즉, 사용자 기반 협업 필터링은 비슷한 영화를 찾을 수는 있지만 점수예측에는 적합하지 않다.
'🛠 기타 > Data & AI' 카테고리의 다른 글
[scikit-learn 라이브러리] SVC (SVM) (0) | 2020.08.23 |
---|---|
오토 인코더 기초개념 (0) | 2020.08.23 |
기초 추천시스템 - 컨텐츠기반 필터링 (2) | 2020.08.21 |
[scikit-learn 라이브러리] AdaBoostClassifier (Adaptive Boosting) (0) | 2020.08.20 |
[scikit-learn 라이브러리] GradientBoosting (0) | 2020.08.19 |