추천 시스템의 평가 지표
Offline Test
Offline Test란
- 새로운 추천 모델을 검증하기 위해 가장 우선적으로 수행되는 단계이다.
- 유저로부터 수집한 데이터를 train/valid/test로 나누어 모델의 성능을 객관적인 지표로 평가한다.
- 이에 사용되는 성능 지표는 랭킹 문제와 예측 문제에 따라 다르게 사용될 수 있다.
- 랭킹 문제 : Precision@K, Recall@K, MAP@K, NDCG@K, HitRate
- 예측 문제 : RMSE, MAE
Precision/Recall @K
Pricision@K
- 유저에게 추천한 K개의 아이템 중 실제 유저가 관심 있는 아이템의 비율이다.
- 5개의 아이템을 유저에게 추천했을 때 5개의 아이템 중 유저가 관심있는 아이템이 2개라면 precision@5=2/5로 계산할 수 있다.
Recall@K
- 유저가 관심있는 아이템 중 유저에게 추천한 아이템의 비율이다.
- 마찬가지로 5개의 아이템을 유저에게 추천했고, 유저가 관심 있는 아이템이 3개 있을 때 그 중 유저에게 추천한 아이템이 2개라면 recall@5=2/3으로 계산할 수 있다.
🧑💻 code
def get_precision(relevant, recommend):
_intersection = set(recommend).intersection(set(relevant))
return len(_intersection) / len(recommend)
def get_recall(relevant, recommend):
_intersection = set(recommend).intersection(set(relevant))
return len(_intersection) / len(relevant)
Mean Average Precision(MAP)@K
AP@K
- Precision@1부터 Precision@K까지의 평균값을 의미한다.
- 관련 아이템을 더 높은 순위에 추천할 수록 AP@K 점수가 높아지는 특징이 있다.
AP@K=m1∑i=1KPrecision@i
MAP@K
- 모든 유저에 대한 Average Precision 값을 평균해준 값이다.
MAP@K=∣U∣1∑u=1∣U∣(AP@K)u
🧑💻 코드
def get_average_precision(relevant, recommend):
_precisions = []
for i in range(len(recommend)):
_recommend = recommend[:i+1]
_precisions.append(get_precision(relevant, _recommend))
return np.mean(_precisions)
Nomalized Discounted Cumulative Gain(NDCG)
NDCG란
- 검색(Information Retrieval)에서 등장한 지표로, 추천 시스템에 가장 많이 사용되는 지표 중 하나이다.
- Precision@K, MAP@K와 마찬가지로 Top K 리스트를 만들고 유저가 선호하는 아이템을 이용해 값을 구하는 방식이며, MAP@K와 마찬가지로 추천 순서에 가중치를 더 많이 두어 평가한다.
- 값이 1에 가까울 수록 좋다.
- Cumulative Gain
-
상위 K개 아이템에 대하여 관련도를 단순히 합한 것이다.
-
CGk=∑i=1Kreli
cg_lst = [1 if item in relevant_item else 0 for item in recommentd_item]
cg = np.sum(cg_lst)
- Discounted Cumulative Gain
-
순서에 따라 Cumulative Gain을 Discount한 것이다.
-
DCGK=∑i=1Klog2(i+1)reli
-
나중에 추천될 수록 로그 항의 값이 커져 전체 값이 Discount된다.
dcg_lst = np.divide(cg_lst, np.log2(np.arange(k) + 2))
dcg = np.sum(dcg_lst)
- Ideal DCG
-
이상적인 추천이 일어났을 때의 DCG 값이다. 사용자가 어떤 아이템을 선호하는지 모두 알고있다고 가정해야 알 수 있는 값이며, 당연히 가능한 DCG 값 중에 가장 큰 값이다.
-
IDCG=∑i=1Klog2(i+1)reliopt
k_for_icg = min(k, len(relevant_item))
icg = np.zeros(k)
for i in range(k_for_icg):
icg[i] += 1
idcg = np.sum(np.divide(icg, np.log2(np.arange(k) + 2))
- Normalized DCG