我正在从事一个涉及使用NDCG(归一化分布累积增益)的项目,并且我了解该方法的基础计算。
因此,我从
ndcg_score
导入了 sklearn.metrics
,然后将一个真实值数组和另一个数组传递给 ndcg_score
函数来计算它们的 NDCG 分数。地面真值数组的值为 [5, 4, 3, 2, 1]
,而另一个数组的值为 [5, 4, 3, 2, 0]
,因此这两个数组中只有最后一个元素不同。
from sklearn.metrics import ndcg_score
user_ndcg = ndcg_score(array([[5, 4, 3, 2, 1]]), array([[5, 4, 3, 2, 0]]))
我预计结果约为 0.96233 (9.88507/10.27192)。然而,
user_ndcg
居然返回了1.0
,这让我很惊讶。最初我以为这是由于舍入造成的,但事实并非如此,因为当我对另一组数组进行实验时:ndcg_score(array([[5, 4, 3, 2, 1]]), array([[5, 4, 0, 2, 0]]))
,它正确返回了0.98898。
有谁知道这是否可能是 sklearn
ndcg_score
函数的错误,或者我的代码是否做错了什么?
我假设您正在尝试预测此问题的六个不同类别(0、1、2、3、4 和 5)。如果要评估五个不同观测值的 ndcg,则必须向函数传递两个形状为
(5, 6)
的数组。
也就是说,您已将基本事实和预测转换为每行五行六列的数组。
# Current form of ground truth and predictions
y_true = [5, 4, 3, 2, 1]
y_pred = [5, 4, 3, 2, 0]
# Transform ground truth to ndarray
y_true_nd = np.zeros(shape=(5, 6))
y_true_nd[np.arange(5), y_true] = 1
# Transform predictions to ndarray
y_pred_nd = np.zeros(shape=(5, 6))
y_pred_nd[np.arange(5), y_pred] = 1
# Calculate ndcg score
ndcg_score(y_true_nd, y_pred_nd)
> 0.8921866522394966
这是
y_true_nd
和 y_pred_nd
的样子:
y_true_nd
array([[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 1., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 1., 0., 0., 0., 0.]])
y_pred_nd
array([[0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 1., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[1., 0., 0., 0., 0., 0.]])
在手动计算 NDCG 分子(即 DCG)时,您使用的是“array([[5, 4, 3, 2, 0]])”。 DCG 计算中应该包含的是ground true相关性分数,根据“array([[5, 4, 3, 2, 0]])”的顺序重新排列。由于分数的顺序是严格降序的,因此 DCG 应直接从 array([[5, 4, 3, 2, 1]]) 计算。换句话说,您的“array([[5, 4, 3, 2, 0]])”分数表示 IDCG 场景。这就是为什么你从 sklearn 得到 1 的原因。 即使您将分数更改为“array([[.5, .4, .3, .2, 0]])”,您最终也会得到相同的 NDCG = 1,因为只有顺序与您的分数有关。以下所有命令都会产生相同的值,即“10.27192”
print("DCG score =: ", dcg_score(np.array([[5, 4, 3, 2, 1]]), np.array([[5, 4, 3, 2, 0]])))
print("DCG score =: ", dcg_score(np.array([[5, 4, 3, 2, 1]]), np.array([[.5, .4, .3, .2, .0]])))
print("IDCG score =: ", dcg_score(np.array([[5, 4, 3, 2, 1]]), np.array([[5, 4, 3, 2, 1]])))