推荐算法手撕集合(持续更新)
NDCG
NDCG 是一种位置敏感的排序指标,更关注在排序结果中,高相关的内容是否被排在越靠前的位置。
为什么需要NDCG?
在搜索 \ 推荐 \ 排序中:
用户只看前几条,位置越靠前,影响越大。
公式
NDCG@K = DCG@K IDCG@K \text{NDCG@K} = \frac{\text{DCG@K}}{\text{IDCG@K}} NDCG@K=IDCG@KDCG@K
- DCG:模型排序的得分
- IDCG:理想排序得分
- NDCG ∈ [0,1],越大越好
DCG
DCG@K = ∑ i = 1 K 2 r e l i − 1 log 2 ( i + 1 ) \text{DCG@K} = \sum_{i=1}^{K} \frac{2^{rel_i} - 1}{\log_2(i+1)} DCG@K=i=1∑Klog2(i+1)2reli−1
- i:位置
- r e l i rel_i reli:第 i 个结果的相关性(0/1/2/3...)
- log :位置越靠后,贡献越小,因为用户更关注排名靠前的结果,模拟用户注意力衰减。
IDCG
IDCG = 把同一批结果,按相关性从高到低排,再算 DCG
python
import math
def dcg_at_k(relevance, k, method=1):
dcg = 0.0
for i in range(k):
rel = relevance[i]
dcg += (2 ** rel - 1) / math.log2(i + 1)
return dcg
def ndcg_at_k(relevance, k, method=1):
idcg = dcg_at_k(sorted(relevance, reverse=True), k, method)
dcg = dcg_at_k(relevance, k, method)
if idcg == 0:
return 0
return dcg / idcg
AUC
含义:随机抽一个正样本和一个负样本,模型把正样本排在负样本前面的概率。
用 n_bins 把预测分数分桶,统计每个桶内正负样本数;从低分到高分扫描桶,累计"正样本比分数更低的负样本高"的配对数,并对同桶 tie 计 0.5 。最后除以总正负配对数,得到 AUC。
复杂度: O ( n + n b i n s ) O(n+n_bins) O(n+nbins)
python
def auc(labels, preds, n_bins=10000) :
neg_his = [0] * n_bins
pos_his = [0] * n_bins
n_pos = 0
n_neg = 0
for i in range(len(labels)) :
cur = int(preds[i] * n_bins)
if labels[i] == 0 :
neg_his[cur] += 1
n_neg += 1
else :
pos_his[cur] += 1
n_pos += 1
total = n_pos * n_neg
sum_neg = 0
sum_auc = 0
for i in range(n_bins) :
sum_auc += (sum_neg * pos_his[i] + pos_his[i] * neg_his[i] * 0.5)
sum_neg += neg_his[i]
return sum_auc / total