[ML] 추천시스템 평가 데이터 구성 방법: Leave-One-Out, Negative Sampling 실전 가이드
이번 포스팅에서는 추천시스템의 평가를 위해서 어떤 전략을 사용해서 학습 데이터와 평가 데이터를 나누는지에 대해서 설명해보고자 한다.
그중에서도 암묵적 피드백으로 이루어진 데이터와 모델을 활용할 때 자주 사용하는 Leave-one-out과 Negative sampling 방법에 대해서 알아보고자 한다.
이를 설명하기 위해서 필수적인 개념들을 한번 더 정리하고, 본격적인 이야기들을 순서대로 설명해보고자 한다.
1. 명시적 피드백 (Explicit Feedback)과 암묵적 피드백 (Implicit Feedback) 이란?
추천시스템에서는 사용자의 선호도를 측정하기 위한 피드백 정보를 사용한다.
그 종류에는 크게 두 가지가 존재하는데, 명시적 피드백 (Explicit Feedback), 암묵적 (Implicit Feedback)이 있다.
명시적 피드백 : 사용자가 명확하게 선호도를 표현한 것으로 예를 들자면 평점, 리뷰, 찜하기 등이 있다.
(추천시스템의 기본을 공부하면 다들 잘 알고 있는 예제처럼 영화가 있고, 해당 영화에 대한 평점 데이터를 생각하면 될 것 같다.)
암묵적인 피드백 : 사용자의 행동을 간접적으로 관찰한 것으로 아이템 클릭, 조회수, 구매 여부, 체류 시간 등이 있다.
2. Negative sampling
사실상 대부분 우리가 가지고 있는 데이터는 사용자들의 암묵적인 피드백인 경우가 많다.
만약, 명시적인 피드백 중 하나인 평점 데이터 자체를 추천시스템에 활용한다고 하면, 1~5점이라는 '정답'이 존재한다.
즉, 이러한 데이터를 활용하면 모델이 회귀 문제 또는 다중 클래스 분류 문제처럼 학습이 쉽게 가능하다는 것이다.
하지만, 암묵적 피드백은 positive만 있고 negative 없다. (positive, negative는 긍, 부정이라고 단순히 생각하면 된다.)
다시 말해서 특정 아이템을 조회하지 않았다고 했을 때, 몰라서 못본건지, 싫어서 안 본 건지 명확히 알 수가 없다.
하지만, 우리는 학습을 진행할 때, 어느정도 negative 한 sample들도 함께 학습이 진행이 되어야 한다.
즉, 모델이 positive 예시만 학습하면 해당 사용자가 뭘 좋아하는지는 알 수 있어도 뭘 싫어하는지는 알 수가 없다.
따라서, 특정 사용자가 "이건 안 좋아할 수도 있겠구나"라는 판단을 학습할 수 있어야 한다.
그렇기 때문에 이러한 negative한 sample을 인위적으로 만들어야 한다.
이러한 방법을 Negative sampling이라고 한다.
3. Leave-one-out (LOO)
그렇다면 이제 negative sampling이 뭔지 알았으니, 어떻게 만들 수 있을지에 대해서 한번 알아보자.
일반적으로 우리가 머신러닝 모델을 개발한 후 평가를 진행할 때는 train-test split을 진행하게 된다.
그런데, 추천시스템의 경우 일반적으로 사용하는 랜덤 train-test-split을 잘 활용하지 않는다.
그 이유는 추천은 본질적으로 랭킹 예측 문제이다.
따라서 모델에 대한 평가를 진행할 때, 추천된 아이템이 사용자가 실제로 본 혹은 구매한 아이템이 예측 순위에서 얼마나 높은 지를 평가하기 때문이다.
그렇다면, 어떤 방법으로 train-test set을 split 하나?
그 방법이 Leave-one-out 방법이다.
Leave-one-out : 유저가 가장 최근에 상호작용한 아이템 (latest interaction)을 test set으로 하고, 나머지 데이터를 train set으로 활용하는 방법
평가 데이터 구성
test data set : 각 사용자에 대해 가장 최근에 상호작용한 1개의 아이템 (Ground Truth)
train data set : 그 나머지 positive 데이터
그런데, 여기서 다시 negative sample에 대해서 생각을 해줘야 한다.
각 사용자들의 positive한 아이템들만 존재하고 있기 때문에, 랜덤 하게 각 사용자들이 조회하지 않았던 아이템들을 무작위로 선택해서 train set에 넣어주는 것이다.
정리하자면, train data에는 사용자들의 positive, negative sample이 동시에 들어가 있고, test data에는 사용자들이 가장 최근에 조회한 아이템 1개가 있는 셈이다.
이렇게 만들게 되면 정답이 없는 암묵적 피드백에서도 마치 이진 분류처럼 학습할 수 있는 환경을 구성할 수 있다.
그렇다면, 여기서 negative smapling은 어느 정도로 해야하는지에 대한 의문이 생길 수 있다.
이 positive와 negative sample에 대한 비율은 성능과 효율을 모두 고려해야 하기 때문에 꽤 중요한 하이퍼파라미터가 될 수 있다. 그에 대한 일반적인 기준과 선택 전략은 다음과 같다.
일반적으로 학습 데이터에서 positive : negative = 1:4 ~ 1:5 비율이 가장 흔하게 사용이 된다.
즉, positive 1개당 negative를 4-5개 구성한다고 생각하면 된다.
실제로 ncf 논문에서도 이 비율을 활용해서 모델에 대한 실험을 진행했다.
추가적으로 실제 추천서비스에서는 유저별로 가장 가능성이 높은 아이템을 추리는 것이 중요하기 때문에 무작위 sampling 보다는 popularity-based 또는 hard negative sampling 전략을 쓴다고 한다.
Popularity-based sampling : 아이템의 인기도를 기준으로 negative 샘플을 정하는 방식
일반적인 무작위 샘플링에서는 너무 생소하거나 인기도 낮은 아이템이 샘플링될 수 있다.
하지만 실제로 인기도 높은 아이템 중에서 유저가 보지 않은 것을 negative로 보는 게 조금 더 현실적일 수 있다.
다만, 너무 인기 있는 것만 샘플링하면 모델이 쉽게 확습되어 일반화가 떨어지고, 모든 유저에게 비슷한 아이템을 추천하는 편향적인 모델이 될 수도 있다.
Hard Negative sampling : 모델이 구분하기 어려운 negative sample을 우선적으로 선택하는 전략
예를 들어, 사용자의 관심과 비슷하지만 아직 클릭하지 않은 아이템들을 선택하는 것
즉, 헷갈릴 만한 아이템을 일부러 negatvie로 넣어서 모델을 더 정교하게 학습을 시키는 것을 말한다.
이는 특히, BRP, NCF, DeepFM과 같은 모델에서 효과가 크다.
하지만, 모델이 학습 초기에 과적합될 위험도 있다.
4. 대표적인 평가 지표
자 어쨋든, 이렇게 해서 모델을 학습할 데이터 셋과 평가할 데이터셋을 만들어 냈다.
그렇다면 실제로 어떻게 평가를 진행하는지 그 평가 지표로 어떤 것을 주로 사용하는지에 대해서 살펴보자.
이렇게 leave-one-out과 negative sampling을 활용할 때, 주로 사용하는 평가 지표는 다음과 같다.
Hit Rate@K (Hit@K)
- 사용자마다 1개의 정답 아이템(positive)이 있고, 모델이 top-K 추천 중에 그게 들어있으면 hit
- 전체 유저 중 hit된 비율을 계산
- 추천 리스트에 정답이 들어있기만 해도 성공으로 보는 단순하고 직관적인 지표
NDCG@K (Normalized Discounted Cumulative Gain)
- Hit@K와 비슷하지만, 정답 아이템의 순위에 따라 가중치를 다르게 줌.
- 예: 정답이 1등에 있을수록 높은 점수
- 단순히 정답이 top-K에 있느냐뿐 아니라, 얼마나 앞에 있는지를 평가할 수 있음
MRR (Mean Reciprocal Rank)
- 추천 리스트에서 정답 아이템이 등장한 첫 번째 위치의 역수로 평가.
- 여러 개의 추천 중 정답이 빠르게 등장할수록 높은 점수를 부여.
- 사용자에게 얼마나 빨리 원하는 결과를 주었는가 평가할 때 적합.
왜 Negative Sampling이 필요하고, 이런 지표들과 맞는가?
- 암묵적 피드백에는 1 (interacted)과 0 (not interacted)만 존재.
- 하지만 실제 0은 "싫어서 안 본 게 아니라, 그냥 안 본 것"일 수 있음.
- 그래서 평가 시 test셋에 있는 정답 외에는 negative 샘플 몇 개만 넣고, 그 중에서 모델이 정답을 얼마나 잘 순위 높게 추천했는지를 평가
이렇게 해서 추천시스템에서 특히, 암묵적 피드백을 활용한 모델을 구현할 때 어떤 식으로 데이터 셋을 구성하는지에 대한 전략에 대해서 알아보았다.
추가적으로,
나의 경우에는 조회수 데이터를 가지고 추천시스템을 구현하고 있었는데, 다음과 같은 코드를 통해서 negative sampling을 진행했고, 실제 데이터와 합쳐준 과정을 담았다.
users = merge_data['user_uid'].unique()
negative_samples = []
total_items = set(list(product_info['item_uid'].unique()))
for user in users:
seen_items = set(merge_data[merge_data['user_uid']==user]['item_uid'])
candidate_items = list(total_items - seen_items)
pos_count = len(seen_items)
neg_count = pos_count*5
if len(candidate_items) < neg_count:
neg_count = len(candidate_items)
negative_items = np.random.choice(candidate_items, size=neg_count, replace=False)
for neg_item in negative_items:
negative_samples.append([user, neg_item, 0])
negative_df = pd.DataFrame(negative_samples, columns=['user_uid', 'item_uid', 'item_view_cnt'])
negative_df['user_uid'] = negative_df['user_uid'].astype(int) # str
negative_df['item_uid'] = negative_df['item_uid'].astype(int) # str
negative_user_merge_df = pd.merge(negative_df, user_info, on='user_uid')
negative_all_merge_df = pd.merge(negative_user_merge_df, product_info, on='item_uid')
오늘도 도움이 되셨다면 좋겠습니다.
감사합니댱
참고 : https://data-scient2st.tistory.com/210
Implicit feedback 추천 모델 평가 방법 이해 (negative sampling, nDCG, HR)
이 글은 NCF 논문을 리뷰하며, implicit feedback 환경에서 item recommendation의 일반적인 평가 방법에 대해 알게 된 내용을 예제를 통해 풀어 재해석한 내용이다. NCF 논문의 4.1 Experimental Settings - Evaluation P
data-scient2st.tistory.com