- 영화 추천 시스템(협업 필터링)
3. Collaborative Filtering (협업 필터링 : 사용자 리뷰 기반)
# surprise 유명한 추천 시스템 패키지
import surprise
surprise.__version__
'1.1.1'
# surprise Reader 공식문서 참고
import pandas as pd
from surprise import Reader, Dataset, SVD
from surprise.model_selection import cross_validate
# tmdb 5000 에서 most view의 제일 인기있는 분의 게시글에서 가져온 파일
ratings = pd.read_csv('ratings_small.csv')
ratings.head()
userId | movieId | rating | timestamp | |
---|---|---|---|---|
0 | 1 | 31 | 2.5 | 1260759144 |
1 | 1 | 1029 | 3.0 | 1260759179 |
2 | 1 | 1061 | 3.0 | 1260759182 |
3 | 1 | 1129 | 2.0 | 1260759185 |
4 | 1 | 1172 | 4.0 | 1260759205 |
ratings['rating'].min()
0.5
ratings['rating'].max()
5.0
# 공식문서는 1~5가 default여서 수정
reader = Reader(rating_scale=(0.5, 5))
# 공식문서에서 이 라이브러리 사용하려면 반드시 3개 컬럼(사용자 id, 아이템 id, rating) 만을 사용하도록 제한한다.
data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader=reader)
data
<surprise.dataset.DatasetAutoFolds at 0x2b7682386d0>
svd = SVD(random_state=0) # SVD 알고리즘 사용
# 교차 검증
# 참고 : 우리가 배웠던 훈련,테스트 8:2나눠서 하는것도 surprise에 있음
cross_validate(svd, data, measures=['RMSE', 'MAE'], cv=5, verbose=True)
Evaluating RMSE, MAE of algorithm SVD on 5 split(s). Fold 1 Fold 2 Fold 3 Fold 4 Fold 5 Mean Std RMSE (testset) 0.8938 0.8901 0.8912 0.9019 0.9022 0.8958 0.0052 MAE (testset) 0.6872 0.6837 0.6864 0.6970 0.6936 0.6896 0.0049 Fit time 3.86 3.78 3.91 3.79 3.80 3.83 0.05 Test time 0.15 0.15 0.15 0.11 0.11 0.14 0.02
{'test_rmse': array([0.89380839, 0.89005166, 0.89122234, 0.90192799, 0.90217437]), 'test_mae': array([0.68724403, 0.68372846, 0.68643029, 0.6969897 , 0.69362123]), 'fit_time': (3.857027769088745, 3.7835288047790527, 3.913365602493286, 3.7860512733459473, 3.8039586544036865), 'test_time': (0.15250229835510254, 0.1499941349029541, 0.14965319633483887, 0.11122775077819824, 0.11458182334899902)}
교차 검증 (K-Fold 교차 검증)
100 개 데이터
A:1-20
B:21-40
C:41-60
D:61-80
E:81-100
아래 예시는 위에서 cv=5
를 의미
ABCD (train set) E (test set)
ABCE (train set) D (test set)
ABDE (train set) C (test set)
ACDE (train set) B (test set)
BCDE (train set) A (test set)
trainset = data.build_full_trainset() # 전체 데이터
svd.fit(trainset)
<surprise.prediction_algorithms.matrix_factorization.SVD at 0x2b768238760>
ratings[ratings['userId'] == 1]
userId | movieId | rating | timestamp | |
---|---|---|---|---|
0 | 1 | 31 | 2.5 | 1260759144 |
1 | 1 | 1029 | 3.0 | 1260759179 |
2 | 1 | 1061 | 3.0 | 1260759182 |
3 | 1 | 1129 | 2.0 | 1260759185 |
4 | 1 | 1172 | 4.0 | 1260759205 |
5 | 1 | 1263 | 2.0 | 1260759151 |
6 | 1 | 1287 | 2.0 | 1260759187 |
7 | 1 | 1293 | 2.0 | 1260759148 |
8 | 1 | 1339 | 3.5 | 1260759125 |
9 | 1 | 1343 | 2.0 | 1260759131 |
10 | 1 | 1371 | 2.5 | 1260759135 |
11 | 1 | 1405 | 1.0 | 1260759203 |
12 | 1 | 1953 | 4.0 | 1260759191 |
13 | 1 | 2105 | 4.0 | 1260759139 |
14 | 1 | 2150 | 3.0 | 1260759194 |
15 | 1 | 2193 | 2.0 | 1260759198 |
16 | 1 | 2294 | 2.0 | 1260759108 |
17 | 1 | 2455 | 2.5 | 1260759113 |
18 | 1 | 2968 | 1.0 | 1260759200 |
19 | 1 | 3671 | 3.0 | 1260759117 |
svd.predict(1, 302)
Prediction(uid=1, iid=302, r_ui=None, est=2.7142061734434044, details={'was_impossible': False})
svd.predict(1, 1029, 3) # UserId = 1 번인 사람이 Movie Id = 1029 인 영화에 대해서 실제 평가 3점일 때, 예측 평가 점수? 2.88...
Prediction(uid=1, iid=1029, r_ui=3, est=2.8814455446761933, details={'was_impossible': False})
ratings[ratings['userId'] == 100]
userId | movieId | rating | timestamp | |
---|---|---|---|---|
15273 | 100 | 1 | 4.0 | 854193977 |
15274 | 100 | 3 | 4.0 | 854194024 |
15275 | 100 | 6 | 3.0 | 854194023 |
15276 | 100 | 7 | 3.0 | 854194024 |
15277 | 100 | 25 | 4.0 | 854193977 |
15278 | 100 | 32 | 5.0 | 854193977 |
15279 | 100 | 52 | 3.0 | 854194056 |
15280 | 100 | 62 | 3.0 | 854193977 |
15281 | 100 | 86 | 3.0 | 854194208 |
15282 | 100 | 88 | 2.0 | 854194208 |
15283 | 100 | 95 | 3.0 | 854193977 |
15284 | 100 | 135 | 3.0 | 854194086 |
15285 | 100 | 141 | 3.0 | 854193977 |
15286 | 100 | 608 | 4.0 | 854194024 |
15287 | 100 | 648 | 3.0 | 854193977 |
15288 | 100 | 661 | 3.0 | 854194086 |
15289 | 100 | 708 | 3.0 | 854194056 |
15290 | 100 | 733 | 3.0 | 854194024 |
15291 | 100 | 736 | 3.0 | 854193977 |
15292 | 100 | 745 | 4.0 | 854194208 |
15293 | 100 | 780 | 3.0 | 854193977 |
15294 | 100 | 786 | 3.0 | 854194056 |
15295 | 100 | 802 | 4.0 | 854194111 |
15296 | 100 | 1073 | 5.0 | 854194056 |
15297 | 100 | 1356 | 4.0 | 854194086 |
# 1029인 영화를 3.77... 평점 줄거라고 예측
svd.predict(100, 1029) # User Id = 100, Movie Id = 1029
Prediction(uid=100, iid=1029, r_ui=None, est=3.7705476478414846, details={'was_impossible': False})
이처럼 같은 영화여도 user마다 평점이 다른 이유는
각 user마다 다른 영화들 평가한것을 전부 데이터 산정해서 평가하기 때문
추후에 자신이 본 영화들은 제외하고 안 본 영화들 중에서 이 알고리즘을 활용해 Top10으로 추천받는것도 좋아 보인다.
또는 쇼핑몰 등에서도 소비자의 선호한 item들을 분석하여 무슨 제품을 더 올리는게 좋을지 추천받는것도 좋아 보인다.
참고자료 : 나도코딩-유튜브
추천!
댓글남기기