做者:LogMpython
本文原载于 https://segmentfault.com/u/logm/articles ,不容许转载~segmentfault
P@K
,表明前 K 个预测值中有多少的准确率 (Precision)。ide
好比,一个模型输出了一组排序,其输出的好坏依次为:好、坏、好、坏、好。idea
那么,code
Prec@3 = 2/3orm
Prec@4 = 2/4排序
Prec@5 = 3/5ip
def precision(gt, pred, K): """ Computes the average precision. gt: list, ground truth, all relevant docs' index pred: list, prediction """ hit_num = len(gt & set(pred[:K])) return float(1.0 * hit_num / K)
AP
是 average precision 的缩写,计算方式是把全部相关文档的 P@K
求平均。ci
借用上面的例子,一个模型输出了一组排序,依次为:好的结果、坏的结果、好的结果、坏的结果、好的结果。文档
那么,
AP = (1/1 + 2/3 + 3/5) / 3 = 0.76
注意,不是 (1/1 + 1/2 + 2/3 + 2/4 + 3/5) / 5。由于在实际状况中,总有一些"好的结果"是模型漏召回的,指标的计算公式应该怎么处理这部分漏召回?
AP
会把全部"好的结果"都算上,可是排序模型可能会对某些"好的结果"漏召回,这些"漏召回"的P@K
视为0。
MAP
是 mean average precision 的缩写,就是把全部的 AP
求平均。
def average_precision(gt, pred): """ Computes the average precision. gt: list, ground truth, all relevant docs' index pred: list, prediction """ if not gt: return 0.0 score = 0.0 num_hits = 0.0 for i, p in enumerate(pred): if p in gt and p not in pred[:i]: num_hits += 1.0 score += num_hits / (i + 1.0) return score / max(1.0, len(gt))
某些场景下,每一个问题只有一个标准答案,咱们只关心标准答案的排序位置。此时,咱们是把标准答案在模型输出结果中的排序取倒数做为它的 RR
(Reciprocal Rank)。
好比,模型的输出一组排序,依次为:非标准答案,标准答案,非标准答案,非标准答案
那么:
RR = 1/2
对全部的问题取平均,获得 MRR
(Mean Reciprocal Rank)。
def reciprocal_rank(gt, pred): """ Computes the reciprocal rank. gt: list, ground truth, all relevant docs' index pred: list, prediction """ if not gt: return 0.0 score = 0.0 for rank, item in enumerate(pred): if item in gt: score = 1.0 / (rank + 1.0) break return score
这块涉及到一些数学公式,我懒得打了,能够谷歌到。直接看下面的代码来理解估计会更清楚一些。
DCG
: Discounted Cumulative Gain
IDCG
: ideal DCG,是 ground truth 状况下的 DCG
NDCG
: normalized DCG,是 DCG 和 IDCG 相除
NDCG = DCG / IDCG
def NDCG(gt, pred, use_graded_scores=False): """ Computes the NDCG. gt: list, ground truth, all relevant docs' index pred: list, prediction """ score = 0.0 for rank, item in enumerate(pred): if item in gt: if use_graded_scores: grade = 1.0 / (gt.index(item) + 1) else: grade = 1.0 score += grade / np.log2(rank + 2) norm = 0.0 for rank in range(len(gt)): if use_graded_scores: grade = 1.0 / (rank + 1) else: grade = 1.0 norm += grade / np.log2(rank + 2) return score / max(0.3, norm)