코드 원본 및 참고 자료

0. 들어가기 전에 알아야될 용어

  • Matrix factorization
    • 기본적으로 행렬인수 분해 알고리즘은 더 낮은 차원으로 사용자 및 항목 속성을 나타내는 잠재 요인을 찾으려고 함
    • 학습 결과는 가능한 관찰된 등급에 가깝게 분해 결과를 수렴하도록 개발
    • 또한 오버피팅 문제를 피하기 위해 학습 과정을 정규화. 예를 들어, 이러한 행렬 인수 분해 알고리즘의 기본 형태는 다음과 같음

1. SAR Single Node on MovieLens (Python, CPU)


  • 노트북 예제에서는 Python 단일 노드 구현을 사용하여 Smart Adaptive Recommendations (SAR) 알고리즘의 각 단계를 수행합니다.
  • SAR은 사용자 트랜잭션 기록을 기반에 개인화된 추천시스템을 위한 빠르고 확장 가능한 적응형 알고리즘입니다. 아이템 간의 유사성을 이해하고 사용자가 기존 친화력을 가진 아이템과 유사한 아이템을 추천함으로써 강화됩니다.

2. SAR algorithm


  • 다음 그림은 SAR의 상위 레벨 아키텍처를 나타냅니다. 높은 수준에서 두 개의 중간 행렬이 만들어지고 추천점수 집합을 생성하는 데 사용됩니다.
  • 항목 유사성 행렬 S은 항목 - 항목 관계를 추정합니다. 친화 행렬 A는 사용자 - 항목 관계를 추정합니다.
  • 추천 점수는 행렬 곱셈 A X S를 계산하여 생성됩니다.
  • 선택 단계 (예 : ‘time decay’ 및 ‘remove seen items’)는 아래에 자세히 설명되어 있습니다.

2.1 Compute item co-occurrence and item similarity


  • SAR은 항목 대 항목 동시 발생 (co-occurrence) 데이터를 기반으로 유사성을 정의합니다. 동시 발생 (co-occurrence)은 주어진 사용자에 대해 두 항목이 함께 나타나는 횟수로 정의됩니다.
  • 모든 항목의 동시 발생을 m X m matrix C로 나타낼 수 있습니다. c_i, j는 항목 i이 항목 j 및 m는 총 항목 수입니다.
  • co-occurence matric C에는 다음과 같은 속성이 있습니다.
  1. It is symmetric
  2. It is nonnegative
  3. The occurrences are at least as large as the co-occurrences. I.e., the largest element for each row (and column) is on the main diagonal: (발생은 적어도 동시 발생만큼 큽니다. 즉, 각 행 (및 열)에 대한 가장 큰 요소는 주 대각선)
  • co-occurrence 행렬이 생기면 주어진 유사도에 따라 co-occurrence을 재조정하여 항목 유사도 행렬 S를 얻을 수 있습니다. 메트릭에 대한 옵션에는 Jaccard,liftcounts (재조정 없음)가 포함됩니다.

  • Jaccard:

  • lift:

  • counts:

  • 일반적으로 ‘카운트’를 유사성 측정 항목으로 사용하면 예측 가능성이 좋아지므로 가장 인기있는 항목이 대부분 추천될 것입니다.
  • 대조적으로 ‘리프트’는 검색 가능성 / 검색 가능성을 선호합니다. 전반적으로 인기는 적지만 소량의 사용자가 선호하는 항목은 추천할 가능성이 큽니다. ‘자카드 (Jaccard)’는 둘 사이의 절충안이다.

2.2 Compute user affinity scores


  • SAR의 affinity 행렬은 각 개별 사용자와 사용자가 이미 상호 작용한 항목 간의 관계의 강도를 포착합니다. SAR은 사용자의 친화력에 영향을 줄 수 있는 두 가지 요소를 통합합니다.

  • 다른 이벤트의 다른 가중치 부여를 통해 사용자-항목 상호 작용의 유형 에 대한 정보를 고려할 수 있습니다
    • (예 : 사용자가 항목을 본 이벤트보다 사용자가 특정 항목을 더 많이 평가한 이벤트의 무게를 측정할 수 있음)
  • 사용자-항목 이벤트가 발생한 에 대한 정보를 고려할 수 있습니다 (예 : 먼 과거에 발생한 이벤트의 가치를 할인 할 수 있음)
  • 이러한 요소를 공식화 하면 사용자 항목 유사성에 대한 표현이 생깁니다.
  • 사용자 i와 항목 j에 대한 친화력 는 사용자 i와 항목 j가 관련된 모든 k 이벤트의 가중 합계입니다.
  • w_k는 특정 이벤트의 가중치를 나타내며 2항의 거듭 제곱은 일시적으로 할인된 이벤트를 반영합니다. t단위가 반감기로 작용하게 됩니다. t_0보다 먼저 T 단위가 t_0보다 먼저 발생하게 됩니다.
  • 모든 n 사용자 및 m 항목에 대해 이 계산을 반복하면 n X m matrix A 가 됩니다.
  • 위의 식의 단순화는 모든 가중치를 1(이벤트 유형을 효과적으로 무시)과 같게 설정하거나 반감기 매개변수 T를 무한대 (트랜잭션 시간 무시)로 설정하여 얻을 수 있습니다.

