python - 최근접 이웃 협업 필터링

chi yeong Yu·2022년 3월 5일
0
post-thumbnail

추천 시스템은 컨텐츠 기반, 협업 필터링 방식으로 나뉨

협업필터링에서는 최근접 이웃, 잠재 요인 으로 나뉨

ex) 나와 비슷한 취향을 가진 사람에게 다른 영화 정보를 묻는 방법

최근접 이웃 협업 필터링은 사용자, 아이템 으로 나뉨

  • 사용자 = 나와 비슷한 성향의 사람이 높은 점수를 준 영화를 추천
  • 아이템 = 아이템에 대한 평가가 유사한 아이템을 추천하는 방식(일반적으로 성능이 뛰어나다고 함)

아이템 기반의 협업 필터링을 구현해 봄.

  • (아이템 기반이 아이템의 속성이 비슷한 것이 아닌 평가가 유사한 것을 추천하는 방식)

데이터는 User_id 별 영화 점수를 매긴 데이터

https://grouplens.org/datasets/movielens/latest/

import pandas as pd
import numpy as np

movies = pd.read_csv('movies.csv')
ratings = pd.read_csv('ratings.csv')

ratings_movie = pd.merge(ratings, movies, on='movieId')

ratings_matrix = ratings_movie.pivot_table('rating', 'userId', 'title')
# pivot_table(value, index, columns) 
# 사용자별 영화 평점 
ratings_matrix.fillna(0, inplace=True)
#NaN = 0 으로 채우기
ratings_matrix_T = ratings_matrix.T
# 영화별 사용자 평점 
# index <-> columns 위치를 바꾸기
# 아이템기반 협업 필터링을 하기위해 사용자-아이템 행렬을 아이템-사용자 행렬을 사용
ratings_matrix.head(3)

ratings_matrix.T.head(3)

from sklearn.metrics.pairwise import cosine_similarity

sklearn_cosine = cosine_similarity(ratings_matrix_T, ratings_matrix_T)

item_similarity = pd.DataFrame(sklearn_cosine, index=ratings_matrix_T.index, columns = ratings_matrix_T.index)

item_similarity.head(3)

item_similarity[movies['title'][300]].sort_values(ascending=False)[:5]
#movies['title'][300] = Muriel's Wedding (1994) 
# 평가 점수와 유사한 영화를 추천 

def predict_rating(ratings_array, item_similarity):
    sum_sr = ratings_array @ item_similarity
            # u x i , item_similarity = ixi
        # @ 연산자는 np.matmul, np.dot 행렬 곱을 해줌
    sum_abs = np.array([np.abs(item_similarity).sum(axis=1)])
    
    ratings_pred = sum_sr / sum_abs
    return ratings_pred

rating_pred = predict_rating(ratings_matrix.values, item_similarity.values)

rating_pred_matrix = pd.DataFrame(data=rating_pred, index=ratings_matrix.index, columns = ratings_matrix.columns)

rating_pred_matrix.head()

def no_watch(ratings_matrix, user):
    user_rating = ratings_matrix.loc[user,:]
    #user_id 별로 평점 정보
    no_watching = user_rating[user_rating==0].index.tolist()
    # 보지않은 영화 리스트
    movie_list = ratings_matrix.columns.tolist()
    # 모든 영화를 리스트 만들기
    no_list = [movie for movie in movie_list if movie in no_watching]
    # 안 본 영화 리스트 
    return no_list

def recommend_movie_by_userid(pred_df, userId, no_list, top_n=10):
    # 안 본 영화리스트 중 예측 점수가 가장 높은 순서 .series
    recommend_movie = pred_df.loc[userId, no_list].sort_values(ascending=False)[:top_n]
    return recommend_movie

user_id = 15
no_watch = no_watch(ratings_matrix, user_id)

recommend_movie = recommend_movie_by_userid(rating_pred_matrix, user_id, no_watch, top_n=10)

recom_movies = pd.DataFrame(data=recommend_movie.values, index=recommend_movie.index, columns=['pred_score'])
recom_movies

참고 문서 https://romg2.github.io/mlguide/02_%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD%EA%B0%80%EC%9D%B4%EB%93%9C-09.-%EC%B6%94%EC%B2%9C%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%B5%9C%EA%B7%BC%EC%A0%91-%EC%9D%B4%EC%9B%83/

profile
호기심천국

0개의 댓글