推荐系统常用评价指标


最近在做一些推荐系统方面的研究工作,对于推荐系统的评价指标总是搞得很乱,现在正好用博客整理下,免得每次都要上网查

目录

  • Rating Prediction
    • RMSE
    • MAE
  • Ranking Prediction
    • Precision@K
    • Recall@K
    • MAP(Mean Average Precision)
    • MRR(Mean Reciprocal Rank)
    • NDCG@K
    • NDCG

1.Rating Prediction

对于rating prediction任务,一般都是根据原有的评分数据,利用矩阵分解等方法去拟合原评分,使得优化后的模型可以去预测新的评分,这里就要衡量你预测的评分和实际评分的差异了,指标也很简单,分为RMSEMAE

(1)RMSE

RMSE ⁡ = 1 ∣ T ∣ ∑ ( u , i ) ∈ T ( r ^ u i − r u i ) 2 \operatorname{RMSE}=\sqrt{\frac{1}{|\mathcal{T}|} \sum_{(u, i) \in \mathcal{T}}\left(\hat{r}_{u i}-r_{u i}\right)^{2}} RMSE=T1(u,i)T(r^uirui)2
其中 T \mathcal{T} T是测试集, r ^ u i \hat{r}_{u i} r^ui是模型预测出来的评分, r u i {r}_{u i} rui是测试集的实际评分。

(2)MAE

$$\mathrm{MAE}=\frac{1}{|\mathcal{T}|} \sum_{(u, i) \in \mathcal{T}}\left|\hat{r}_{u i}-r_{u i}\right|$$

RMSE ⁡ = 1 ∣ T ∣ ∑ ( u , i ) ∈ T ( r ^ u i − r u i ) 2 \operatorname{RMSE}=\sqrt{\frac{1}{|\mathcal{T}|} \sum_{(u, i) \in \mathcal{T}}\left(\hat{r}_{u i}-r_{u i}\right)^{2}} RMSE=T1(u,i)T(r^uirui)2
其中 T \mathcal{T} T是测试集, r ^ u i \hat{r}_{u i} r^ui是模型预测出来的评分, r u i {r}_{u i} rui是测试集的实际评分。

RMSE和MAE实际上差别不大的指标,在Rating任务中比较常用

2.Ranking Prediction

对于Ranking prediction任务,一般是将其化为二分类任务:有评分为1,无评分为0(这是比较粗糙的做法),然后对每个用户取其偏好最高的K个商品(TOP-K)推荐。指标看起来也“复杂”很多,分别有Rrecision@K,Recall@K,MAP,MRR,NDCG

(1)Precision@K

p r e c i s i o n @ K = ∣ R e l u ∩ R e c u ∣ ∣ R e c u ∣ precision@K = \frac{\left|R e l_{u} \cap R e c_{u}\right|}{\left|R e c_{u}\right|} precision@K=RecuReluRecu
其中 R e l u R e l_{u} Relu表示与用户 u u u 相关的商品集(测试集), R e c u R e c_{u} Recu表示推荐给用户的前K个列表,二者的交集除以 R e c u R e c_{u} Recu的集合元素个数(其实就是K),得到Precision@K。一般是算出每个用户的Precision@K,然后取平均值。

#计算每个用户的Precision@K值,最后还要取平均值
    def cal_precision_at_k(k, rankedlist, test_matrix):
	    test_set = set(test_matrix)
	    rank_set = set(rankedlist)
	    hit = len(test_set & rank_set)
	    return float(hit / k)

(2)Recall@K

R e c a l @ K = ∣ R e l u ∩ R e c u ∣ ∣ R e l u ∣ Recal@K = \frac{\left|R e l_{u} \cap R e c_{u}\right|}{\left|R e l_{u}\right|} Recal@K=ReluReluRecu
其中 R e l u R e l_{u} Relu表示与用户u相关的商品集(测试集), R e c u R e c_{u} Recu表示推荐给用户的前K个列表,二者的交集除以 R e l u R e l_{u} Relu中元素的个数(也就是测试集中用户u评过分的商品数),得到Recall@K。一般是算出每个用户的Recall@K,然后取平均值。

