sirin05137 / CSE364_Project

2 stars 0 forks source link

Movie recommendation based on movie title input #35

Closed sirin05137 closed 3 years ago

sirin05137 commented 3 years ago

Make recommendation system based on movie title input

해당 이슈는 Milestone3 - part2 에서 영화 추천 시스템이 어떻게 구현되는 지를 설명한다. 추천 시스템의 작동방식은 2가지로 나뉜다. 하나는 아이템 기반 협업 필터링(Item-based Collaborative Filtering) 이며 또다른 하나는 장르 기반 추천(Genre-based recommendation)이다. 두 알고리즘이 어떻게 작동하는지 알아보자.

Item-based Collaborative Filtering

입력받은 영화와 각 영화별 유사도를 계산하여 영화를 추천해주는 방식이다. 협업 필터링은 아이템 기반과 유저 기반 두가지로 나눌 수 있는데 여기서는 아이템 기반을 사용한다. 이는 만약 영화 A를 재밌게 본 사람들이 영화 B도 재밌게 봤다면 영화 A와 영화 B는 유사하다고 보는 것이다.

각 영화별 유사도를 측정하는 데에는 피어슨 상관계수(Pearson correlation coefficient)를 사용하였다. 피어슨 상관계수에 대한 자세한 내용은 여기를 참고하기 바란다. 피어슨 상관계수를 구하는 공식은 다음과 같다. image 또한 피어슨 상관계수는 다음과 같은 메소드를 통해 구할 수 있다.

static double get_pearson_similarity(HashMap<String, Integer> rating, HashMap<String, Integer> rating_of_input, double mean_rating_of_input, double distance_of_input)

피어슨 상관계수를 통해 유사도를 구했으면 유사도가 높은 순으로 정렬시킨다. 예를들어 입력값으로 "Superman (1978)" 이 들어오면 다음과 같은 유사도 순위를 얻을 수 있다. image 정렬이 완료 되면 유사도가 가장 큰 항목부터 (1.5 * limit)개 만큼을 ArrayList<Movie_data_node> movie_data_table에 추가한다.(만약 "Superman (1978)"을 입력받았으면 "Superman (1978)"을 출력할 필요가 없기 때문에 리스트에 추가할때 해당 항목은 제외하고 나머지 항목들을 추가한다.)

IMDB의 weighted rating 방법에 피어슨 상관계수를 더하여 각 영화의 가중평균을 구한다.

W = {(vR+mC)/(v+m)} + sim

v = 해당 영화의 총 투표수 m = Top 차트에 들기 위한 최소한의 투표수 R = 해당 영화의 평균 평점 C = 모든 영화의 평균 평점 sim = 입력받은 영화와 해당 영화 사이의 피어슨 상관계수

IMDB의 weighted rating 방법에 피어슨 상관계수를 더하는 이유는 입력받은 영화와 유사도가 높은 영화에 조금 더 높은 가중치를 두기 위해서 이다. 만약 "Superman (1978)"을 입력받으면 "Superman II (1980)" 및 "Superman III (1983)" 와 유사도가 높은 것을 알 수 있다. 하지만 이 영화들이 유사도가 높은 것에 비해 유저 평가가 낮은 경향이 있다. 이런 경우에 유저 평가가 매우 낮은 편이 아니라면 높은 유사도를 우대 받을 수 있도록 하기위하여 IMDB의 weighted rating 방법에 피어슨 상관계수를 더하였다.

v와 R 값은 Movie_data_node에서 쉽게 구할 수 있으며 m과 C는 각각 다음과 같은 메소드를 이용하여 구할 수 있다. 해당 메소드의 헤더는 다음과 같다

static int percentile(ArrayList<Movie_data_node> movie_rating_matrix, double p)
static double total_average_rating(ArrayList<Movie_data_node> movie_rating_matrix)

위의 두 메소드는 milestone2에서 가져온 것이다. Percentile 메소드에서 p는 임의로 설정할 수 있다. 여기서는 0을 사용하였다. 그 이유는 만약 p가 0보다 크다면 유사도가 매우 높음에도 무시될 수 있기 때문이다. 그런 다음 movie_data_table에서 vote count가 m 이상인 객체만 골라서 classified_table라는 ArrayList를 만든다. 그 후 가중평균에 따라 내림차순으로 List를 sort 하고 상위 limit개의 영화만 출력한다.

