추천 시스템 개요 및 이론, Surprise Package
I. 개요
- 대고객 대상으로 한 대부분의 플랫폼 서비스 업체들은 고객 개개인에게 맞춤형의 추천 서비스를 도입하고 있음
- 전자상거래 업체, 유투브, 애플 뮤직 등
- ML의 여러 알고리즘 중 비즈니스 관점에 부합하는 기법이 추천 시스템.
- 추천 시스템의 진정한 묘미는 사용자 본인도 모르는 취향 발견, 재구매로 연결하도록 설계
- 누가 필요할까?
- 모든 플랫폼 서비스
- 이유1: 플랫폼은 다수의 판매자와 소비자를 필요로 함, 문제는 카테고리와 메뉴구성이 복잡해지면 소비자의 제품 선택에 부작용
- 이유2: 만족도가 떨어지면 고객은 그 플랫폼을 떠날 가능성이 크며, 이는 플랫폼 서비스의 매출 하락과 직결
- 모든 플랫폼 서비스는 기본적으로 추천서비스를 장착하고 싶어함
- 영화 데이터를 기준으로 추천시스템을 단계별로 구현함을 목표로 함
II. 추천시스템의 유형 및 역사
- 추천시스템의 유형과 간단한 역사에 대해 배워보도록 한다.
(1) 유형
- 크게 세가지로 구분됨.
- Demographic Filtering
- 콘텐츠 기반 필터링 (Content Filtering)
- 협업 필터링 (Collaborative Filtering)
- 최근접 이웃(Nearest Neighbor)
- 잠재 요인(Latent Factor)
(2) 역사
- 초창기: 콘텐츠 기반 필터링 또는 최근접 이웃 기반 협업 필터링이 주로 사용됨.
- 중기: 넷플릭스 추천 시스템 경연 대회에서 행렬 분해 (Matrix Factorization) 기법을 이용한 잠재요인 협업 필터링 방식으로 우승한 뒤, 유명해짐.
- 최근: 개인화 특성을 강화하기 위해서 하이브리드 형식으로 콘텐츠 기반과 협업 기반을 적절히 결합해 사용하는 경우도 늘고 있음
III. Surprise 패키지
Surprise
패키지는 추천시스템 패키지이다.- 설치 방법은 다음 문서를 참조하기를 바란다.
- 해당 패키지를 활용하면 보다 쉽게
API
를 활용해서 추천 시스템을 구축할 수 있다.- 다양한 추천 알고리즘들이 해당 패키지에 내재되어 있다.
(1) 패키지 개요
-
영어 원문에는 아래와 같이 설명되어 있다.
-
Give users perfect control over their experiments. To this end, a strong emphasis is laid on documentation, which we have tried to make as clear and precise as possible by pointing out every detail of the algorithms.
-
Alleviate the pain of Dataset handling. Users can use both built-in datasets (Movielens, Jester), and their own custom datasets.
-
Provide various ready-to-use prediction algorithms such as baseline algorithms, neighborhood methods, matrix factorization-based ( SVD, PMF, SVD++, NMF), and many others. Also, various similarity measures (cosine, MSD, pearson…) are built-in.
-
위 글에서 보는 것처럼, 최근접이웃과 같은 다양한 알고리즘들이 내장되어 있는 것을 볼 수 있다.
-
Make it easy to implement new algorithm ideas.
-
Provide tools to evaluate, analyse and compare the algorithms performance. Cross-validation procedures can be run very easily using powerful CV iterators (inspired by scikit-learn excellent tools), as well as exhaustive search over a set of parameters.
-
-
Surprise 패키지의 API는 사이킷런의 핵심 API와 유사하다.
(2) 데이터 수집
- 데이터는
kaggle
에서 가져왔다.
(3) 데이터 설명
- 여러 데이터들이 있는데, 관련 내용은 캐글 본문의 것을 그대로 사용한다.
- movies_metadata.csv: The main Movies Metadata file. Contains information on 45,000 movies featured in the Full MovieLens dataset. Features include posters, backdrops, budget, revenue, release dates, languages, production countries and companies.
- keywords.csv: Contains the movie plot keywords for our MovieLens movies. Available in the form of a stringified JSON Object.
- credits.csv: Consists of Cast and Crew Information for all our movies. Available in the form of a stringified JSON Object.
- links.csv: The file that contains the TMDB and IMDB IDs of all the movies featured in the Full MovieLens dataset.
- links_small.csv: Contains the TMDB and IMDB IDs of a small subset of 9,000 movies of the Full Dataset.
- ratings_small.csv: The subset of 100,000 ratings from 700 users on 9,000 movies.
(4) 구글 드라이브와 연동
- 구글 드라이브와 연동하여
pandas
를 활용하여 데이터를 수집한다. - 구글 드라이브와 연동하는 방법에 대해서는 Colab + Drive + Github Workflow에서 확인한다.
from google.colab import drive # 패키지 불러오기
from os.path import join
ROOT = "/content/drive" # 드라이브 기본 경로
print(ROOT) # print content of ROOT (Optional)
drive.mount(ROOT) # 드라이브 기본 경로 Mount
MY_GOOGLE_DRIVE_PATH = 'My Drive/Colab Notebooks/your/path' # 프로젝트 경로
PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH) # 프로젝트 경로
print(PROJECT_PATH)
/content/drive
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6q
Enter your authorization code:
··········
Mounted at /content/drive
/content/drive/My Drive/Colab Notebooks/your/path
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_recommendation
!ls
data source
import pandas as pd
import pandas_profiling
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
import seaborn as sns
from IPython.core.display import display, HTML
from pandas_profiling import ProfileReport
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
import pandas.util.testing as tm
- 이번에 수집하는 데이터는 사용자 ID와 영화 ID를 기반으로 한
ratings_small
데이터를 활용한다.
import pandas as pd
ratings = pd.read_csv('data/ratings_small.csv', low_memory=False)
print(ratings.head(3))
userId movieId rating timestamp
0 1 31 2.5 1260759144
1 1 1029 3.0 1260759179
2 1 1061 3.0 1260759182
IV. 협업 필터링
- 추천시스템에서 획기적인 전기를 마련한 회사가 넷플릭스 회사이다.
- 크게 두가지 방식이 있다.
- 최근접 이웃 협업 필터링
- 잠재 요인 협업 필터링
- 본 포스트에서는 잠재 요인 협업 필터링에 대해 기술하고 활용한다.
(1) 잠재 요인 협업 필터링의 이해
- 사용자-아이템 평점 매트릭스 속에 숨어 있는 잠재 요인을 추출해 추천 예측을 할 수 있게 하는 기법
- 이 때 문제는
잠재 요인
이 어떤 것인지는 명확히 정의할 수 없음. - 다음 수식을 본다.
$$ R \approx PQ^{2} $$
-
R:
m
명의 사용자들의n
개의 아이템에 대한 평점 행렬 -
P:
m
명의 사용자와k
요인에 대한 관계 행렬 -
Q:
n
개의 아이템과k
요인에 대한 관계 행렬- 여기에서 문제는
Matrix Factorization
을 활용하려면 기본적으로모든 사용자들이 모든 상품들에 대해 평점을 매기는 조건
이 필요하다. - 그런데, 현실적으로 행렬
R
은 대부분 희소 행렬(Sparse Matrix)이 된다. - 이렇게 다차원의 희소 행렬인 사용자-아이템 행렬 데이터를 저차원의 밀집 행렬의 사용자-잠재요인 행렬과, 아이템-잠재요인 행렬로 분해한 뒤, 두 행렬의 내적(뜻: 벡터의 곱으로 결과값이 상수를 가짐)을 통해 새로운 예측 사용자-아이템 평점 행렬 데이터를 만들어서 사용자가 아직 평점을 부여하지 않는 아이템에 대한 예측 평점을 생성하는 것이
잠재 요인 협력 필터링 알고리즘
의 뜻 - 이 때 사용되는 기법이
SVD
,NMF
등이 있음.
- 여기에서 문제는
(2) Simple Code
Surprise
패키지에는 이러한 알고리즘이 내재되어 있다. 필수 모듈을 설치한 뒤 간단하게 구현해본다.- 우선
Reader()
클래스를 활용한다. - Reader()는 다음과 같은 구조를 필요로
user ; item ; rating ; [timestamp]
- 만약 위와 같이 되어 있지 않다면 데이터를 수정해야 한다.
Reader
형태로 데이터를 변환하는 의미로 생각하면 된다.
- Dataset.load_from_df는 판다스의
DataFrame
에서 데이터를 로딩한다. 마찬가지로 반드시 3개의 칼럼인 사용자 아이디, 아이템 아이디, 평점 순으로 칼럼 순서가 정해야 있어야 하며,Reader
로 파일의 포맷을 지정한다.
!pip install scikit-surprise
Collecting scikit-surprise
[?25l Downloading https://files.pythonhosted.org/packages/f5/da/b5700d96495fb4f092be497f02492768a3d96a3f4fa2ae7dea46d4081cfa/scikit-surprise-1.1.0.tar.gz (6.4MB)
[K |████████████████████████████████| 6.5MB 6.2MB/s
[?25hRequirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (0.15.1)
Requirement already satisfied: numpy>=1.11.2 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.18.5)
Requirement already satisfied: scipy>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.4.1)
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.12.0)
Building wheels for collected packages: scikit-surprise
Building wheel for scikit-surprise (setup.py) ... [?25l[?25hdone
Created wheel for scikit-surprise: filename=scikit_surprise-1.1.0-cp36-cp36m-linux_x86_64.whl size=1675756 sha256=a46585f526f96128004380c19928286fd41a0c79822adcd4ed9717572e0ffd93
Stored in directory: /root/.cache/pip/wheels/cc/fa/8c/16c93fccce688ae1bde7d979ff102f7bee980d9cfeb8641bcf
Successfully built scikit-surprise
Installing collected packages: scikit-surprise
Successfully installed scikit-surprise-1.1.0
from surprise import Reader, Dataset, SVD, accuracy
from surprise.model_selection import cross_validate
from surprise.model_selection import train_test_split
# 데이터 변환
reader = Reader()
data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)
# 훈련 및 테스트 데이터 분리
trainset, testset = train_test_split(data, test_size=.25, random_state=0)
# SVD 모형 학습
algo = SVD()
algo.fit(trainset)
<surprise.prediction_algorithms.matrix_factorization.SVD at 0x7f0d4ae07d68>
# 모형 테스트
predictions = algo.test(testset)
print('prediction tpe:', type(predictions), ' size:', len(predictions))
print('prediction 결과의 최초 5개 추출')
predictions[:5]
prediction tpe: <class 'list'> size: 25001
prediction 결과의 최초 5개 추출
[Prediction(uid=30, iid=254, r_ui=3.0, est=3.6828864855270904, details={'was_impossible': False}),
Prediction(uid=652, iid=2626, r_ui=5.0, est=4.362735526468264, details={'was_impossible': False}),
Prediction(uid=466, iid=2174, r_ui=3.0, est=3.5455084961831242, details={'was_impossible': False}),
Prediction(uid=561, iid=3438, r_ui=4.5, est=3.2762003911403488, details={'was_impossible': False}),
Prediction(uid=529, iid=34552, r_ui=4.0, est=3.3783094948422194, details={'was_impossible': False})]
uid
는 사용자의 아이디iid
는 영화(또는 아이템) 아이다r_ui
는 실제 평점 정보est
는 예측 평점
(3) 예측
predict()
함수를 활용하여 추천 평점 예측을 해본다.
uid = str(194)
iid = str(302)
pred = algo.predict(uid, iid)
print(pred)
user: 194 item: 302 r_ui = None est = 3.54 {'was_impossible': False}
svd.predict(1, 302, 3)
Prediction(uid=1, iid=302, r_ui=3, est=2.8156662920105133, details={'was_impossible': False})
(4) 모형 평가
Surprise
의Accuracy
모듈은RMSE
,MSE
등의 방법으로 추천 시스템의 성능 평가 제공함
accuracy.rmse(predictions)
RMSE: 0.8910
0.8909960969933768
V. Conclusion
- 이론은 다소 복잡할 지 모르지만, 구현하는 것은 생각보다 어려운 것은 아니다.
- 각 함수에 맞춰서 데이터셋만 맞춰주면 된다. (물론 이게 어렵다)
- 개별 알고리즘에 대한 이론 공부는 병행해야 하지만,
Manual
에 사실 설명서가 다 있기 때문에, 크게 걱정을 하지 않았으면 좋겠다. - 아직 끝이 아니다. 여기서 추가적으로 진행하지 못한 부분은
metadata
와 합친 것은 아니기 때문이다. 이러한 부분은 추후에 전체 리뷰 시 다시 기술하겠다.- 별도의 함수를 만들어야 하는 작업이 있는데, 이에 대한 추가 설명이 필요하다. (
Comming Soon
)
- 별도의 함수를 만들어야 하는 작업이 있는데, 이에 대한 추가 설명이 필요하다. (
VI. Reference
Ibtesama. (2020, May 16). Getting Started with a Movie Recommendation System. Retrieved June 21, 2020, from https://www.kaggle.com/ibtesama/getting-started-with-a-movie-recommendation-system