#计算每个用户的Recall@K值,最后还要取平均值
def cal_Recall_at_k_for_each_user(k, rankedlist, testlist):
    test_set = set(test_matrix)
    rank_set = set(rankedlist)
    hit = len(test_set & rank_set)
    return float(hit / len(test_set))

(3)MAP(Mean Average Precision,平均准确率)

M A P = ∑ u ∈ U ∗ e A P u ∣ U t e ∣ M A P=\frac{\sum_{u \in U^{* e}} A P_{u}}{\left|\mathcal{U}^{t e}\right|} MAP=UteuUeAPu
首先需要计算每个用户AP(Average Precision)
A P u = 1 ∣ I u t e ∣ ∑ i ∈ I u t e ∑ j ∈ I u t u δ ( r a n k u j < r a n k u i ) + 1 r a n k u i A P_{u}=\frac{1}{\left|\mathcal{I}_{u}^{t e}\right|} \sum_{i \in \mathcal{I}_{u}^{t_{e}}} \frac{\sum_{j \in \mathcal{I}_{u}^{t_{u}}} \delta\left(rank_{u j}<rank_{u i}\right)+1}{rank_{u i}} APu=Iute1iIuterankuijIutuδ(rankuj<rankui)+1
公式看起来有点吓人,其中 r a n k u i rank_{u i} rankui表示推荐列表中物品 i 的排序位置, r a n k u j < r a n k u i rank_{u j}<rank_{u i} rankuj<rankui 表示在对用户 u u u 的排序列表中物品 j j j 的排序位置在物品 i i i 的前面。假设你推荐的TOP-K商品中,有N个命中了(与测试集的交集为N),其实就是 A P u = ∑ i ∈ I ∗ u i 在 推 荐 列 表 中 的 排 名 i 在 测 试 集 中 的 排 名 A P_{u} = \frac{\sum_{i \in I^{* u}} i在推荐列表中的排名}{\mathcal i在测试集中的排名} APu=iiIui其中 I ∗ u I^{* u} Iu是用户u的推荐列表中命中的元素集合。MAP就是所有用户AP的平均值。 M A P = 1 ∣ U ∣ ∑ u = 1 ∣ U ∣ A P u \mathrm{MAP}=\frac{1}{|U|} \sum_{u=1}^{|U|} {AP_u} MAP=U1u=1UAPu还是不理解?上代码:

#这个只是计算每个用户MAP的代码,最后还要对整个取平均值
def cal_map_for_each_user(rankedlist, testlist):
    ap = 0
    s = set(testlist)
    #命中的元素在testlist中的排名
    hits = [ idx for idx, val in enumerate(rankedlist) if val in s ] 
    count = len(hits)
    for i in range(count):
        ap += (i+1) / (hits[i] + 1)
        
    if count != 0:
        map = ap / count
    else:
    	map = 0

    return map

(4)MRR(Mean Reciprocal Rank, 平均倒数排名)

M R R = 1 ∣ Q ∣ ∑ i = 1 ∣ U ∣ 1 rank ⁡ i \mathrm{MRR}=\frac{1}{|Q|} \sum_{i=1}^{|U|} \frac{1}{\operatorname{rank}_{i}} MRR=Q1i=1Uranki1
其中 ∣ U ∣ |U| U是用户的个数, r a n k i rank_i ranki是对于第 i i i个用户,推荐列表中第一个在测试集结果中的商品所在的排列位置,计算起来也十分简单:

#这个也是只是计算每个用户的MRR,最后还要取均值
    if count != 0:
        mrr = 1 / (hits[0] + 1)
    else:
    	mrr = 0

(5) NDCG@K(Normalized Discounted Cummulative Gain@K)

NDCG应该是Ranking指标里面最复杂的了,讲NDCG应该先从CG,DCG讲起

CG@K(Cummulative Gain,累计增益)

C G k = ∑ i = 1 k r e l i C G_{k}=\sum_{i=1}^{k} r e l_{i} CGk=i=1kreli
其中, r e l i rel_i reli 表示处于位置 i i i 的推荐结果的相关性,在推荐系统中是命中 r e l i rel_i reli 为1,不命中 r e l i rel_i reli 为0。 k k k是TOP-K中的K。

DCG@K(Discounted Cummulative Gain)