2.3 Remove seen item


  • 선택에 따라 이미 훈련 세트에 표시된 항목을 삭제합니다. 즉, 이전에 사용자가 구매한 항목을 다시 추천하지 않는 것입니다.

2.4 Top-k item calculation


  • 다음 선호도 행렬 A에 유사도 행렬 S을 곱하여 사용자 집합에 대한 맞춤형 추천을 얻을 수 있습니다. 결과는 추천점수 매트릭스입니다.
  • 각 행은 사용자에 해당하고 각 열은 항목에 해당하며 각 항목은 사용자 / 항목 쌍에 해당합니다. 높은 점수는 더 강하게 추천되는 항목에 해당합니다.
  • 추천 작업의 복잡성은 데이터 크기에 따라 다릅니다. SAR 알고리즘 자체는 복잡합니다.
  • 따라서 단일 노드 구현은 대규모 데이터 세트를 확장 가능한 방식으로 처리하지 않아야 합니다. 알고리즘을 사용할 때마다 충분히 큰 메모리로 실행하는 것이 좋습니다.

3. SAR single-node implementation


  • 이 노트북에 설명 된 SAR 구현은 파이썬에서 주로 numpy, pandas 및 scipy와 같은 Python 패키지로 개발되었으며 대부분 데이터 분석 / 기계학습 작업에서 사용됩니다. 구현 세부 정보는 아래에서 찾을 수 있습니다.

  • Recommenders/reco_utils/recommender/sar/sar_singlenode.py

3.1 SAR single-node based movie recommender


# set the environment path to find Recommenders
import sys
sys.path.append("../../")

import itertools
import logging
import os

import numpy as np
import pandas as pd
import papermill as pm

from reco_utils.dataset import movielens
from reco_utils.dataset.python_splitters import python_random_split
from reco_utils.evaluation.python_evaluation import map_at_k, ndcg_at_k, precision_at_k, recall_at_k
from reco_utils.recommender.sar.sar_singlenode import SARSingleNode

print("System version: {}".format(sys.version))
print("Pandas version: {}".format(pd.__version__))
System version: 3.5.2 (default, Nov 12 2018, 13:43:14) 
[GCC 5.4.0 20160609]
Pandas version: 0.23.4
# top k items to recommend
TOP_K = 10

# Select Movielens data size: 100k, 1m, 10m, or 20m
MOVIELENS_DATA_SIZE = '20m'

3.2 Load Data


  • SAR은 다음 스키마와의 상호 작용에 사용하기 위한 것입니다. <사용자 ID>, <아이템 ID>, <시간>

  • 각 행은 사용자와 항목간의 단일 상호 작용을 나타냅니다. 상호 작용은 전자상거래 웹사이트에서 사용자가 항목을 클릭하여 보고 장바구니에 추가하거나 추천 링크를 따라 클릭하는 등 다양한 유형의 이벤트일 수 있습니다.
  • MovieLens 데이터 세트는 영화에 등급을 제공하는 사용자의 형식이 잘 지정된 상호 작용입니다 (영화 등급은 이벤트 가중치로 사용됩니다). 나머지 예제에서는 이 등급을 사용합니다.
data = movielens.load_pandas_df(
    size=MOVIELENS_DATA_SIZE,
    header=['UserId', 'MovieId', 'Rating', 'Timestamp'],
    title_col='Title'
)

# Convert the float precision to 32-bit in order to reduce memory consumption 
data.loc[:, 'Rating'] = data['Rating'].astype(np.float64)

data.head()
UserId MovieId Rating Timestamp Title
0 1 2 3.5 1112486027 Jumanji (1995)
1 5 2 3.0 851527569 Jumanji (1995)
2 13 2 3.0 849082742 Jumanji (1995)
3 29 2 3.0 835562174 Jumanji (1995)
4 34 2 3.0 846509384 Jumanji (1995)
data.shape()

3.3 Split the data using the python random splitter provided in utilities:


We utilize the provided python_random_split function to split into train and test datasets randomly at a 75/25 ratio.

train, test = python_random_split(data, 0.75)
header = {
    "col_user": "UserId",
    "col_item": "MovieId",
    "col_rating": "Rating",
    "col_timestamp": "Timestamp",
    "col_prediction": "Prediction",
}

In this case, for the illustration purpose, the following parameter values are used:

Parameter Value Description
similarity_type jaccard Method used to calculate item similarity.
time_decay_coefficient 30 Period in days (term of $T$ shown in the formula of Section 2.2.2)
time_now None Time decay reference.
timedecay_formula True Whether time decay formula is used.
# set log level to INFO
logging.basicConfig(level=logging.DEBUG, 
                    format='%(asctime)s %(levelname)-8s %(message)s')