sirin05137 commented 3 years ago

아이템 기반 협업 필터링의 단점

가장 큰 문제점은 영화에 대한 평가 수가 0일 경우 유사도를 구할 수 없다는 것이다. 또한 영화의 평가 수가 적을 경우에도 유사도의 신뢰성이 떨어진다. 이밖에도 특정 영화에 대한 서로 다른 유저의 평점이 모두 똑같을 경우(eg. movie A : (3,3,0,3), 0은 평가 하지 않은 것으로 취급) 피어슨 상관계수를 구할 수 없어서 영화간의 유사도를 구할 수 없게 된다. 유사도를 구할 수 없거나 유사도의 신뢰성이 떨어지는 경우 협업 필터링을 통해 제대로된 결과물(영화 추천)을 얻을 수 없다. 이를 해결하기 위해, 입력받은 영화의 평가 수가 100 이하일 경우 장르기반추천(Genre-based recommendation)을 사용하였다.

Genre-based recommendation

입력받은 영화의 장르와 각 영화별 장르의 유사도를 계산하여 영화를 추천해주는 방식이다. 유사도를 측정하는 데에는 자카드 유사도(Jaccard similarity)를 사용하였다. 자카드 유사도를 구하는 공식은 다음과 같다. image

또한 자카드 유사도는 다음과 같은 메소드를 통해 구할 수 있다.

static double get_jaccard_similarity(ArrayList<String> movie_data ,ArrayList<String> genre_of_input_list)

자카드 유사도를 통해 유사도를 구했으면 내림차순으로 유사도를 정렬시킨다. 정렬이 완료 되면 3가지 경우로 나누어서 생각해 볼 수 있다.

첫째, (limit*1.5)번째 유사도가 0이 아닌 경우

(limit1.5)번째 유사도를 A라 하자. 유사도가 1부터 A까지인 영화들을 모두 ArrayList<Movie_data_node> movie_data_table에 추가한다. (이 경우 A와 유사도가 같은 영화들도 리스트에 추가되므로 리스트의 길이는 (limit1.5)보다 크다.)

둘째, (limit*1.5)번째 유사도는 0이지만, limit번째 유사도는 0이 아닌 경우

limit번째 유사도를 B라 하자 유사도가 1부터 B까지인 영화들을 모두 ArrayList<Movie_data_node> movie_data_table에 추가한다. (이 경우 B와 유사도가 같은 영화들도 리스트에 추가되므로 리스트의 길이는 (limit)보다 크고 (limit*1.5)보다 작다 .)

셋째, limit번째 유사도가 0인 경우

유사도가 0이 아닌 영화들을 모두 ArrayList<Movie_data_node> movie_data_table에 추가한다. 유사도가 0인 영화들을 IMDb weighted rating 방식으로 계산하고 상위 (limit - 리스트 길이)개 만큼을 movie_data_table에 추가한다.

물론 만약 "Superman (1978)"을 입력받았으면 "Superman (1978)"을 출력할 필요가 없기 때문에 리스트에 추가할때 해당 항목은 제외하고 나머지 항목들을 추가한다.

IMDB의 weighted rating

W = (vR+mC)/(v+m)

v = 해당 영화의 총 투표수 m = Top 차트에 들기 위한 최소한의 투표수 R = 해당 영화의 평균 평점 C = 모든 영화의 평균 평점

v와 R 값은 Movie_data_node에서 쉽게 구할 수 있으며 m과 C는 각각 다음과 같은 메소드를 이용하여 구할 수 있다. 해당 메소드의 헤더는 다음과 같다

static int percentile(ArrayList<Movie_data_node> movie_rating_matrix, double p)
static double total_average_rating(ArrayList<Movie_data_node> movie_rating_matrix)

위의 두 메소드는 milestone2에서 가져온 것이다.

Percentile 메소드에서 p는 임의로 설정할 수 있다. p는 다음과 같은 메소드로 구할 수 있다.

static double get_ratio(int a, int b)

그런 다음 movie_data_table에서 vote count가 m 이상인 객체만 골라서 classified_table라는 ArrayList를 만든다. 그 후 가중평균에 따라 내림차순으로 List를 sort 하고 상위 limit개의 영화만 출력한다.

sirin05137 commented 3 years ago

참고 : [1], [2]

yuujinleee commented 3 years ago

리드미 주소 복붙용 유사도 image

피어슨 image 자카드 image