[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🛠 기타/Data & AI

기초 추천시스템 - 컨텐츠기반 필터링

inu 2020. 8. 21. 18:14
반응형
  • 추천 시스템의 종류에는 크게 컨텐츠기반 필터링, 협업 필터링이 있다.
  • 컨텐츠기반 필터링 : 컨텐츠끼리의 유사도 기반 추천, 장르 및 키워드 등의 정보를 벡터화하여 유사도를 측정한다.
  • 코사인 유사도 : 코사인 값을 기반으로 결정하는 유사도. 두 벡터의 각도가 직각이면 0, 180도면 -1, 0도면 1의 값을 갖는다.
  • kaggle에 존재하는 데이터로 추천시스템을 만들어 컨텐츠기반 필터링이 어떤 원리로 이루어지는지 알아보겠다.

추천시스템 : 데이터 불러오기 및 전처리

import pandas as pd
import numpy as np
from ast import literal_eval

movies = pd.read_csv('../data/tmdb_5000_movies.csv')
movies = movies.loc[:, ['title', 'genres', 'keywords']]

# 문자열 -> 딕셔너리 형태로 변환
movies['genres'] = movies['genres'].apply(literal_eval)
movies['keywords'] = movies['keywords'].apply(literal_eval)
  • tmdb_5000_movies.csv(https://www.kaggle.com/tmdb/tmdb-movie-metadata?select=tmdb_5000_movies.csv)로부터 데이터를 불러와 pd 데이터프레임 형태로 만든다.
  • 현재 movies의 genres와 keywords 컬럼의 데이터는 딕셔너리의 리스트로 구성된 것처럼 보이지만 실재로는 그렇지 않다.
  • literal_eval함수는 이러한 형태의 문자열 데이터를 한번에 딕셔너리 리스트화 해준다.
# [{}, {}, {}, {}] -> [장르, 장르, 장르, 장르]
movies['genres'] = movies['genres'].apply(lambda x : [y['name'] for y in x])
movies['keywords'] = movies['keywords'].apply(lambda x : [y['name'] for y in x])

# [장르, 장르, 장르, 장르] -> 장르 장르 장르 장르
movies['genres'] = movies['genres'].apply(lambda x : ' '.join(x))
movies['keywords'] = movies['keywords'].apply(lambda x : ' '.join(x))
  • 현재 데이터는 {'id': 28, 'name': 'Action'}와 같이 id와 내용이 함께 딕셔너리 형태로 들어있다.
  • 우리가 이중 사용할 것은 'Action'이라는 name 데이터이다. 따라서 lambda 함수로 이를 가져와 적용해준다.
  • 그리고 그를 사용하기 편하도록 [장르, 장르, 장르, 장르] -> 장르 장르 장르 장르 형태로 바꿔준다.

단어 벡터화

from sklearn.feature_extraction.text import TfidfVectorizer

# ngram_range=(1, 2) : 단어를 1개 혹은 2개 연속으로 보겠다
tfidf_vec = TfidfVectorizer(ngram_range=(1, 2))
tfidf_matrix = tfidf_vec.fit_transform(movies['keywords'])
  • keyword 데이터를 TfidfVectorizer(TFIDF 기반 벡터화) 메소드로 벡터화한다.
  • TF-IDF 방식으로 단어의 가중치를 조정한 BOW 벡터를 만든다.
  • ngram_range는 단어를 1개 혹은 2개 연속으로 보고 이를 하나로 묶는다는 의미이다. 예를 들어 [action adventure fantasy] 의 키워드를 가진 영화가 있다면 해당 키워드정보로부터 action, adventure, fantasy만 보고 벡터화하는 것이 아니라 action adventure, action fantasy, adventure fantasy도 보고 벡터화한다는 것이다.
  • 그러한 TfidfVectorizer를 기반으로 keyword 데이터를 바로 fit 및 transfrom 한다.

유사도 측정

from sklearn.metrics.pairwise import cosine_similarity

# 4803개의 영화랑 4803개의 영화끼리 유사도를 구하겠다!
# 자신과의 유사도는 1
genres_similarity = cosine_similarity(tfidf_matrix, tfidf_matrix)
print(genres_similarity)
# 유사도 값이 높은 영화의 제목
# 유사도 값이 높은 순으로 인덱스 값을 뽑아낸다
similar_index = np.argsort(-genres_similarity)
print(similar_index)
  • cosine_similarity 메소드는 코사인 유사도를 기반으로 유사도를 측정해준다.
  • 그렇게 측정된 유사도 행렬은 영화개수x영화개수의 shape를 가진다.
  • np.argsort(-genres_similarity)를 수행하면 genres_similarity를 유사도가 높은 순서대로 정렬한 인덱스 numpy 배열을 리턴한다. 즉, 각 영화에 해당하는 행마다 자신과 유사한 영화를 순서대로 가지고 있는 배열이 생성되는 것이다.

사용자입력 및 결과 출력

input_movie = input()

movie_index = movies[movies['title']==input_movie].index.values
similar_movies = similar_index[movie_index, :10]

# 인덱스로 사용하기 용이하도록 1차원으로 변경
similar_movies_index = similar_movies.reshape(-1)

display(movies.iloc[similar_movies_index])

  • 사용자가 입력한 영화의 인덱스 값을 찾아내고 similar_index 에 접근한다.
  • 그리고 similar_index에서 얻어낸 정보를 기반으로 유사도가 제일 가까운 10개의 영화 인덱스를 가져온다.
  • 해당 데이터는 2차원으로 되어있는데, 인덱스를 활용하기 용이하도록 1차원으로 변경한다.
  • movies 데이터에서 해당 인덱스 정보를 활용해 값을 출력한다.
반응형