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)에서는 오늘 구현한 유클리디안 유사도 말고 다른 유사도들을 알아보겠다.

 

 

 

 

 

 

 


reference: https://www.fun-coding.org/recommend_basic2.html