model = SARSingleNode(
    similarity_type="jaccard", 
    time_decay_coefficient=30, 
    time_now=None, 
    timedecay_formula=True, 
    **header
)
30 * 24 * 60 * 60
2592000
model.fit(train)
2019-05-16 07:02:37,345 INFO     Collecting user affinity matrix
2019-05-16 07:02:37,347 INFO     Calculating time-decayed affinities
2019-05-16 07:02:37,372 INFO     Creating index columns
2019-05-16 07:02:37,381 INFO     Building user affinity sparse matrix
2019-05-16 07:02:37,385 INFO     Calculating item co-occurrence
2019-05-16 07:02:37,518 INFO     Calculating item similarity
2019-05-16 07:02:37,519 INFO     Calculating jaccard
2019-05-16 07:02:37,574 INFO     Done training
top_k = model.recommend_k_items(test, remove_seen=True)
2019-05-16 07:08:35,951 INFO     Calculating recommendation scores
2019-05-16 07:08:36,020 INFO     Removing seen items
2019-05-16 07:08:36,025 INFO     Getting top K
top_k.shape
(9430, 3)

The final output from the recommend_k_items method generates recommendation scores for each user-item pair, which are shown as follows.

top_k_with_titles = (top_k.join(data[['MovieId', 'Title']].drop_duplicates().set_index('MovieId'), 
                                on='MovieId', 
                                how='inner').sort_values(by=['UserId', 'Prediction'], ascending=False))
display(top_k_with_titles.head(10))
MovieId Prediction UserId Title
4678 385 22.063621 943 True Lies (1994)
4674 79 20.945250 943 Fugitive, The (1993)
4675 69 20.665495 943 Forrest Gump (1994)
4671 82 20.615830 943 Jurassic Park (1993)
4676 202 20.333979 943 Groundhog Day (1993)
4672 550 20.223571 943 Die Hard: With a Vengeance (1995)
4677 265 20.060790 943 Hunt for Red October, The (1990)
4679 183 19.947005 943 Alien (1979)
4673 403 19.897582 943 Batman (1989)
4670 168 19.895860 943 Monty Python and the Holy Grail (1974)
data[['MovieId', 'Title']].drop_duplicates()
MovieId Title
0 242 Kolya (1996)
117 302 L.A. Confidential (1997)
414 377 Heavyweights (1994)
... ... ...
99996 1640 Eighth Day, The (1996)
99997 1637 Girls Town (1996)
99998 1630 Silence of the Palace, The (Saimt el Qusur) (1...
99999 1641 Dadetown (1995)

1682 rows × 2 columns

3.4 Evaluate the results


  • 항목 유사도 행렬 S와 사용자 선호도 행렬 A가 행렬 곱으로생성된 추천 점수는 movielens 데이터 세트의 원래 명시적 등급과 동일한 축을 가져야 합니다.
  • 즉, SAR 알고리즘은 사용자 - 항목 쌍에 대한 명시적 등급을 “예측하는 것”이 아니라 관련되는 항목을 사용자에게 “추천하는 작업”을 의미합니다.
  • RMSE와 같은 평가 지표보다 precision@k, recall@k 등과 같은 순위측정 기준은 SAR 알고리즘을 평가하는 데 더 적합합니다.
  • 다음은reco_utils에 제공된 평가 함수를 사용하여 SAR 모델을 평가하는 방법을 보여줍니다.
# all ranking metrics have the same arguments
args = [test, top_k]
kwargs = dict(col_user='UserId', 
              col_item='MovieId', 
              col_rating='Rating', 
              col_prediction='Prediction', 
              relevancy_method='top_k', 
              k=TOP_K)

eval_map = map_at_k(*args, **kwargs)
eval_ndcg = ndcg_at_k(*args, **kwargs)
eval_precision = precision_at_k(*args, **kwargs)
eval_recall = recall_at_k(*args, **kwargs)
test.shape
(25000, 5)
test.head()
UserId MovieId Rating Timestamp Title
75721 498 693 3.0 881957625 Casino (1995)
80184 642 542 5.0 885606609 Pocahontas (1995)
19864 58 135 4.0 884305150 2001: A Space Odyssey (1968)
76699 495 674 3.0 888635995 Cat People (1982)
92991 618 735 3.0 891308571 Philadelphia (1993)
top_k.shape
(9430, 3)
top_k.head()
MovieId Prediction UserId
0 69 3.160962 498
1 196 3.170867 498
2 132 3.176901 498
3 234 3.185214 498
4 96 3.193433 498
print({model.model_str},{TOP_K},{eval_map},{eval_ndcg},{eval_precision},{eval_recall}, sep='\n')
{'sar_ref'}
{10}
{0.10350057001415401}
{0.3681048446660098}
{0.3176033934252386}
{0.16970898480940927}

댓글남기기