NDCG 详解:以油菜育种品系排序为例
概念
NDCG(Normalized Discounted Cumulative Gain,归一化折损累计增益) 是信息检索与排序学习中用来评价排序质量的核心指标。
它由三个逐层递进的概念组成:
- CG(Cumulative Gain,累计增益):把排序结果前 k 个位置的相关性得分直接相加。它不关心顺序 —— 排第 1 还是排第 100,贡献完全相同。
- DCG(Discounted Cumulative Gain,折损累计增益):在 CG 基础上,给越靠后的位置施加越大的折扣(惩罚)。因为决策者通常只关注前几位,排在前面的高相关项理应获得更高权重。
- NDCG(归一化折损累计增益):把 DCG 除以一个理想排序的 DCG(即 IDCG),把结果压缩到
[0, 1]区间,方便不同任务之间横向比较。
一句话总结:NDCG 衡量的是真正重要的项,有没有被排在前面,并用 0~1 的分数表达。
作用
NDCG 作为排序评价指标,其普适价值体现在以下几个方面:
- 客观比较多个排序模型 / 策略:面对同一批待排序对象,不同算法(如基于规则的排序、基于单特征的排序、基于机器学习的排序)给出的榜单往往不同。NDCG 提供一把统一的量尺,让谁的排序更懂得把重要项往前放有据可循,排除人工主观评判。
- 支持分级相关性评价:现实中的相关性常是分级的(如 0~4 的等级、星级、得分),而非简单的「相关 / 不相关」二分。NDCG 能区分「极重要」与「一般重要」的差异,二值指标则做不到。
- 聚焦头部质量:很多业务只关心排在最前面的少数结果(搜索的前几条、推荐的前几位、筛选的前 k 个候选)。
NDCG@k直接衡量前 k 个结果里,重要的项是否足够多、是否足够靠前,与真实使用场景高度契合。 - 可作模型训练目标:在排序学习(Learning to Rank)中,NDCG 既可作为评估指标,也可被直接作为目标函数,指导模型朝着把高相关项顶到前面的方向学习。
公式
设排序列表前 k 个位置的相关性得分为 rel₁, rel₂, ..., relₖ(relᵢ 为第 i 位的相关性等级)。
CG(累计增益)
$CG@k = \sum_{i=1}^{k} rel_i$
DCG(折损累计增益,常用指数形式)
$DCG@k = \sum_{i=1}^{k} \frac{2^{rel_i} - 1}{\log_2(i+1)}$
折扣项 $\log_2(i+1)$ 随位置 i 增大而增大,因此越靠后,单位相关性得分的贡献越小。第 1 位折扣为 $\log_2 2 = 1$(不折损),第 2 位 $\log_2 3 \approx 1.585$,第 3 位 $\log_2 4 = 2$,依此类推。
当相关性得分是连续实数时,则采用对数形式 $DCG@k = \sum \frac{rel_i}{\log_2(i+1)}$。
IDCG(理想 DCG):将相关性得分按从大到小排序后计算的 DCG,即“理论上最好排法”的得分。
NDCG(归一化)
$NDCG@k = \frac{DCG@k}{IDCG@k} \in [0, 1]$
NDCG 越接近 1,说明排序越好;越接近 0,说明排序越差。
示例:油菜育种品系排序
场景设定
某育种单位有 5 个甘蓝型油菜杂交后代品系,准备筛选综合表现最优者进入区域试验。育种专家依据综合育种价值(产量、含油量、抗疫病性、早熟性)给每个品系打了 0~4 的等级分 —— 这是用于事后评估的真实相关性:
| 品系 | 综合育种价值等级 rel | 说明 |
|---|---|---|
| 中油杂 A | 4(极优) | 高产、高油、抗疫病 |
| 华油杂 B | 3(优) | 高产、中油 |
| 中双 C | 2(中) | 中产、高油 |
| 秦优 D | 1(一般) | 中产、晚熟 |
| 油研 E | 0(淘汰) | 低产、感病 |
注:
rel是分级的(0~4),正是 NDCG 擅长处理的情形。
两个排序模型
- 模型甲(综合指数排序)给出的推荐顺序:
B → C → A → D → E - 模型乙(仅按单产排序,朴素)给出的推荐顺序:
E → D → C → B → A(恰好把最差的排最前,用于对照)
理想顺序(按真实 rel 降序):A → B → C → D → E,排序可视化如下图:

由图可知,模型甲给出的排序要较优于模型乙。
手动计算(以模型甲为例,k=5)
先准备:位置分母 $\log_2(i+1)$ 为 1, 1.585, 2, 2.322, 2.585;指数项 $(2^{rel}-1)$ 为 rel=4→15,3→7,2→3,1→1,0→0。
模型甲 DCG@5
| 位置 i | 品系 | rel | 2^rel−1 | log₂(i+1) | 贡献 |
|---|---|---|---|---|---|
| 1 | B | 3 | 7 | 1.000 | 7.000 |
| 2 | C | 2 | 3 | 1.585 | 1.893 |
| 3 | A | 4 | 15 | 2.000 | 7.500 |
| 4 | D | 1 | 1 | 2.322 | 0.431 |
| 5 | E | 0 | 0 | 2.585 | 0.000 |
| DCG | 16.823 |
理想 IDCG@5
| 位置 i | 品系 | rel | 2^rel−1 | log₂(i+1) | 贡献 |
|---|---|---|---|---|---|
| 1 | A | 4 | 15 | 1.000 | 15.000 |
| 2 | B | 3 | 7 | 1.585 | 4.416 |
| 3 | C | 2 | 3 | 2.000 | 1.500 |
| 4 | D | 1 | 1 | 2.322 | 0.431 |
| 5 | E | 0 | 0 | 2.585 | 0.000 |
| IDCG | 21.347 |
$NDCG@5_{甲} = \frac{16.823}{21.347} \approx 0.788$
同理,模型乙 DCG@5 ≈ 10.952,故 $NDCG@5_{乙} \approx 0.513$;理想排序 NDCG = 1.000。
解读:模型甲把极优品系 A 排到了第 3 位(被 B、C 挡在前面),所以没拿满分,但整体仍不错(0.79);模型乙几乎把顺序完全颠倒,得分骤降到 0.51。NDCG 清晰量化了「谁更懂得把好东西往前放」。
代码实现
下面用 Python 实现 NDCG,并复现上面的油菜育种示例。
| |
运行输出:
代码要点
dcg()用指数形式 $\sum (2^{rel}-1)/\log_2(i+1)$,位置从 1 开始计数。ndcg()默认把输入相关性降序当作理想排序(IDCG);也可显式传入真实理想列表。- NDCG 对位置敏感:把
rel=4的 A 从第 1 位挪到第 3 位,分数立刻从 1.0 掉到 0.79,直观体现了「好东西要往前放」。
总结
- NDCG 是什么:一种把排序结果映射成 0~1 分数的指标,核心是位置越靠后折扣越大 + 归一化到理想排序。
- 关键特性:支持分级相关性;关注头部顺序;跨任务可比。