1. 가장 높은 평점을 갖는 아이템을 추천하는 가장 단순한 방법을 연습합니다.
ratings={
'Dave':{'달콤한인생':5,'범죄도시':3,'샤인':3},
'David':{'달콤한인생':5,'범죄도시':1,'샤인':4},
'Alex':{'달콤한인생':0,'범죄도시':4,'샤인':5},
'Andy':{'달콤한인생':2,'범죄도시':1,'샤인':5}
}
movies_dict = dict()
for rating in ratings:
for movie in ratings[rating].keys():
if movie not in movies_dict:
movies_dict[movie] = ratings[rating][movie]
else:
movies_dict[movie] = (movies_dict[movie] + ratings[rating][movie])
for movie in ratings[rating].keys():
movies_dict[movie] = movies_dict[movie]/4
import operator
sorted_x = sorted(movies_dict.items(), key=operator.itemgetter(1), reverse=True)
print(sorted_x)
##결과: [('달콤한인생', 4.5), ('범죄도시', 3.375), ('샤인', 6.375)]
-> 각 사용자가 남긴 평점을 영화별로 평균을 내고 가장 평점 평균이 높은 영화를 찾을 수 있었습니다. 이를 통해 가장 높은 평점 평균을 가진 영화를 사람들에게 추천해주는 단순한 방식입니다.
2. 이번에는 즉 CF 기법을 사용하는 것입니다. 사용자 간의 유사도 까지만 구해보도록 하겠습니다.
데이터 셋은 다음과 같습니다. 평점을 입력하지 않은 사용자가 있다는 것을 알 수 있다. 이렇게 불완전한 데이터를 가진 와중에도 서로 유사도를 구할 수 있다니 아직 모르는 게 너무 많은 단계인 듯 합니다...
ratings={
'Dave':{'달콤한인생':5,'범죄도시':3,'샤인':3},
'David':{'달콤한인생':2,'범죄도시':1,'샤인':4},
'Alex':{'범죄도시':4,'샤인':5},
'Andy':{'달콤한인생':2,'범죄도시':1,'샤인':5}
}
피타고라스 공식을 통한 유클리드 거리를 활용하여 유사도를 구해봅니다.
입력하는 i와 j는 평점 간의 차를 넣습니다. 그리고 각각 제곱하여 합에 루트를 씌워줌으로써 유클리디안 거리 값을 구하게 됩니다.
import math
def sim(i,j):
return math.sqrt(pow(i,2)+pow(j,2))
영화 '샤인', '범죄도시'에 대해서 Alex와 Andy의 유사도를 구해봅니다. 두 분이 동시에 평가한 영화가 저 두개라서 저 둘로 유사도를 측정하게 됩니다. 이런 부분을 만날 때 CF기법의 단점에 대해 한번 생각..만 해보고 넘어갔습니다.🐱🚀
🐱🏍var1, var2는 두 영화의 매겨진 각 평점들의 차이 입니다.
var1= ratings.get("Alex").get("샤인") - ratings.get("Andy").get("샤인")
# 0
var2= ratings.get("Alex").get("범죄도시") - ratings.get("Andy").get("범죄도시")
# 3
둘의 유사도는 3이라는 결과를 얻게 되었습니다.
sim(var1, var2)
#3.0
🐱🏍그럼 이번에는 Alex님이 평가한 영화 '범죄도시'와 '샤인' 을 모두 평가하신 다른 나머지 모두와의 유사도를 각각 계산해보는 예제를 살펴보겠습니다.
이전 만들었던 sim(i, j) 함수를 그대로 사용하였습니다.
for i in ratings:
if i != 'Alex':
var1= ratings['Alex']['범죄도시'] - ratings[i]['범죄도시']
var2= ratings['Alex']['샤인'] - ratings[i]["샤인"]
print(i, " : ",sim(var1, var2))
# Dave : 2.23606797749979
# David : 3.1622776601683795
# Andy : 3.0
다른사람과 Alex님 사이의 거리를 알 수 있습니다. Dave가 거리가 가장 멀지 않다는 것을 알 수 있습니다. 좀 더 수치적으로 쉽게 알아보기 위해 정규화를 해보도록 하겠습니다.
이곳에서 정규화는 우리가 구한 거리에 1을 더하고 역수로 바꿔주었습니다
for i in ratings:
if i != 'Alex':
var1= ratings['Alex']['범죄도시'] - ratings[i]['범죄도시']
var2= ratings['Alex']['샤인'] - ratings[i]["샤인"]
print(i, " : ",1/(sim(var1, var2)+1))
# Dave : 0.3090169943749474
# David : 0.2402530733520421
# Andy : 0.25
-> 수치를 보니 아까 거리가 가장 가까웠다고 말했던 Dave 가 정규화한 수치가 가장 높게 나왔습니다. 즉, 상대적으로 다른 사람보다 수치상 크다는 것으로 우리는 Alex와 Dave가 가장 유사하다고 해석을 해볼 수 있게되었습니다.
이번엔 Dave님의 다른 사람과의 유사도를 측정해봅니다.
for i in ratings:
if i!='Dave':
num1 = ratings.get('Dave').get('범죄도시') - ratings.get(i).get('범죄도시')
num2 = ratings.get('Dave').get('샤인') - ratings.get(i).get('샤인')
print(i," : ", 1 / ( 1 + sim(num1,num2) ) )
# David : 0.3090169943749474
# Alex : 0.3090169943749474
# Andy : 0.2612038749637414
-> David와 Alex와 가장 유사하다는 동일한 수치를 볼 수 있습니다. 이는 행렬을 통해 보면 한눈에 쉽게 알아 볼 수 있습니다.
🐱🚀 유사도 행렬 만들기.
import math
import pandas as pd
def sim(i,j):
return math.sqrt(pow(i,2)+pow(j,2))
def sim_matrix(ratings):
sim_mat=[]
for i in ratings:
tmp=[]
for j in ratings:
num1 = ratings.get(i).get('범죄도시') - ratings.get(j).get('범죄도시')
num2 = ratings.get(i).get('샤인') - ratings.get(j).get('샤인')
tmp.append(1 / ( 1 + sim(num1,num2)))
sim_mat.append(tmp)
return pd.DataFrame(sim_mat, index=list(ratings.keys()), columns=list(ratings.keys()))
sim_matrix(ratings)
-> 자기 자신과는 당연히 동일하므로 정규화 값 1을 갖게 되고 나머지를 통해서 사용자 간의 유사도를 알 수 있습니다. Alex가 만약에 '달콤한인생' 영화에 평점을 주었다면 유사도가 더욱 의미를 갖게 될 것이라 생각해보면서 이 번 장을 마칩니다.
'추천시스템' 카테고리의 다른 글
MovieLens 데이터를 활용한 Collaborative Filtering 구현 (0) | 2020.01.15 |
---|---|
콘텐츠 기반 필터링 추천 예제 (0) | 2020.01.14 |
연구주제를 위한 논문 리뷰 (0) | 2020.01.10 |
사용자간 유사도를 활용한 협업필터링 추천 예제 (0) | 2019.11.24 |
추천시스템 개념 (0) | 2019.11.23 |
댓글