最近在做一些推荐系统方面的研究工作,对于推荐系统的评价指标总是搞得很乱,现在正好用博客整理下,免得每次都要上网查
目录
1.Rating Prediction
对于rating prediction任务,一般都是根据原有的评分数据,利用矩阵分解等方法去拟合原评分,使得优化后的模型可以去预测新的评分,这里就要衡量你预测的评分和实际评分的差异了,指标也很简单,分为RMSE和MAE。
(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=∣T∣1(u,i)∈T∑(r^ui−rui)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=∣T∣1(u,i)∈T∑(r^ui−rui)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=∣Recu∣∣Relu∩Recu∣
其中
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=∣Relu∣∣Relu∩Recu∣
其中
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=∣Ute∣∑u∈U∗eAPu
首先需要计算每个用户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=∣Iute∣1i∈Iute∑rankui∑j∈Iutuδ(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=i在测试集中的排名∑i∈I∗ui在推荐列表中的排名其中
I
∗
u
I^{* u}
I∗u是用户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=∣U∣1u=1∑∣U∣APu还是不理解?上代码:
#这个只是计算每个用户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=∣Q∣1i=1∑∣U∣ranki1
其中
∣
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=1∑kreli
其中,
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=1∑klog2(i+1)2reli−1,推荐系统中,命中则 2 r e l i − 1 2^{r e l_{i}}-1 2reli−1为1,不命中则 2 r e l i − 1 2^{r e l_{i}}-1 2reli−1为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=1∑klog2(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=∣Ute∣∑u∈UteNDCGu@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=1∑nlog2(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=∣Ute∣∑u∈UteNDCGu@k
其中,
U
t
e
U^{te}
Ute为测试集中的所有用户。
好了总结完毕~
最后不得不感谢Mathpix Snipping Tool这个工具太好用了,全文的LaTeX公式都是用它做的,想了解的自己去百度搜索,你会发现新天地的。