일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Len
- where
- 데이터
- css
- 단어 공부
- 파이썬
- GIT
- 설계
- Django
- 파이썬 슬라이싱
- count
- List Comprehension
- SQL 고득점 Kit
- pcce 기출문제
- 프로그래머스
- date_format
- Join
- 아이엠어바텐더
- python
- YOLOv5
- sql
- Python3
- 프로젝트
- 파이썬 몫
- 코딩테스트 연습
- map
- 슬라이싱
- 백준
- html
- ORDER BY
- Today
- Total
nan + nan = 2nan
[개인프로젝트] 영화 추천 알고리즘 본문
인턴 합격 후 시간이 남는 중간에 그냥 혼자 여러가지 사이드 프로젝트를 해보고 싶었다.
아직은 실력이 낮기 때문에, youtube에서 이것 저것 찾아 보다가 영화 추천 알고리즘을 간단히 구현해보는 게 있었는데 재밌을 것 같아서 해봤다.
해당 코드는 Youtube의 '빵형의 개발도상국' 채널에 있는 영화 추천 만들기 영상에서 참조했다.
https://www.youtube.com/watch?v=mLwMe4KUZz8
import pandas as pd
import numpy as np
import json
meta = pd.read_csv('movies_metadata.csv', encoding='utf8', low_memory=False)
meta.head()
해당 데이터셋은 캐글에서 영화 관련 메타 데이터 셋을 이용했다.
https://www.kaggle.com/rounakbanik/the-movies-dataset
# 추천 데이터에 필요한 컬럼만 추림
meta = meta[['id', 'original_title', 'original_language', 'genres']]
# id 컬럼을 알아 보기 좋게 변경
meta = meta.rename(columns={'id' : 'movieId'})
# 영어로 된 데이터가 가장 많기 때문에, 영어로 된 데이터만 분류
meta = meta[meta['original_language'] == 'en']
meta.head()
# 평점 데이터를 불러온다
ratings = pd.read_csv('ratings_small.csv', encoding='utf8')
# 필요한 컬럼만 추림
ratings = ratings[['userId', 'movieId', 'rating']]
ratings.head()
# 평균, 편차, 최대, 4분위값 등 확인
ratings.describe()
# null 값 및 데이터 타입 확인
meta.info()
# 평점 관련 info. 지금 보니 non-null count가 왜 안 나왔는지 의문.
ratings.info()
# movieId를 object -> int 형태로 가공
meta.movieId = pd.to_numeric(meta.movieId, errors='coerce')
ratings.movieId = pd.to_numeric(meta.movieId, errors='coerce')
to_numeric은 데이터를 숫자 형식으로 바꿔주는 역할을 한다.
해당 코드에서는 object와 float 형태를 int 형태로 가공하기 위함이지 않나 싶다.
또한, 뒤의 errors 인자는 3가지 옵션이 존재한다.
1) ignore = 숫자로 변경할 수 없는 데이터라면, 원본 데이터를 그대로 반환
2) coerce = 숫자로 변경할 수 없는 데이터라면, 기존 데이터 삭제 후 Nan 값을 반환
3) raise = 숫자로 변경할 수 없는 데이터라면, 에러가 뜨면서 코드 중단
# genres가 json 형태로 string으로 저장
# 이를 배열 형태로, 장르만 뽑아내서 리스트에 담아주고,
# apply 함수를 활용해서 각 행마다 해당 함수를 적용시키게끔
def parse_genres(genres_str):
genres = json.loads(genres_str.replace('\'', '"'))
genres_list = []
for g in genres:
genres_list.append(g['name'])
return genres_list
meta['genres'] = meta['genres'].apply(parse_genres)
meta.head()
replace로 '\''를 '"' 치환 후 append를 하는 것 같은데, 해당 문자열이 어디있는지는 원 데이터를 봐도 잘 모르겠다..
그 다음 apply 함수를 통해서 행마다 함수를 적용시킨 후의 모습이다.
# 두 df를 movieId를 기준으로 inner 방식을 활용해서 merge.
data = pd.merge(ratings, meta, on='movieId', how='inner')
data.head(10)
# 피벗 테이블 생성
matrix = data.pivot_table(index='userId', columns='original_title', values='rating')
matrix.tail(20)
피어슨 상관계수
통계학에서, 피어슨 상관 계수란 두 변수 X 와 Y 간의 선형 상관 관계를 계량화한 수치
# 피어슨 상관관계
GENRE_WEIGHT = 0.1
# s1 의 각 행에서 s1의 평균 값을 빼준다.
# (s1 * s2) 합 / 제곱근(s1의 제곱의 합 * s2 제곱의 합)
# 즉, 두 변수의 공분산을 각각의 표준편차의 곱으로 나눈 값
# 피어슨 상관계수 = 공분산 / 표준편차 * 표준편차
def pearsonR(s1, s2):
s1_c = s1 - s1.mean()
s2_c = s2 - s2.mean()
return np.sum(s1_c * s2_c) / np.sqrt(np.sum(s1_c ** 2) * np.sum(s2_c ** 2))
# 추천 함수 작성
# 비교 대상 영화 타이틀/ 피벗 테이블 / 몇 개를 추천 받을 것인가 / 비슷한 장르에 가중치를 둘 것인가?
def recommend(input_movie, matrix, n, similar_genre=True):
# 가져온 타이틀의 장르를 추출
input_genres = meta[meta['original_title'] == input_movie]['genres'].iloc(0)[0]
# 결과를 담을 리스트 생성
result = []
for title in matrix.columns:
# 가져온 타이틀과 input 영화가 같다면 건너뛰기
if title == input_movie:
continue
# 피어슨 상관계수 계산
cor = pearsonR(matrix[input_movie], matrix[title])
# 장르를 비교
if similar_genre and len(input_genres) > 0:
temp_genres = meta[meta['original_title'] == title]['genres'].iloc(0)[0]
# in1d -> 배열을 비교하여 같은 요소가 있으면 True를 반환
same_count = np.sum(np.in1d(input_genres, temp_genres))
# 같은 장르가 많을수록 더 높은 가중치 부여
cor += (GENRE_WEIGHT * same_count)
# 피어슨 상관계수의 값이 nan 값이라면 건너뛰기
if np.isnan(cor):
continue
else:
# 상관계수 값이 있다면 결과 리스트에 제목 / 상관계수 점수 / 해당 title의 장르 append
result.append((title, '{:.2f}'.format(cor), temp_genres))
# 위 과정이 끝나면 rating이 높은 순서대로 (내림차순) sorting
result.sort(key=lambda r: r[1], reverse=True)
# n개 만큼 반환
return result[:n]
# '다크 나이트'와 비슷한 장르의 영화를 10개를 추천, 장르는 비슷한 것일수록 좋다(가중치 부여)
recommend_result = recommend('The Dark Knight', matrix, 10, similar_genre=True)
pd.DataFrame(recommend_result, columns= ['Title', 'Correlation',' Genre'])
가벼운 추천 시스템을 경험해보았다. 머신러닝이나 딥러닝 기법을 직접 사용하지 않고 피어슨 상관계수 로직을 통해 간단히 알고리즘을 구현한 것 같다.
해당 로직이 사용자 기반 협업 필터링과 관련된 로직이라고 하는데, 다음 글은 메모리 기반 협업 필터링과 모델 기반 협업 필터링의 차이를 파악하면서 공부해야겠다. 추천 시스템, 챗봇 등 많이 쓰이고 있는 기술들의 기본적인 프로세스와 로직은 알아야 나의 자산이 되지 않을까 싶다.
'Statistics > Machine Learning' 카테고리의 다른 글
[인턴] Data Cleansing 및 Undersampling, Modeling (0) | 2022.04.27 |
---|---|
[인턴] EDA 및 데이터 정제 (0) | 2022.04.15 |
[인턴] AI 병해충 진단 서비스 App 개발 (0) | 2022.03.15 |
[데이터 분석]구글 트렌드를 이용한 20대 대선 분석_1 (0) | 2022.03.15 |
[ML][210909] 선형회귀분석 (0) | 2021.09.09 |