做者: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)