Precision@k。适用于 Top-K 推荐任务。
P r e c i s i o n @ K = ∑ i = 1 N ∣ R ( i ) ∩ T ( i ) ∣ ∑ i = 1 N ∣ R ( i ) ∣ (1) Precision@K=\frac{\sum_{i=1}^{N}|R(i)\cap T(i)|}{\sum_{i=1}^{N}|R(i)|}\tag{1} Precision@K=∑i=1N∣R(i)∣∑i=1N∣R(i)∩T(i)∣(1)
N N N 表示用户数, i i i 表示用户 id, R ( i ) R(i) R(i) 表示对用户 i i i 的推荐列表, T ( i ) T(i) T(i) 表示用户 i i i 的真实访问的项目列表。
Recall@k。适用于 Top-K 推荐任务。
R e c a l l @ K = ∑ i = 1 N ∣ R ( i ) ∩ T ( i ) ∣ ∑ i = 1 N ∣ T ( i ) ∣ (2) Recall@K=\frac{\sum_{i=1}^{N}|R(i)\cap T(i)|}{\sum_{i=1}^{N}|T(i)|}\tag{2} Recall@K=∑i=1N∣T(i)∣∑i=1N∣R(i)∩T(i)∣(2)
N N N 表示用户数, i i i 表示用户 id, R ( i ) R(i) R(i) 表示对用户 i i i 的推荐列表, T ( i ) T(i) T(i) 表示用户 i i i 的真实访问的项目列表。
HR(Hit Ratio)@K。适用于 Top-K 推荐任务。
H R @ K = ∑ i = 1 N h r ( i ) N (3) HR@K=\frac{\sum_{i=1}^{N}hr(i)}{N}\tag{3} HR@K=N∑i=1Nhr(i)(3)
h r ( i ) = { 1 , R ( i ) ∩ T ( i ) ≠ ∅ 0 , R ( i ) ∩ T ( i ) = ∅ (4) hr(i)=\left\{\begin{array}{ll} 1 & , R(i) \cap T(i) \neq \varnothing \\ 0 & , R(i) \cap T(i)=\varnothing \end{array}\right.\tag{4} hr(i)={10,R(i)∩T(i)=∅,R(i)∩T(i)=∅(4)
N N N 表示用户数, i i i 表示用户 id, h r ( ⋅ ) hr(\cdot) hr(⋅) 表示命中函数, R ( i ) R(i) R(i) 表示对用户 i i i 的推荐列表, T ( i ) T(i) T(i) 表示用户 i i i 的真实访问的项目列表。
MRR(Mean Reciprocal Rank)@K。适用于 Top-K 推荐任务。
M R R @ K = 1 N ∑ i = 1 N 1 r a n k ( i ) (5) MRR@K=\frac{1}{N}\sum_{i=1}^{N}\frac{1}{rank(i)}\tag{5} MRR@K=N1i=1∑Nrank(i)1(5)
N N N 表示用户数, i i i 表示用户 id, r a n k ( i ) rank(i) rank(i) 表示对用户 i i i 的推荐中,第一个命中的项目在推荐列表中的次序,若没有命中 r a n k ( i ) → ∞ rank(i)\to\infty rank(i)→∞ 。
NDCG(Normalized Discounted Cumulative Gain)@K。适用于 Top-K 推荐任务。
C G @ K = ∑ i = 1 K r e l ( i ) (6) CG@K=\sum_{i=1}^{K}rel(i)\tag{6} CG@K=i=1∑Krel(i)(6)
r e l ( i ) = { 1 , r [ i ] = t [ i ] 0 , r [ i ] ≠ t [ i ] (7) rel(i)=\left\{\begin{array}{ll} 1 & , r[i] = t[i] \\ 0 & , r[i] \neq t[i] \end{array}\right.\tag{7} rel(i)={10,r[i]=t[i],r[i]=t[i](7)
D C G @ K = ∑ i = 1 K 2 r e l ( i ) − 1 l o g 2 ( i + 1 ) (8) DCG@K=\sum_{i=1}^{K}\frac{2^{rel(i)}-1}{log_{2}{(i+1)}}\tag{8} DCG@K=i=1∑Klog2(i+1)2rel(i)−1(8)
I D C G @ K = ∑ i = 1 K 1 l o g 2 ( i + 1 ) (9) IDCG@K=\sum_{i=1}^{K}\frac{1}{log_{2}{(i+1)}}\tag{9} IDCG@K=i=1∑Klog2(i+1)1(9)
N D C G @ K = D C G @ K I D C G @ K (10) NDCG@K=\frac{DCG@K}{IDCG@K}\tag{10} NDCG@K=IDCG@KDCG@K(10)
NDCG@K 的计算对象是任一用户的推荐列表和其真实访问的项目列表。 r e l ( ⋅ ) rel(\cdot) rel(⋅) 表示相关函数,r 表示用户的推荐列表,t 表示用户真实访问的项目列表,IDCG (Idel Discounted Cumulative Gain)。
Python 实现
其中,Precision 是先求分子和分母之后再做除法,Recall 同样也是先计算分子和分母之后再做除法,HR 是求和命中数之后求均值,MRR 是计算排名的倒数和之后求均值,NDCG 是计算每个用户的真实列表和推荐列表的值然后求和再求均值。
def calc_precision_a(t, r):
"""
The numerator of Precision
t represent the true list for a user
r represent the recommendation list for a user
"""
return len([x for x in r if x in t])
def calc_precision_b(t, r):
"""
The denominator of Precision
t represent the true list for a user
r represent the recommendation list for a user
"""
return len(r)
def calc_recall_a(t, r):
"""
The numerator of Precision
t represent the true list for a user
r represent the recommendation list for a user
"""
return len([x for x in r if x in t])
def calc_recall_b(t, r):
"""
The denominator of Precision
t represent the true list for a user
r represent the recommendation list for a user
"""
return len(t)
def calc_hit(t, r):
"""
calc the hit for a user
t represent the true list for a user
r represent the recommendation list for a user
"""
for i in t:
if i in r:
return 1
return 0
def calc_rank_reciprocal(t, r):
for i in r:
if i in t:
return 1 / (t.index(i) + 1)
return 0
def calc_ndcg(t, r):
DCG, IDCG = [], []
for i in range(min(len(t), len(r))):
a = 1 if t[i] == r[i] else 0
b = np.log2(i + 2) # the index in the equation starts from 1, but in code it starts from 0.
DCG.append(a / b)
IDCG.append(1 / b)
return np.sum(DCG) / np.sum(IDCG)
def evaluate(t, r):
return calc_precision_a(t, r), calc_precision_b(t, r), calc_recall_a(t, r), calc_recall_b(t, r), calc_hit(t, r), calc_rank_reciprocal(t, r), calc_ndcg(t, r)
if __name__ == '__main__':
Precision_a, Precision_b, Recall_a, Recall_b, HR, MRR, NDCG = [], [], [], [], [], [], []
for u in range(1, num_users + 1):
r = R[u] # r
t = T[u] # t
precision_a, precision_b, recall_a, recall_b, hr, mrr, ndcg = evaluate.evaluate(t, r)
Precision_a.append(precision_a)
Precision_b.append(precision_b)
Recall_a.append(recall_a)
Recall_b.append(recall_b)
HR.append(hr)
MRR.append(mrr)
NDCG.append(ndcg)
Precision = np.sum(Precision_a) / np.sum(Precision_b)
Recall = np.sum(Recall_a) / np.sum(Recall_b)
HR = np.mean(HR)
MRR = np.mean(MRR)
NDCG = np.mean(NDCG)
print(f'Precision = {Precision}, Recall = {Recall}, HR = {HR}, MRR = {MRR}, NDCG = {NDCG}')