NDCG原理及代码实现

Normalized Discounted Cumulative Gain(归一化折损累计增益)

NDCG用作排序结果的评价指标,评价排序的准确性。

推荐系统通常为某用户返回一个item列表,假设列表长度为K,这时可以用NDCG@K评价该排序列表与用户真实交互列表的差距。

解释:

  • Gain: 表示列表中每一个item的相关性分数

G a i n = r ( i ) Gain=r(i) Gain=r(i)

  • Cumulative Gain:表示对K个item的Gain进行累加

C G @ K = ∑ i K r ( i ) CG@K=\sum^K_ir(i) CG@K=iKr(i)

  • Discounted Cumulative Gain:考虑排序顺序的因素,使得排名靠前的item增益更高,对排名靠后的item进行折损。

D C G @ K = ∑ i K r ( i ) l o g 2 ( i + 1 ) DCG@K=\sum^K_i\frac{r(i)}{log_2(i+1)} DCG@K=iKlog2(i+1)r(i)

如果相关性分数r(i)只有(0,1)两种取值时,DCG@K有另一种表达。其实就是如果算法返回的排序列表中的item出现在真实交互列表中时,分子加1,否则跳过。

D C G @ K = ∑ i K = 2 r ( i ) l o g 2 ( i + 1 ) DCG@K=\sum_i^K=\frac{2^{r(i)}}{log_2(i+1)} DCG@K=iK=log2(i+1)2r(i)

  • Normalized Discounted Cumulative Gain:DCG能够对一个用户的推荐列表进行评价,如果用该指标评价某个推荐算法,需要对所有用户的推荐列表进行评价,由于用户真实列表长度不同,不同用户之间的DCG相比没有意义。所以要对不同用户的指标进行归一化,自然的想法就是计算每个用户真实列表的DCG分数,用IDCG表示,然后用每个用户的DCG与IDCG之比作为每个用户归一化后的分值,最后对每个用户取平均得到最终的分值,即NDCG。

N D C G u @ K = D C G u @ K I D C G u NDCG_u@K=\frac{DCG_u@K}{IDCG_u} NDCGu@K=IDCGuDCGu@K

N D C G @ K = N D C G u @ K ∣ u ∣ NDCG@K=\frac{NDCG_u@K}{|u|} NDCG@K=uNDCGu@K

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")}')

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值