[추천시스템] 넷플릭스 영화 추천 시스템 구현 파이썬 코드

2020. 4. 8. 14:12노트/Python : 프로그래밍

 

데이터 

 

movie_ratings.zip
7.12MB

  • 필요한 데이터만 첨부

 

코드 

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 유사도 기반 영화 추천 알고리즘 

출처: 멀티캠퍼스_빅데이터AI설계 박길식 강사님 PPT

#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

 

The Movies Dataset

Metadata on over 45,000 movies. 26 million ratings from over 270,000 users.

www.kaggle.com

데이터불러오기

#데이터 불러오기 
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(배열)로 변경

 

코사인 유사도 함수

 

출처: 멀티캠퍼스_빅데이터AI설계 박길식 강사님 PPT

#코사인유사도함수 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가 출력되었음을 확인할 수 있음.

 

 

※실제 넷플릭스에서 사용하는 알고리즘은 아니며, 직원이 아닌 관계로 알 수 없습니다.