2018. 8. 8. 23:30ㆍkaggle
kaggle 영화 추천 시스템
데이터는 아래의 사이트에가서 다운 받으면 된다.
이걸 하면서 처음봤지만 영화관련 데이터는 이곳에서 가져오는 것 같다.
이런 데이터들을 이렇게 저렇게 요리해서 4개의 단순한 추천 기능을 만들 것 이다.
장르를 통한 추천: 이 시스템은 전반적으로 TMDB 투표수와 평균 투표수를 사용해서 특정 장르 영화를 추천해주는 시스템입니다. IMDB 가중평가 시스템은 정렬이 최종적으로 수행 된 평가를 계산하는 데 사용되었습니다.
- 콘텐츠 기반 추천: 영화의 내용과 캐릭터, 감독, 배우 등등을 고려하여 추천하는 시스템이다.
- 협업 필터링: surprise 라이브러리를 사용하여 단일값 분해를 기반으로 협업필터링을 작성할 수 있다. 여기서 구해진 평균제곱 오차는 1보다 작으며 사용자 및 영화에 대한 평가를 제공합니다.
- Hybrid Engine: 콘텐츠(내용, 감독, 배우)와 협업 필터링 아이디어를 모아서 내부적으로 계산한 예상 등급을 기반으로 영화를 추천해줍니다.
%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from ast import literal_eval # 문자열 모형의 딕트를 스근하게 데이터 형 딕트로 바꾸어 준다.
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer #문자열 데이터를 벡터화
from sklearn.metrics.pairwise import linear_kernel, cosine_similarity
from nltk.stem.snowball import SnowballStemmer #dogs나 다...크킄크크 같은 것을 일반적인 단어로 바꿔준다.
from nltk.stem.wordnet import WordNetLemmatizer
from nltk.corpus import wordnet
from surprise import Reader, Dataset, SVD, evaluate
import warnings; warnings.simplefilter('ignore')
2. 데이터 읽어오고 각종 특징 보기
md = pd.read_csv('input/movies_metadata.csv')
데이터를 읽어온다. 그리고 head나 describe, isnull().sum()등을 사용하여 데이터들의 특징들을 본다.
md.isnull().sum()
adult 0
belongs_to_collection 40972
budget 0
genres 0
homepage 37684
id 0
imdb_id 17
......
이런식으로 데이터에 nan 값이 있는지 확인 할 수 있다.
md.describe()
3. data 정제해주기
3-1 genres 칼럼 데이터 정제해주기
genres라는 칼럼에는 영화가 어떤 장르인지 리스트형태로 나타나 있다.
이런식으로
[{'id': 16, 'name': 'Animation'}, {'id': 35, '...
1 [{'id': 12, 'name': 'Adventure'}, {'id': 14, '...
2 [{'id': 10749, 'name': 'Romance'}, {'id': 35, ...
3 [{'id': 35, 'name': 'Comedy'}, {'id': 18, 'nam...
이걸 도큐먼트 안에있는 name이라는 값을 각영화마다 따로 빼내서 넣어보자!!
md['genres'] = md['genres'].fillna('[]').apply(literal_eval).apply(lambda x : [i['name'] for i in x] if isinstance(x, list) else [])
fillna는 nan인 데이터를 알아서 채워주고 literal_eval은 문자열 형태의 도큐먼트를 진짜 도큐먼트로 바꾸는 기능을한다. []안에 장르를 다넣어 주고 결과를 보면 아래와 같은 형태로 genres에 적용 된 것을 알 수 있다.
0 [Animation, Comedy, Family]
1 [Adventure, Fantasy, Family]
2 [Romance, Comedy]
3 [Comedy, Drama, Romance]
4 [Comedy]
5 [Action, Crime, Drama, Thriller]
6 [Comedy, Romance]
7 [Action, Adventure, Drama, Family]
8 [Action, Adventure, Thriller]
9 [Adventure, Action, Thriller]
3-2 투표수와 평점에의해 영화별 평가점수 내보기
TMDB사이트에서 제공하는 영화 평점을 이용해서 영화 차트를 만들어 보겠습니다.
공식은 IMDB에서 제공하는 공식을 사용해서 영화평점을 만들어 보겠습니다.
- v는 영화의 득표수
- m은 차트에 나열되기 위한 최소한의 투표수
- R은 영화의 평균 평점
- C는 전체 차트의 평균 평점
vote_count = md[md['vote_count'].notnull()]['vote_count'].astype('int')
vote_average = md[md['vote_average'].notnull()]['vote_average'].astype('int')
m = vote_count.quantile(0.95) #quanitle은 4분위 데이터를 말한건데 0.95는 95% 부터의 데이터를 의미한다.
C = vote_average.mean()
영화 개봉일에서 출시년도만 빼서 데이터에 넣기
md['year'] = md['release_date'].apply(lambda x : str(x).split('-')[0] if x != np.nan else np.nan)
0 1995
1 1995
2 1995
3 1995
4 1995
5 1995
qualified = md[(md['vote_count'].notnull()) & (md['vote_average'].notnull()) & (md['vote_count'] >= m)][['title', 'year',
'vote_count', 'vote_average', 'popularity', 'genres']]
qualified['vote_count'] = qualified['vote_count'].astype(int)
qualified['vote_average'] = qualified['vote_average'].astype(int)
qualified라는 데이터 셋을 따로하나 만든다.
def weight_rate(x):
v = x['vote_count']
r = x['vote_average']
return (v / (v + m)*r) + (m/(m+v)*C)
위는 점수를 만들 함수이다.
qualified['wr'] = qualified.apply(weight_rate, axis=1) qualified = qualified.sort_values(by='wr', ascending=False)
qualified['wr']를 만들어서 얘를 기준으로 정렬시켜준다.
qualified.head(10)를 통해서 상위 10개의 영화를 볼 수 있다.
4 장르를 통해서 평가해보기
위 사진의 결과를 보면 한감독의 영화인 Inception, 다크나이트, 인터스텔라 등등의 영화과 상위권인 것을 알 수 있다. 그렇다면 이번에는 장르를 통해서 상위권 영화를 뽑아보겠다.
s = md.apply(lambda x: pd.Series(x['genres']), axis=1).stack().reset_index(level=1, drop=True)
s
0 Animation
0 Comedy
0 Family
1 Adventure
1 Fantasy
1 Family
2 Romance
2 Comedy
3 Comedy
3 Drama
3 Romance
이런식으로 s에 데이터가 저장된다. 각 인덱스의 0이나 1은 동일한 영화에 장르를 말하는 것입니다.
s.name = 'genres'
s_gen = md.drop('genres', axis=1).join(s)
이 코드를 실행하면 원래 존재하던 genres는 지워버리고 새로운 genres 데이터인 s를 집어 넣는다. 토이스토리는 장르가 3개이니 같은 영화 데이터가 장르에 따라서 세개 만들어짐을 알 수 있다.
0 False {'id': 10194, 'name': 'Toy Story Collection', ... 30000000
0 False {'id': 10194, 'name': 'Toy Story Collection', ... 30000000
0 False {'id': 10194, 'name': 'Toy Story Collection', ... 30000000
def chart_bar(genre, percenTage=0.85):
df = s_gen[s_gen['genres'] == genre]
vote_count = df[df['vote_count'].notnull()]['vote_count'].astype(int)
vote_average = df[df['vote_average'].notnull()]['vote_average'].astype(int)
m = vote_count.quantile(percenTage)
c = vote_average.mean()
qualified = df[(df['vote_count'].notnull()) & (df['vote_count'] >= m) & (df['vote_average'].notnull())] [['title', 'year', 'vote_count', 'vote_average', 'popularity']]
qualified['vote_count'] = qualified['vote_count'].astype('int')
qualified['vote_average'] = qualified['vote_average'].astype('int')
qualified['wr'] = qualified.apply(lambda x: (x['vote_count'] / (x['vote_count'] + m)*x['vote_average']) + (m/(m+x['vote_count'])*c), axis=1)
qualified = qualified.sort_values('wr', ascending=False) return qualified
위는 장르별 순위를 정해주는 함수이다. 지금까지 우리가 진행했던 과정과 비슷하여 어렵지 않은 코드이다.
chart_bar('Romance').head(3)
chart_bar('Adventure').head(3)
다음에는 영화 내용이나 감독, 배우를 통해서 추천하는 시스템을 만들어 보겠다.
일단 저는 이제막 타이타닉만 해본 햇병아리입니다.
'kaggle' 카테고리의 다른 글
[kaggle] 영화 추천 시스템 2편 (0) | 2018.08.09 |
---|