一、CG,累计增益 Cumulative Gain
CG表示对K个item的Gain进行累加,其中Gain表示列表中每一个item的相关性分数,CG即:
二、DCG,折损累计增益 Discounted cumulative gain
DCG提出:如果有效结果在列表中排的较低的话,应该对列表的评分惩罚,惩罚和有效结果的排位有关。所以就加了衰减因子:
还有一个公式广泛在工业界和kaggle比赛中,对应的公式和代码如下:
# 第二种公式的实现
import numpy as np
def dcg_at_n(rel, n):
rel = np.asfarray(rel)[:n]
dcg = np.sum(np.divide(np.power(2, rel) - 1, log2_table[:rel.shape[0]]))
return dcg
注意:当相关性得分是 ,即 时,上面两个公式是等价的。
三、NDCG,归一化折损累计增益 Normalized Discounted Cumulative Gain
3.1 NDCG简介
常用作排序模型的指标评估。DCG没有考虑到推荐列表和每个检索中真正有效结果(test items list) 的个数,所以最后引入NDCG,就是标准化后的DCG。
其中 是指ideal DCG,即理想结果下的DCG,对应的公式为:
简单说:NDCG是由各DCG除以当前DCG中最大的值得到的。 n:Normalization,不同指标大小不同,需要做normalization D:Position discount,位置越靠前影响越大 C:Cumulating, G:Gain,可以使相关性、点击率等指标
3.2 电影推荐的一个栗子
基于打分的个性推荐系统可以用CG(cumulative gain), 累计増益。假设我们推荐 个物品,这个推荐列表的 计算 公式如下:
表示第 个物品的相关性。假设我们共推孝 个电影, 可以是用户对第 部电影的评分。 比如豆篗给用户推荐了五部电影,
该用户对这五部电影的评分分别是 那么这个推荐列表的CG等于
CG没有考虎推荐的次序,在此基础之后我们引入对物品顺序的考虑,就有了DCG(discounted CG), 折扣累积增益。 公式如下:
比如豆蛌给用户推荐了五部电影,
该用户对这五部电影的评分分别是 那么这个推荐列表的DCG等于
3.3 代码实践栗子
这里也贴一个代码的实践例子:
import numpy as np
def ndcg(rel_true, rel_pred, p=None, form="linear"):
""" Returns normalized Discounted Cumulative Gain
Args:
rel_true (1-D Array): relevance lists for particular user, (n_songs,)
rel_pred (1-D Array): predicted relevance lists, (n_pred,)
p (int): particular rank position
form (string): two types of nDCG formula, 'linear' or 'exponential'
Returns:
ndcg (float): normalized discounted cumulative gain score [0, 1]
"""
rel_true = np.sort(rel_true)[::-1]
p = min(len(rel_true), min(len(rel_pred), p))
# 因为索引是从0开始的,正常应该加1,但是从0开始,log(0+1)则等于无穷大,所以这里面加的是2,如果索引是从1开始,则加的是1,所以感觉跟上面的公式不一致,其实是一样的。
discount = 1 / (np.log2(np.arange(p) + 2))
if form == "linear":
idcg = np.sum(rel_true[:p] * discount)
dcg = np.sum(rel_pred[:p] * discount)
elif form == "exponential" or form == "exp":
idcg = np.sum([2 ** x - 1 for x in rel_true[:p]] * discount)
dcg = np.sum([2 ** x - 1 for x in rel_pred[:p]] * discount)
else:
raise ValueError("Only supported for two formula, 'linear' or 'exp'")
return dcg / idcg
if __name__ == "__main__":
song_index = {'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8}
user_lists = ["USER1", "USER2", "USER3"]
relevance_true = {
# 每首歌曲i在每个用户下的评分,并且按降序排序,这个顺序对于相应的用户是最完美的。
"USER1": [3, 3, 2, 2, 1, 1, 0, 0, 0],
"USER2": [3, 2, 1, 1, 2, 0, 1, 1, 1],
"USER3": [0, 1, 0, 1, 2, 3, 3, 1, 0]
}
s1_prediction = {
# 模型预测,用户可能点击的顺序
"USER1": ['A', 'E', 'C', 'D', 'F'],
"USER2": ['G', 'E', 'A', 'B', 'D'],
"USER3": ['C', 'G', 'F', 'B', 'E']
}
s2_prediction = {
"USER1": ['A', 'B', 'C', 'G', 'E'],
"USER2": ['B', 'A', 'G', 'E', 'F'],
"USER3": ['E', 'G', 'F', 'B', 'I']
}
for user in user_lists:
print(f'===={user}===')
r_true = relevance_true[user]
for song in s1_prediction[user]:
test = song_index[song]
test2 = r_true[test]
s1_pred = [r_true[song_index[song]] for song in s1_prediction[user]]
s2_pred = [r_true[song_index[song]] for song in s2_prediction[user]]
print(f'S1 nDCG@5 (linear): {ndcg(r_true, s1_pred, 5, "linear")}')
print(f'S2 nDCG@5 (linear): {ndcg(r_true, s2_pred, 5, "linear")}')
# 一般我们使用下面指数的形式
print(f'S1 nDCG@5 (exponential): {ndcg(r_true, s1_pred, 5, "exp")}')
print(f'S2 nDCG@5 (exponential): {ndcg(r_true, s2_pred, 5, "exp")}')
结果如下,三个用户对应的NDCG指标:
====USER1===
S1 nDCG@5 (linear): 0.8232936061974518
S2 nDCG@5 (linear): 0.8793791209851007
S1 nDCG@5 (exponential): 0.7406319169800546
S2 nDCG@5 (exponential): 0.911476869939315
====USER2===
S1 nDCG@5 (linear): 0.8241067540896558
S2 nDCG@5 (linear): 0.864255024163802
S1 nDCG@5 (exponential): 0.7200216168193889
S2 nDCG@5 (exponential): 0.821434096248145
====USER3===
S1 nDCG@5 (linear): 0.6850898875992608
S2 nDCG@5 (linear): 0.867837452040598
S1 nDCG@5 (exponential): 0.6922758990315323
S2 nDCG@5 (exponential): 0.826208951093206
四、Hit Rate
hr指标在top N推荐中经常使用:
Reference
[1] 推荐系统常用评价指标:NDCG、Recall、Precision、Hit Rate
[2] en.wikipedia.org/wiki/Discou…
[3] 推荐系统有哪些常用的评价标准
[5] 推荐系统5---多目标排序