작성자 | 장원준 |
일 시 | 2024. 5. 2 (목) 18:00 ~ 21:00 |
장 소 | 복지관 b128-1호 |
참가자 명단 | 임혜진, 이재영, 성창민, 김명원, 장원준 |
사 진 |
아이템 간의 유사도를 측정하는 법은 매우 다양할 수 있다.
예를 들어 Jaccard Similarity 가 있다.
자카드 유사도는 집합간의 유사도를 측정 하는 것으로, 교집합에 합집합을 나누어주어서 그 유사도를 비교 한다.
다음으로는 Cosine Similarity 가 있다.
두벡터가 같은 방향을 바라보면 유사도 높은 것이다.
이제 위를 이용한 코드로 실습을 해볼 것이다.
!wget https://files.grouplens.org/datasets/movielens/ml-25m.zip
!unzip ml-25m.zip
데이터셋을 불러옵니다. 데이터 셋은 movielens 의 데이터셋입니다.
import csv
movies = {}
genresets = {}
with open("ml-25m/movies.csv") as f:
csvreader = csv.reader(f)
next(csvreader) # skip column names
for mid, title, genre in csvreader:
movies[int(mid)] = title
genresets[int(mid)] = set(genre.split("|"))
영화 제목과 장르를 불러옵니다.
(여기서 csv는 값들을 쉼표로 구분한 파일)
ratings = []
with open("ml-25m/ratings.csv", "r") as f:
print(f.readline()) # skip column names
for line in f:
uid, mid, rating, timestamp = line.split(",")
ratings.append((int(uid), int(mid), float(rating)))
별점데이터를 불러오는 코드입니다.
def jaccard_similarity(a, b):
if len(a|b) == 0: return 0
return len(a&b) / len(a|b)
def find_topk_jaccard_genres(target_mid, k=20):
target_title = movies[target_mid]
target_genres = genresets[target_mid]
res = []
for mid, genres in genresets.items():
jaccard_score = jaccard_similarity(target_genres, genres)
res.append( (jaccard_score, movies[mid]) )
res.sort(reverse=True)
return res[:k]
자카드 유사도를 선언하고, 가장 유사도가 높은 k개의 영화를 찾는 코드입니다.
mid = 104841 # Gravity (2013)
print(movies[mid])
find_topk_jaccard_genres(mid, 20)
그래비티 와 장르가 비슷한 영화를 찾는 코드 입니다.
위 코드를 실행 한 결과값입니다.
결과물이 그래비티의 장르 몇가지로 비슷한 영화를 찾은 것이여서 실제로 그래비티와 비슷한 장르를 갖고 있는지가 애매하게 느껴집니다.
uratings = defaultdict(dict)
for uid, mid, rating in ratings:
uratings[mid][uid] = rating
# 점수 보정 (pearson correlation)
for mid, urset in uratings.items():
avg = sum(urset.values())/len(urset)
for uid in urset:
urset[uid] -= avg
각 영화의 rating 을 평균값을 뻴셈 해주어서 전처리하는 코드입니다.
def cosine_similarity(a, b):
numerator = sum(a[k] * b[k] for k in a.keys() & b.keys())
denominator = (sum(x*x for x in a.values()) * sum(x*x for x in b.values())) ** 0.5
if denominator == 0:
return 0
return numerator / denominator
def find_topk_cosine_ratings(target_mid, k=20):
target_urset = uratings[target_mid]
res = []
for mid, urset in tqdm(uratings.items()):
cosine_score = cosine_similarity(target_urset, urset)
res.append( (cosine_score, movies[mid]) )
res.sort(reverse=True)
return res[:k]
전처리한 데이터들을 이용해서 위에서 말한 코사인 유사도를 검사하는 코드입니다.
mid = 104841 # Gravity (2013)
print(movies[mid])
find_topk_jaccard_ratings(mid, 20)
위 코드를 통한 결과값인데, 자카드 유사도에 비해 그래비티 영화라 생각이 들면 생각 날 법한 우주와 과학에 관한 영화들이 나와서 코사인 유사도가 조금더 성능이 좋은 듯 합니다.
기본적인 추천시스템 알고리즘을 공부를 하며 코드로 구현도 해 본 좋은 경험이었고 더 나은 알고리즘이 있는지 다음시간에 알아볼 예정이다.