D C G k = ∑ i = 1 k 2 r e l i − 1 log ⁡ 2 ( i + 1 ) D C G_{k}=\sum_{i=1}^{k} \frac{2^{r e l_{i}}-1}{\log _{2}(i+1)} DCGk=i=1klog2(i+1)2reli1,推荐系统中,命中则 2 r e l i − 1 2^{r e l_{i}}-1 2reli1为1,不命中则 2 r e l i − 1 2^{r e l_{i}}-1 2reli1为0。 D C G DCG DCG引入了位置因素,比 C G CG CG更有价值。

IDCG@K(Ideal DCG)

I D C G k = ∑ i = 1 k 1 log ⁡ 2 ( i + 1 ) I D C G_{k}=\sum_{i=1}^{k} \frac{1}{\log _{2}(i+1)} IDCGk=i=1klog2(i+1)1
k k k是TOP-K中的K。 I D C G IDCG IDCG是理想化的 D C G DCG DCG,因此 D C G DCG DCG的值介于[0, I D C G IDCG IDCG]之间。

    for i in range(k):
        idcg_k += 1 / math.log(i + 2, 2)

NDCG@K (Normalized Discounted Cummulative Gain@K)

N D C G u @ k = D C G u @ k I D C G u N D C G_{u} @ k=\frac{D C G_{u} @ k}{I D C G_{u}} NDCGu@k=IDCGuDCGu@k
终于轮到 N D C G @ K NDCG@K NDCG@K了,它的值就是 D C G DCG DCG I D C G IDCG IDCG之间的比值,介于[0,1]之间。
因此所有用户的平均 N D C G @ K NDCG@K NDCG@K为: N D C G @ k = ∑ u ∈ U t e N D C G u @ k ∣ U t e ∣ N D C G @ k=\frac{\sum_{u \in \mathcal{U}^{te} N D C G_{u} @ k}}{\left|\mathcal{U}^{te}\right|} NDCG@k=UteuUteNDCGu@k
其中, U t e U^{te} Ute为测试集中的所有用户。

#计算每个用户的NDCG@K值,最后还要取平均值
def cal_ndcg_at_k_for_each_user(k, rankedlist, testlist):
    idcg_k = 0
    dcg_k = 0
    if len(testlist) < k: k = len(testlist)
    for i in range(k):
        idcg_k += 1 / math.log(i + 2, 2)
        
    s = set(testlist)
    hits = [ idx for idx, val in enumerate(rankedlist) if val in s]
    count = len(hits)

    for i in range(count):
        dcg_k += 1 / math.log(hits[i] + 2, 2)

    return  float(dcg_k / idcg_k)

(6)NDCG(Normalized Discounted Cummulative Gain)

既然已经介绍了 N D C G @ K NDCG@K NDCG@K,为啥还要单独介绍一个 N D C G NDCG NDCG呢,二者除了一个 @ K @K @K有啥区别?
主要是看有的论文是用 N D C G @ K NDCG@K NDCG@K,有的是用 N D C G NDCG NDCG,因此两个都记下来好了,二者的区别主要是计算 I D C G IDCG IDCG的不同( D C G DCG DCG计算是一样的)

IDCG(Ideal DCG)

I D C G n = ∑ i = 1 n 1 log ⁡ 2 ( i + 1 ) I D C G_{n}=\sum_{i=1}^{n} \frac{1}{\log _{2}(i+1)} IDCGn=i=1nlog2(i+1)1
其中n是用户 u u u的测试集长度,这样一算 I D C G IDCG IDCG变大了。然后 N D C G NDCG NDCG计算是公式一样的:
N D C G = ∑ u ∈ U t e N D C G u @ k ∣ U t e ∣ N D C G =\frac{\sum_{u \in \mathcal{U}^{te} N D C G_{u} @ k}}{\left|\mathcal{U}^{te}\right|} NDCG=UteuUteNDCGu@k
其中, U t e U^{te} Ute为测试集中的所有用户。

好了总结完毕~

最后不得不感谢Mathpix Snipping Tool这个工具太好用了,全文的LaTeX公式都是用它做的,想了解的自己去百度搜索,你会发现新天地的。

你可能感兴趣的:(推荐系统)