추천 시스템 개요 및 이론, 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