评估指标及代码实现(NDCG)

针对排序常用的评估指标,给出其计算原理及代码实现

排序评估指标

NDCG

1 原理

NDCG全称为 Normalized Discounted Cumulative Gain(归一化折损累计增益),通常用在搜索排序任务中,在这样的任务里,通常会返回一个list作为搜索排序的结果进行输出,为了验证这个list的合理性,就需要对这个list的排序进行评价。这也是NDCG的由来。

在实验中,list代表所有item的预测相关性,进行排序之后,得到每个项目id的位置rank,和标签label进行对比,在NDCK@10中,就是如果rank<10,那么就纳入ndcg计算,进行贡献。

  • Gain: G,增益

    在排序list中,增益指的就是里面的相关性得分,也就是模型的预测结果。rel(i)表示item(i)相关性得分。

  • Culumatative Gain:CG,累计增益。

    对k个rel(i)进行叠加,不考虑位置关系。
    C G k = ∑ i = 1 k r e l ( i ) CG_k=\sum_{i=1}^krel(i) CGk=i=1krel(i)

  • Discounted Cumulative Gain: DCG,折损累计增益。

    考虑排序顺序的因素,使得排名靠前的item增益更高,对排名靠后的item进行折损。DCG认为排在前面的贡献度更大,后面的贡献度较小,也就是对增益值进行加权求和,权重就是位置引起的。
    D C G k = ∑ i = 1 k r e l ( i ) l o g 2 ( i + 1 ) DCG_k=\sum_{i=1}^k\frac{rel(i)}{log_2(i+1)} DCGk=i=1klog2(i+1)rel(i)
    或者:
    D C G k = ∑ i = 1 k 2 r e l ( i ) + 1 l o g 2 ( i + 1 ) DCG_k=\sum_{i=1}^k\frac{2^{rel(i)}+1}{log_2(i+1)} DCGk=i=1klog2(i+1)2rel(i)+1
    也即是说:i越大,排序越往后,对应的 l o g ( i + 1 ) log(i+1) log(i+1)就越大,折损就越高。

  • iDCG,最好排列的的DCG

    根据rel(i)进行降序排列,以此序列计算DCG,也就是最好的DCG,称为iDCG。在计算中,采用labels的相关性得分计算(隐形就是0,1;显性评分则是1-5分数)。
    如果是隐性评分,根据

  • NDCG,归一化折损累计增益

    由于不同搜索的结果返回长度不一样,这样的iDCG就是一个绝对值,没法比较,因此通过DCG/iDCG来表示NDCG,代表着一个相对程度。
    N D C G = D C G i D C G NDCG = \frac{DCG}{iDCG} NDCG=iDCGDCG

2 代码实现

上面的理论乍一看理解起来很简单,但是真到具体应用的时候,发现还是很复杂的,以后很多问题需要思考,比如,里面的相似性得分,排序根据什么得分排序等等。代码的实现也容易绕晕。下面给出两种代码方式,分别是只能计算隐性得分的torch版本和numpy版本

torch

# socres为对应item(i)的预测得分,labels对item(i)的标签,由于是隐形评分数据,只有0,1点击值
scores = torch.tensor([[0,0.1,0.3,0.4,0.5]])
labels = torch.tensor([[0,1,1,0,1]])
k = 5
# 降序排列,获取推荐列表的id
rank = (-scores).argsort(dim=1)
cut = rank[:, :k]
# 获取相关性得分,也就是0,1,如果命中
hits = labels.gather(1, cut)
# 计算位置关系,从2开始计
position = torch.arange(2, 2+k)
# 根据位置关系计算位置权重
weights = 1 / torch.log2(position+1)
# 计算DCG
dcg = (hits* weights).sum(1)
# 计算iDCG,由于相关性得分为0,1,且经过排序,所以计算前面为1对应weights之和即可。
idcg = torch.Tensor([weights[:min(n, k)].sum() for n in labels.sum(1)])

ndcg = dcg / idcg
print(ndcg)

numpy

