카테고리 없음

[추천시스템설계] Finding Similar Items

외손잡이 2024. 5. 2. 21:53
작성자 장원준
일 시 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)

 위 코드를 통한 결과값인데, 자카드 유사도에 비해 그래비티 영화라 생각이 들면 생각 날 법한 우주와 과학에 관한 영화들이 나와서 코사인 유사도가 조금더 성능이 좋은 듯 합니다.

 

기본적인 추천시스템 알고리즘을 공부를 하며 코드로 구현도 해 본 좋은 경험이었고 더 나은 알고리즘이 있는지 다음시간에 알아볼 예정이다.