ML/Recommendation
[Recommendation] 추천 알고리즘 Python 구현 : Collaborative Filtering w/ 유클리디안 유사도
dokylee
2020. 3. 6. 13:14

넷플릭스를 한창 보는 중인데, 도대체 넷플릭스는 어떤 방식으로 나한테 추천을 해주는 건지가 궁금해졌다.
추천 알고리즘을 좀 알아봐야겠다!
먼저 제일 기초적인 [1. 사용자 간의 유사도를 구하는 방식 + 2. 그 유사도로 추천하는 기본 방식]을 알아보고,
넷플릭스는 그걸 어떻게 사용하는지 알아보자.
Popularity, High Rated Based
가장 단순한 방법 → 평점이 높은 것을 추천
모두에게 같은 item 추천하게 됨.
ratings = {
'doky':{'Anne_with_an_E':5,'Strange_Things':3,'The_Escape':3},
'steve':{'Anne_with_an_E':5,'Strange_Things':1,'The_Escape':4},
'jamie':{'Anne_with_an_E':0,'Strange_Things':4,'The_Escape':5},
'bobby':{'Anne_with_an_E':2,'Strange_Things':1,'The_Escape':5}
}
recmd_movielist = dict()
# (A)
for name in ratings:
for title in ratings[name]:
score = ratings[name][title]
if title not in recmd_movielist:
recmd_movielist[title] = score
else:
recmd_movielist[title] += score
#
# (B)
for recmd_movietitle in recmd_movielist:
recmd_movielist[recmd_movietitle] /= 4
#
# (C)
from operator import itemgetter
recmd_movielist = sorted(recmd_movielist.items(), reverse=True, key=itemgetter(1))
#
recmd_movielist
Out: [('The_Escape', 4.25), ('Anne_with_an_E', 3.0), ('Strange_Things', 2.25)]
네 사람이 같은 영화에 준 평점들을 각각 더한 다음 (A)
4로 나눠서 각 영화가 받은 평점의 평균을 낸다 (B)
그 평균으로 내림차순 정렬해서 추천 리스트를 만든다 (C)
Collaborative Filtering
- 사용자가 입력한 선호도(평점)를 사용하여 사용자-항목 선호도(평점) 행렬 계산
- 그 행렬을 사용하여 사용자들 간의 유사도를 계산
- 사용자들 간의 유사도를 바탕으로 모든 항목에 대해 예측 값을 계산하고, 높은 예측 값을 갖는 상위 N개의 추천 목록을 생성
ratings = {
'doky':{'Anne_with_an_E':5,'Strange_Things':3,'The_Escape':3},
'steve':{'Anne_with_an_E':5,'Strange_Things':1,'The_Escape':4},
'jamie':{'Strange_Things':4,'The_Escape':5},
'bobby':{'Anne_with_an_E':2,'Strange_Things':1,'The_Escape':5}
}
import math
def sim_w_dist(i, j):
return math.sqrt(pow(i,2) + pow(j,2))
유클리디안 거리 유사도 측정
max_sim_w_dist = sim_w_dist(5, 5)
min_sim_w_dist = sim_w_dist(0, 0)
print(min_sim_w_dist, ',', max_sim_w_dist)
sim_w_dist로 구한 sim의
최대값=루트50, 최소값=0
for name in ratings:
if name != 'jamie':
v1 = ratings['jamie']['Strange_Things'] - ratings[name]['Strange_Things']
v2 = ratings['jamie']['The_Escape'] - ratings[name]['The_Escape']
sim = sim_w_dist(v1, v2)
norm_sim = (sim-min_sim_w_dist)/(max_sim_w_dist-min_sim_w_dist)
print('similarity with', name, ':', sim, '->', norm_sim)
Out: similarity with doky : 2.23606797749979 -> 0.31622776601683794
similarity with steve : 3.1622776601683795 -> 0.4472135954999579
similarity with bobby : 3.0 -> 0.4242640687119285
jamie가 평가한 Strange_Things, The_Escape를 모두 평가한 사용자와의 유사도 구하기
● sim_w_dist 함수 사용
● sim을 0과 1 사이로 정규화한 norm_sim 계산 => 1에 가까운 값일수록 유사도 높음
다음 포스팅(#2)에서는 오늘 구현한 유클리디안 유사도 말고 다른 유사도들을 알아보겠다.