NDCG(标准化贴现收益)是否有缺陷?我计算了一些替代的排名质量衡量标准,但我无法理解它

nee*_*hiv 5 python information-retrieval machine-learning ranking-functions supervised-learning

我正在使用 python 来解决学习排序问题,并且我正在使用以下 DCG 和 NDCG 代码(来自http://nbviewer.ipython.org/github/ogrisel/notebooks/blob/master/Learning %20to%20Rank.ipynb )

def dcg(relevances, rank=20):
    relevances = np.asarray(relevances)[:rank]
    n_relevances = len(relevances)
    if n_relevances == 0:
        return 0.
    discounts = np.log2(np.arange(n_relevances) + 2)
    return np.sum(relevances / discounts)

def ndcg(relevances, rank=20):
    best_dcg = dcg(sorted(relevances, reverse=True), rank)
    if best_dcg == 0:
        return 0.
    return dcg(relevances, rank) / best_dcg
Run Code Online (Sandbox Code Playgroud)

以下是 3 个项目列表中最好和最坏情况的 DCG 值,没有重复的排名...

>>> ndcg(np.asarray([3,2,1]))
1.0
>>> ndcg(np.asarray([1,2,3]))
0.78999800424603583
Run Code Online (Sandbox Code Playgroud)

我们可以使用这个指标来比较两个排名,看看哪个更好。但是,如果我计算 4 项列表的最坏情况......

>>> ndcg(np.asarray([1,2,3,4]))
0.74890302967841715
Run Code Online (Sandbox Code Playgroud)

4 项列表似乎不再与 3 项列表具有可比性。

我还计算了两个替代的 NDCG。NDCG2 将获得的 dcg 与 bot 的最佳和最坏情况进行比较......

def ndcg2(relevances, rank=20):
    best_dcg = dcg(sorted(relevances, reverse=True), rank)
    worst_dcg=dcg(sorted(relevances, reverse=False),rank)
    if best_dcg == 0:
        return 0.
    return (dcg(relevances, rank)-worst_dcg) / (best_dcg-worst_dcg)
Run Code Online (Sandbox Code Playgroud)

NDCG 将我的实际排名列表随机化 50 次,计算每个排名的 dcg,并将其与我的实际 DCG 进行比较。

def ndcg3(relevances, rank=20):
    shuffled=np.copy(relevances)
    rands=[]
    for i in range(50):
        np.random.shuffle(shuffled)
        rands.append(dcg(shuffled,rank))
    avg_rand_dcg=np.mean(np.asarray(rands))
    return dcg(relevances, rank) / avg_rand_dcg
Run Code Online (Sandbox Code Playgroud)

在我的各种列表中,我得到了以下指标......

  • NDCG:平均值为 0.87(听起来不错)
  • 斯皮尔曼排名:0.25左右(并不惊人,但还是有一些东西)
  • NDCG2:0.58(平均而言,比最差的 dcg 稍微更接近于最佳的 dcg)
  • NDCG3:1.04(比随机排序列表稍好)

老实说,我无法理解这些结果。我的 NDCG 值看起来不错,但它们在各个列表之间真的具有可比性吗?替代指标是否更有意义?

编辑:在我的第一次随机比较中,我没有使用 np.copy()。因此,我的随机分数几乎总是 0.99。现在这个问题已经解决了,结果也更有意义。

Clé*_*gnc 5

有人认为可能会误导你的是NDCG正常化的方式。通常,您有许多文档需要排名,但您的 NDCG 会被截断为较少数量的文档(例如 NCDG@3)。在您的代码中,这是由参数“rank”确定的。

假设您想要对相关性 R = [1, 2, 3, 4, 0] 的 5 个文档进行排名,并计算 NDCG@3。如果您的算法认为最佳顺序是 [doc1, doc2, doc3, doc4, doc5],那么您将拥有:

NDCG@3 = DCG([1, 2, 3]) / DCG([4, 3, 2])
Run Code Online (Sandbox Code Playgroud)

并不是

NDCG@3 = DGC([1, 2, 3]) / DCG([3, 2, 1])   # Incorrect
Run Code Online (Sandbox Code Playgroud)

所以从某种意义上来说,NDCG([1, 2, 3]) 和 NDCG([1, 2, 3, 4]) 没有可比性。分子完全相同,但分母完全不同。如果你想让NDCG有一个直观的含义,你必须将'rank'设置为小于或等于你的文档数量。