[핸즈온 추천시스템] Collaborative filtering (CF)란?

Collaborative FIltering에 대해 알아보고, python을 활용해 추천시스템을 만들어 보겠습니다.

chrisjune
6 min readJun 2, 2023
Image: source

Collaborative filtering은 평점정보와 같은 Explicit한 데이터 또는 클릭이나 구매와 같은 Implicit한 데이터를 활용하여 추천정보를 제공하는 것을 의미합니다.

크게는 메모리기반 방법과 모델기반 방법이 있으며, 대표적으로 KNN(K-Nearest neighborhood)는 메모리 기반, Matrix Factorization은 모델 기반 방법입니다.

가장 먼저 할 수 있는 알고리즘은 유사도를 활용하여 상품추천모델을 만들 수 있습니다. 유사도는 다양한 툴에서 구할 수 있기 때문에 SQL 쿼리만으로도 추천시스템을 만들 수 있습니다.

여기에서는 Movie-dataset과 Cosine similarity로 간단하게 상품추천을 만들어 보겠습니다.

사전작업

# 라이브러리설치
!pip install kaggle pandas numpy matplotlib scikit-learn

# https://www.geeksforgeeks.org/how-to-download-kaggle-datasets-into-jupyter-notebook/
# 링크로 이동하여 1번, 2번 스탭 가이드대로 현재위치에 kaggle.json 파일을 다운로드

# kaggle 폴더 생성
!mkdir ~/.kaggle
!cp ./kaggle.json ~/.kaggle
!chmod 600 ~/.kaggle/kaggle.json

# 데이터셋 다운로드
!kaggle datasets download -d rounakbanik/the-movies-dataset

# 데이터셋 압축해제
!mkdir dataset
!mv ./the-movies-dataset.zip ./dataset
!unzip -d dataset dataset/the-movies-dataset.zip

데이터 전처리

# 필요 라이브러리 임포트
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# 데이터 로딩
ratings = pd.read_csv("./dataset/ratings_small.csv")
movies = pd.read_csv("./dataset/movies_metadata.csv")

# rating 데이터와 movie 데이터를 머지전 movie 데이터에 컬럼명을 변경
movies.rename(columns={"id": "movieId"},inplace=True)

def is_number(s):
try:
float(s)
return True
except ValueError:
return False

# movieId 컬럼에 숫자가 아닌 값들은 비정상 데이터로 판단하여 제외
movies = movies[movies['movieId'].apply(is_number)]
movies['movieId'] = movies.movieId.astype(np.int64)
movie_ratings = pd.merge(ratings,movies, on='movieId')
movie_ratings.head()

학습

학습전 데이터를 row는 userId, colum은 영화명인 user-item matrix로 변경이 필요합니다. user-item matrix에는 모든 유저가 평가한 평점이 담겨 있으며, 대부분의 데이터는 평점이 없기 때문에 0으로 표현됩니다. 실제 데이터의 경우 대부분 sparsity가 99%이상입니다.

보통 Scipy library의 sparse matrix를 활용하면 평점이 없는 데이터를 표현하는데 드는 메모리를 절약할 수 있습니다. 여기에서는 데이터가 적기 때문에 pivot_table 메서드를 활용하여 user-item matrix로 변경하겠습니다.

data = movie_ratings.pivot_table('rating', index='userId', columns='title').fillna(0)
data = data.transpose()
cossim = cosine_similarity(data)
movie_sim_df = pd.DataFrame(cossim, index=data.index, columns=data.index)
movie_sim_df.head()

추천결과

top_k = 10
movie_sim_df["Batman Returns"].sort_values(ascending=False)[1:top_k+1]

아래는 CBF로 학습한 결과에 대한 추천인데, CBF의 결과는 다소 뻔하게 여겨질 수 있는 반면 CF의 결과는 뻔하지 않는 결과를 확인할 수 있습니다.

유사도를 활용한 CF는 구현이 쉬운 장점이 있지만, 유사도 계산의 막대한 비용이 드는 단점이 있습니다. 상황에 따라 다양한 모델을 선택할 수 있는 능력이 중요하다고 생각합니다.

본 포스팅이 조금이라도 도움이 되셨다면 좋겠습니다. 감사합니다

참고

--

--