[추천시스템] 넷플릭스 영화 추천 시스템 구현 파이썬 코드
2020. 4. 8. 14:12ㆍ노트/Python : 프로그래밍
데이터
- 필요한 데이터만 첨부
코드
import pandas as pd
import numpy as np
# 데이터 읽어오기
movies=pd.read_csv("movies.csv")
ratings=pd.read_csv("ratings.csv")
# 아이템 기반 협업 필터링
data=pd.merge(ratings,movies,on="movieId")
column=['userId','movieId','rating','title','genres']
data=data[column]
data
moviedata=data.pivot_table(index="movieId", columns='userId')['rating']
moviedata
#NaN값을 -1로 변경 ( 평점을 계산할 때 양수값만 처리하면 됌)
moviedata.fillna(-1, inplace=True)
moviedata
Kdd 유사도 기반 영화 추천 알고리즘
#kdd 유사도 함수
from math import sqrt
def sim_distance(data, n1, n2):
sum=0
#두 사용자가 모두 본 영화를 기준으로 해야해서 i로 변수 통일(j따로 안 써줌)
for i in data.loc[n1,data.loc[n1,:]>=0].index:
if data.loc[n2,i]>=0:
sum+=pow(data.loc[n1,i]-data.loc[n2,i],2) #누적합
return sqrt(1/(sum+1)) #유사도 형식으로 출력
# 나와 유사도가 높은 user 매칭 함수
def top_match(data, name, rank = 5, simf = sim_distance):
simList = []
for i in data.index[-10:]:
if name != i:
simList.append((simf(data, name, i), i))
simList.sort()
simList.reverse()
return simList[:rank]
# 추천 시스템 함수
def recommendation(data, person, simf = sim_distance):
res = top_match(data, person, len(data))
score_dic = {}
sim_dic = {}
myList = []
for sim, name in res:
if sim < 0:
continue
for movie in data.loc[person, data.loc[person, :] < 0].index:
simSum = 0
if data.loc[name, movie] >= 0:
simSum += sim * data.loc[name, movie]
score_dic.setdefault(movie, 0)
score_dic[movie] += simSum
sim_dic.setdefault(movie, 0)
sim_dic[movie] += sim
for key in score_dic:
myList.append((score_dic[key] / sim_dic[key], key))
myList.sort()
myList.reverse()
return myList
# 25번 user가 안본 영화중에서
#추천 점수가 가장 높은 순으로 예상평점과 영화제목을 추천 (10개까지)
movieList = []
for rate, m_id in recommendation(moviedata, 25):
movieList.append((rate, movies.loc[movies['movieId'] == m_id, 'title'].values[0]))
movieList[:10]
피어슨 상관계수 기반 영화 추천 알고리즘
#피어슨 상관계수
def sim_pearson(data, n1, n2):
#구현
sumX=0
sumY=0
sumSqX=0 # x 제곱합
sumSqY=0 # y 제곱합
sumXY=0 #XY 합
cnt =0 #영화 갯수
for i in data.loc[n1,data.loc[n1,:]>=0].index:
if data.loc[n2,i]>=0:
sumX+=data.loc[n1,i]
sumY+=data.loc[n2,i]
sumSqX+=pow(data.loc[n1,i],2)
sumSqY+=pow(data.loc[n2,i],2)
sumXY+=(data.loc[n1,i])*(data.loc[n2,i])
cnt+=1
global num # 전역변수 선언
global den # 전역변수 선언
num=sumXY-((sumX*sumY)/cnt)
den= (sumSqX-(pow(sumX,2)/cnt))*(sumSqY-(pow(sumY,2)/cnt))
return num/sqrt(den+0.00001) # 분모=0방지
#나와 유사도가 높은 user와 매칭 함수
def top_match(data, name, rank = 5, simf = sim_pearson):
simList = []
for i in data.index:
if name != i:
if simf(data, name, i) is not None:
simList.append((simf(data, name, i), i))
simList.sort()
simList.reverse()
return simList[:rank]
#추천 시스템 함수
def recommendation(data, person, simf = sim_pearson):
res = top_match(data, person, len(data))
score_dic = {}
sim_dic = {}
myList = []
for sim, name in res:
if sim < 0:
continue
for movie in data.loc[person, data.loc[person, :] < 0].index:
simSum = 0
if data.loc[name, movie] >= 0:
simSum += sim * data.loc[name, movie]
score_dic.setdefault(movie, 0)
score_dic[movie] += simSum
sim_dic.setdefault(movie, 0)
sim_dic[movie] += sim
for key in score_dic:
myList.append((score_dic[key] / sim_dic[key], key))
myList.sort()
myList.reverse()
return myList
movieList = []
for rate, m_id in recommendation(moviedata, 1):
movieList.append((rate, movies.loc[movies['movieId'] == m_id, 'title'].values[0]))
if len(movieList)==10: #10 개되면 멈추기
break
movieList[:10] # 10개만 추출
- 알고리즘 단점: 계산 느림
코사인 유사도 기반 영화 추천 알고리즘
: 메타데이터의 영화 줄거리 데이터가 있을때, 이와 유사한 영화를 추천해주는 알고리즘
데이터
https://www.kaggle.com/rounakbanik/the-movies-dataset
데이터불러오기
#데이터 불러오기
import pandas as pd
data=pd.read_csv("movies_metadata.csv",encoding="UTF-8")
#데이터가 많은 관계로 20000개까지 짜름
data=data.head(20000)
데이터 결측값 처리
data['overview'].isnull().sum() #135
data['overview']=data['overview'].fillna('')
data['overview'].isnull().sum() #0 으로 바뀜 내적하면 모두 0 나옴
tf-idf행렬 생성
# tfidf 행렬 생성
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf=TfidfVectorizer(stop_words='english')#불용어 제거
tfidf_mat=tfidf.fit_transform(data['overview']).toarray()
- 줄거리 행렬에 대한 tf-idf행렬을 생성하여 단어의 빈도수를 나타내고 array(배열)로 변경
코사인 유사도 함수
#코사인유사도함수 2 (분모=!0)
from numpy.linalg import norm
def cos_sim2(X,Y):
return np.dot(X,Y)/((norm(X)*norm(Y))+1e-7)
- 분모가0이 되지 않도록 1e-7 값을 넣어줄 것
추천함수
#추천 함수
def top_match_ar2(data, name, rank=5,simf=cos_sim2):
sim=[]
for i in range(len(data)):
if name != i:
sim.append((simf(data[i],data[name]),i))
sim.sort()
sim.reverse()
return sim[:rank]
영화 추천
(영화제목, 코사인유사도) 출력
# Toystory와 코사인유사도가 비슷한 순으로 영화 추천 : (영화제목, 코사인유사도)
movieList = []
for sim, movie_id in top_match_ar2(tfidf_mat,0,10):
movieList.append((sim, data.loc[movie_id,'title']))
movieList[:10]
- 실제로 Toy Story와 줄거리가 비슷한 Toy Story 3, Toy Story 2가 출력되었음을 확인할 수 있음.
※실제 넷플릭스에서 사용하는 알고리즘은 아니며, 직원이 아닌 관계로 알 수 없습니다.
'노트 > Python : 프로그래밍' 카테고리의 다른 글
[파이썬기초] 시계열 데이터 생성하기 (0) | 2020.04.13 |
---|---|
[토픽모델링] LSA (Latent Similarity Analysis)를 이용한 토픽모델링 파이썬 코드 (1) | 2020.04.09 |
[파이썬기초] 데이터전처리 중복값 처리 (0) | 2020.04.07 |
[알고리즘] 영화 추천 시스템 코드 (1) | 2020.04.06 |
[파이썬기초] 데이터전처리 결측값 (NaN) 처리 (0) | 2020.04.06 |