此文为学习何晗老师《自然语言处理入门》笔记
参考:
准确率是衡量一个系统准确程度的标准,可以理解为一系列评测指标。
混淆矩阵
在搜索引擎、分类器、中文分词场景下的准确率本质上是下图四个集合的并集运算。 下图中“纵坐标”为预测结果,“横坐标”为标准答案。 这种图表在机器学习中也称混淆矩阵(confusion matrix)
混淆矩阵性质:
- 样本全集 = TP ∪ FP ∪ FN ∪ TN
- 任何一个样本属于4个集合中的一个,即没有交集
精确率、召回率
在中文分词任务中,一般使用在标准数据集上词语级别的精确率、召回率与F1 计算方法
- 精确率 (pricision,P) 指的是预测结果中正类数量占全部结果的比率。
- 召回率 (recall, R) 指的是正类样本被找出来的比率。
精确率和召回率:一场拔河比赛
要全面评估模型的有效性,必须同时检查准确率和召回率。遗憾的是,准确率和召回率往往是此消彼长的情况。即提高准确率通常会导致降低召回率,反之亦然。
如下图显示了电子邮件分类模型做出了30项预测,分类阈值右侧的被归类为“垃圾邮件”,左侧的被归类为“非垃圾邮件”。
| TP: 8 | FP: 2 |
| FN: 3 | TN: 17 |
?P = \frac {8} {8 + 2} = 0.8? ?R = \frac {9} {8 + 3} = 0.73?
提高分类阈值后:
FP会减少,FN会增加。结果,精确率有所提高,召回率则有所降低:
| TP: 7 | FP: 1 |
| FN: 4 | TN: 18 |
?P = \frac {7} {7 + 1} = 0.88? ?R = \frac {7} {7 + 4} = 0.64?
降低分类阈值
FP增加,FN减少。结果,精确率有所降低,而召回率有所提高:
| TP: 9 | FP: 3 |
| FN: 2 | TN: 16 |
?P = \frac {9} {9 + 3} = 0.75? ?R = \frac {9} {9 + 2} = 0.82?
更合适的评测标准
在系统排名中,人们只习惯用一个指标F1值。
?F1 = \frac {2 * P * R}{P+R}?
计算
标准答案构成一个集合A
分词结果所有单词构成一个集合B ?{TP}\cup{FN} = A? ?{TP}\cup{FP} = B? ?TP = A \cap B? ?P = \frac{|A \cap B|}{|B|}? ?R = \frac{|A \cap B|}{|A|}?
示例
100个病人,99个阴性,1个阳性,当预测阳性机器全部预测为阳性的时候
可见单纯的根据P或者R来评测并不客观。
OOV-R/IV-R
OOV指的是“未登录词”(Out Of Vocabulary),俗称新词,即词典未收录词汇。 如何正确切分OOV,乃至识别其语义,是整个NLP领域的难题之一。
IV指的是“登录词”(In Vocabulary)。 IV Recall Rate指的是词典中的词汇被正确召回的概率,连词典中的词汇都无法百分之百召回,说明词典分词的消歧能力不好。
OOV-R和IV-R是两个很有用的指标
计算方法
- 标准词典dic
- 记标准答案为A
- 计算分词结果B
- 统计标准答案A中,判断在词典dic中的累计IV,否则累计OOV
- 统计在A & B (即TP)中,判断在词典dic中的累计IV_R,否则累计OOV_R ?{OOV-R} = \frac{OOV_R}{OOV}? ?{IV-R} = \frac{IV_R}{IV}?
代码(摘录自书本82页)
def prf(gold, pred, dic):
"""
计算P R F1 OOV-R IV-R
:param gold: 标准答案,比如“商品 和 服务”
:param pred: 分词结果文件,比如“商品 和服 务”
:param dic: 词典
: return (P, R, F1, OOV-R, IV-R)
"""
A_size, B_size, A_cap_B_size, OOV, IV, OOV_R, IV_R = 0, 0, 0, 0, 0, 0
with open(gold) as gd, open(pred) as pd:
for g, p in zip(gd, pd):
# to_region 讲分词结果分为区间数组
# 比如 “商品 和 服务” 转为 [(0, 2), (2, 3), (3, 5)]
A, B = set(to_region(g)), set(to_region(p))
A_size += len(A)
B_size += len(B)
A_cap_B_size += len(A & B)
# \\s表示 空格,回车,换行等空白符
text = re.sub("\\s+", "", g)
# 计算标准答案
for (start, end) in A:
word = text(start: end)
if dic.containsKey(word):
IV += 1
else:
OOV += 1
# 计算TP
for (start, end) in A & B:
word = text(start: end)
if dic.containsKey(word)
IV_R += 1
else:
OOV_R += 1
P, R = A_cap_B_size / B_size * 100, A_cap_B_size / A_size * 100
F1 = 2 * P * R / (P + R)
IV-R, OOV-R = IV_R / IV, OOV_R / OOV
return P, R, F1, IV-R, OOV-R