def getDCG(scores):
    return np.sum(
        np.divide(np.power(2, scores) - 1, np.log2(np.arange(scores.shape[0], dtype=np.float32) + 2)+1),
        # np.divide(scores, np.log2(np.arange(scores.shape[0], dtype=np.float32) + 2)+1),
        dtype=np.float32)

def getNDCG(rank_list, pos_items):
    relevance = np.ones_like(pos_items)
    it2rel = {it: r for it, r in zip(pos_items, relevance)}
    rank_scores = np.asarray([it2rel.get(it, 0.0) for it in rank_list], dtype=np.float32)
    print(rank_scores)
    idcg = getDCG(relevance)

    dcg = getDCG(rank_scores)

    if dcg == 0.0:
        return 0.0

    ndcg = dcg / idcg
    return ndcg
## l1是推荐排序列表,l2是真实点击的列表
l1 = [4,3,2,1,0]
l2 = [4,2,1]
a = getNDCG(l1, l2)
print(a)
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
NDCG(Normalized Discounted Cumulative Gain)是用来衡量推荐算法排序效果的一种指标,其值越大说明算法排序效果越好。下面是利用NDCG评估AFM算法代码实现的详细步骤: 1. 首先,我们需要准备数据集。通常情况下,我们需要将数据集分成训练集和测试集两部分,其中训练集用来训练模型,测试集用来评估模型的性能。 2. 在训练集上训练AFM模型,并在测试集上进行预测。预测结果通常是每个用户对所有物品的评分,我们需要根据评分对物品进行排序。 3. 计算每个用户的NDCG值。具体来说,对于每个用户,我们需要将其预测评分按照从高到低的顺序排列,并根据真实评分计算NDCG值。NDCG的计算公式如下: $$ NDCG_k = \frac{DCG_k}{IDCG_k} $$ 其中,$k$表示推荐列表的长度,$DCG_k$表示在推荐列表中前$k$个物品的折损累加收益,$IDCG_k$表示在所有物品中按照真实评分排名前$k$个物品的折损累加收益。具体来说,$DCG_k$和$IDCG_k$的计算公式分别为: $$ DCG_k = \sum\limits_{i=1}^k \frac{2^{rel_i}-1}{log_2(i+1)} $$ $$ IDCG_k =\sum\limits_{i=1}^k \frac{2^{rel_i}-1}{log_2(i+1)} $$ 其中,$rel_i$表示第$i$个物品的真实评分,$log_2(i+1)$是一个惩罚因子,表示排名越靠后的物品权重越小。 4. 最后,我们需要对所有用户的NDCG值求平均,得到AFM算法的平均NDCG值,用于评估模型的性能。 下面是利用Python实现计算NDCG代码示例: ```python import numpy as np def dcg_k(scores, k): # 计算DCG值 rel = scores[:k] dcg = np.sum((2 ** rel - 1) / np.log2(np.arange(2, k+2))) return dcg def idcg_k(scores, k): # 计算IDCG值 rel = np.sort(scores)[::-1][:k] idcg = np.sum((2 ** rel - 1) / np.log2(np.arange(2, k+2))) return idcg def ndcg_k(scores, k): # 计算NDCG值 dcg = dcg_k(scores, k) idcg = idcg_k(scores, k) ndcg = dcg / idcg if idcg > 0 else 0 return ndcg def evaluate_ndcg(model, test_set, k): # 计算平均NDCGndcg_list = [] for user in test_set.keys(): items = list(test_set[user].keys()) scores = model.predict(user, items) ranked_scores = np.argsort(-scores) ranked_items = [items[i] for i in ranked_scores] ranked_ratings = [test_set[user][item] for item in ranked_items] ndcg = ndcg_k(ranked_ratings, k) ndcg_list.append(ndcg) return np.mean(ndcg_list) ``` 其中,`evaluate_ndcg`函数接收三个参数:`model`表示训练好的AFM模型,`test_set`表示测试集数据,`k`表示推荐列表的长度。函数的返回值是AFM算法在测试集上的平均NDCG值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Weiyaner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值