作者:LogM
本文原載於 https://segmentfault.com/u/logm/articles ,不允許轉載~
1. P@K
P@K
,代表前 K 個預測值中有多少的準確率 (Precision)。
比如,一個模型輸出了一組排序,其輸出的好壞依次爲:好、壞、好、壞、好。
那麼,
Prec@3 = 2/3
Prec@4 = 2/4
Prec@5 = 3/5
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)
2. MAP
AP
是 average precision 的縮寫,計算方式是把所有相關文檔的 P@K
求平均。
借用上面的例子,一個模型輸出了一組排序,依次爲:好的結果、壞的結果、好的結果、壞的結果、好的結果。
那麼,
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))
3. MRR
某些場景下,每個問題只有一個標準答案,我們只關心標準答案的排序位置。此時,我們是把標準答案在模型輸出結果中的排序取倒數作爲它的 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
4. NDCG
這塊涉及到一些數學公式,我懶得打了,可以谷歌到。直接看下面的代碼來理解估計會更清楚一些。
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)