📝ltem based collaborative filtering으로 영화 추천하는 기능 만들기
우선 데이터 데이터 프레임을 불러와서 불필요한 컬럼을 제거하고 합쳐준다
import pandas as pd
import numpy as np
# 영화정보파일과 리뷰파일을 불러온다
movie_titles_df = pd.read_csv('Movie_Id_Titles.csv')
movies_rating_df = pd.read_csv('u.data', sep='\t', names= ['user_id', 'item_id', 'rating', 'timestamp'])
# timestamp 컬럼은 필요없으니, movies_rating_df 에서 제거
movies_rating_df.drop('timestamp', axis= 1, inplace= True)
# 두개의 데이터프레임을 합치기(리뷰가 없는 영화정보도 가져오게 how= 'left')
movies_rating_df = pd.merge(movie_titles_df, movies_rating_df, on= 'item_id', how= 'left')
데이터를 분석한다
※ item_id 로 그룹바이하면 이 값이 인덱스로 표현되므로 판다스에서 데이터를 분석할때는
인덱스가 사람이 해석할 수 있는 데이터로 나타나도록 해주는게 좋다
# 영화 타이틀별로 리뷰 점수 통계치 조회
movies_rating_df.groupby('title')['rating'].describe()
# 영화 타이틀별로 리뷰 점수의 통계치를 평균이 높은 순으로 조회
movies_rating_df.groupby('title')['rating'].describe().sort_values('mean', ascending= False)
각 영화별 별점 평균수와 갯수를 변수에 저장하고 합친다
ratings_df_mean = movies_rating_df.groupby('title')['rating'].mean()
ratings_df_count = movies_rating_df.groupby('title')['rating'].count()
# 각각 데이터 프레임으로 만들고 컬럼 이름 변경
df1 = ratings_df_mean.to_frame()
df1.columns = ['mean']
df2 = ratings_df_count.to_frame()
df2.columns = ['count']
# join으로 합쳐준다
ratings_mean_count_df = df1.join(df2)
히스토그램으로 데이터를 확인해본다
import matplotlib.pyplot as plt
import seaborn as sns
ratings_mean_count_df['mean'].hist()
plt.show()
ratings_mean_count_df['count'].hist(bins= 50)
plt.show()
※ 평균 점수가 5점인 데이터를 확인해보면 리뷰 갯수가 1개인 것들이 많으니 나중에 처리해줘야한다
이제 상관계수를 뽑기 위해 데이터 프레임을 피봇테이블(pivot_table)한다
※ 인덱스는 user_id, 컬럼은 title, 그 안의 데이터(밸류)는 rating
df = movies_rating_df.pivot_table(index= 'user_id', columns= 'title', values= 'rating', aggfunc= 'mean') # aggfunc 디폴트는 평균이므로 안써도 됨
전체 데이터를 하기 전 한개의 데이터만 가지고 추천 시스템을 만들어보겠다
# 타이타닉 컬럼과 df의 전체 컬럼간의 상관계수를 뽑기
corr_titanic = df.corrwith( df['Titanic (1997)'] )
# 데이터 프레임으로 만들어주고 컬럼명을 변경해준다
corr_titanic = corr_titanic.to_frame()
corr_titanic.columns = ['correlation']
# 별점을 한명이 남긴 리뷰도 있을거니 확인하기 위해 카운트를 붙여준다
corr_titanic = corr_titanic.join( ratings_mean_count_df['count'] )
# nan은 아무 관계 없는 것이니 삭제해준다
corr_titanic.dropna(inplace= True)
# 이렇게 하면 count수가 적은 데이터도 있기 때문에 아래 코드로 실행한다
corr_titanic.sort_values('correlation', ascending= False)
# 80명 이상 리뷰를 남긴 영화만 가져와서 correlation 순으로 정렬
corr_titanic.loc[ corr_titanic['count'] >= 80 ].sort_values('correlation', ascending= False).head(10)
이렇게 한개의 데이터를 가지고 해봤으니 이제 전체 데이터셋에 대한 ltem based collaborative filter를 만든다
# 모든 영화의 상관계수를 뽑는다
# 단, 각 영화는 적어도 80명 이상이 별점을 준 영화만 상관계수를 뽑는다
corr_movie = df.corr(min_periods= 80)
# 나의 영화 별점 정보를 담은 파일을 가져온다
myRatings = pd.read_csv('My_Ratings.csv')
# 내가 본 영화는 여러개일 수 있기 때문에 반복문을 사용한다
similar_movies_list = pd.DataFrame()
for i in range( myRatings.shape[0] ) :
movie_title = myRatings['Movie Name'][i]
recom_movies = corr_movie[movie_title].dropna().sort_values(ascending= False).to_frame()
recom_movies.columns = ['correlation']
recom_movies['weight'] = recom_movies['correlation'] * myRatings['Ratings'][i]
similar_movies_list = similar_movies_list.append( recom_movies )
1. weight로 정렬한다 (내가 준 별점이 반영된 컬럼이 바로 weight)
similar_movies_list = similar_movies_list.sort_values('weight', ascending= False)
2. 내가 본 영화는 위의 데이터프레임에서 삭제한다
# 내가 본 영화 제목을 리스트로 만들어 변수에 저장
drop_index_list = myRatings['Movie Name'].to_list()
# 반복문을 사용해 봤던 영화의 행 제거
for name in drop_index_list :
if name in similar_movies_list.index :
similar_movies_list.drop(name, axis=0, inplace= True)
3. 내가 본 영화는 이제 없으므로 영화를 추천해주면 된다
similar_movies_list
★ 추천 영화가 중복되는 경우도 발생한다
따라서 중복된 영화가 있을 경우는 웨이트가 가장 높은 값으로만 추천해준다
즉, 영화 이름별로 웨이트가 가장 높은 데이터를 가져와서 웨이트로 정렬한다
# 중복 데이터가 있는지 먼저 확인한다
similar_movies_list.reset_index()['title'].value_counts()
# 중복이 있으니 제거한다
similar_movies_list.groupby('title')['weight'].max().sort_values(ascending= False)
'인공지능 > 인공지능' 카테고리의 다른 글
Time Series 데이터를 처리할때 사용하는 resample 함수 (0) | 2023.01.03 |
---|---|
Prophet 라이브러리를 이용한 Time Series 데이터 예측하기 (0) | 2023.01.02 |
댓글