NLP入门(2)-分词结果评价及实战
上一篇中我们介绍了词典分词的方法,并介绍了正向最长匹配、逆向最长匹配和双向最长匹配几种分词规则。本文主要介绍一下如何对分词结果进行评价。
对于分词结果的评价,本文主要介绍五个指标,分别是精确率、召回率、F1值、OOV Recall Rate和IV Recall Rate。
1、评价指标介绍
1.1 精确率、召回率、F1值
先回顾一下精确率、召回率、F1值的定义。对于二分类问题,真实的样本标签有两类,我们学习器预测的类别有两类,那么根据二者的类别组合可以划分为四组,如下表所示:
上表即为混淆矩阵,其中,行表示预测的label值,列表示真实label值。TP,FP,FN,TN分别表示如下意思:
TP(true positive):表示样本的真实类别为正,最后预测得到的结果也为正;
FP(false positive):表示样本的真实类别为负,最后预测得到的结果却为正;
FN(false negative):表示样本的真实类别为正,最后预测得到的结果却为负;
TN(true negative):表示样本的真实类别为负,最后预测得到的结果也为负.
可以看到,TP和TN是我们预测准确的样本,而FP和FN为我们预测错误的样本。
基于混淆矩阵,我们可以得到如下的评测指标:
精确率/召回率
精确率表示预测结果中,预测为正样本的样本中,正确预测为正样本的概率;
召回率表示在原始样本的正样本中,最后被正确预测为正样本的概率;
二者用混淆矩阵计算如下:
F1值
为了折中精确率和召回率的结果,我们又引入了F-1 Score,计算公式如下:
但是分词问题并不是一个分类问题,如何计算上述的指标呢?需要做一个转换,假设对于一段文本,每个单词在文本中所对应的位置为[a,b],那么标准答案中,所有单词的区间构成一个集合A,对于某一种切分规则,得到的分词结果的区间构成一个集合B(为什么要使用区间,而不直接使用字符串呢,因为前后字符串可能有相同的,但对于区间,是不可能有重复的)。
所以集合A是所有的正确样本,即A 为TP 和 FN的并集,而B是分词器认为的正确样本,即TP和FP的并集,那么 TP 即为 A和B的交集,公式表示如下:
好了,根据上面的转换,我们就可以计算精确率、召回率和F1值了:
举个简单的例子:
所以精确率和召回率均为3/5=0.6,而F1值也是0.6。
1.2 OOV Recall Rate和IV Recall Rate
接下来介绍两个比较新奇的指标。OOV的意思是未登陆词(Out of Vocabulary),也可以称作新词。假设“就读于中国人民大学”的正确分词结果是“就读 于 中国人民大学”,由于“中国人民大学”没有出现在词典中,那么就是未登陆词。OOV Recall Rate指的就是分词方法把这些未登陆词给找出来的能力,如果一种分词方法,能够找出像中国人民大学这种的新词,那么它的OOV Recall Rate会比较高。其计算方法如下:
1)首先计算正确分词结果中所有未登陆词的个数,作为分母
2)计算基于某种分词方法得到的分词结果中分词正确部分中未登陆词的个数,作为分子(这里分子不是基于某种分词方法得到的分词结果中未登陆词的个数,而是分词正确的那部分中未登陆词的个数)
3)分子分母相除,得到OOV Recall Rate
但很明显的,对于词典分词来说,它是基于词典匹配进行切分的,词典中未出现的词它也是基本找不到的,所以说词典分词的新词发现能力几乎为零(但并不是0,单字的新词还是可以找到的)。
新词发现也是NLP领域的一个比较核心的难题。
IV的意思是是登陆词(In Vocabulary),相应的IV Recall Rate指的是词典中的词汇被正确召回的概率。其计算方法如下:
1)首先计算所有正确分词结果中所有登陆词的个数,作为分母
2)计算基于某种分词方法得到的分词结果分词正确部分中登陆词的个数,作为分子(这里同样是正确分词部分,而非所有的分词结果)
3)分子分母相除,得到IV Recall Rate
几个评测指标的原理介绍就到这里了,接下来进入实战阶段吧。
2、实战练习
这里,我们首先定义一个函数,把分词结果转换为对应的区间集合:
def to_region_set(segment_str):
# input : 就读 于 中国人民大学
# return:[(0,1),(2,2),(3,8)] 闭区间
region =[]
start = 0
for word in segment_str.split(" "):
end = start + len(word)
region.append((start,end-1))
start = end
return region
print(to_region_set('就读 于 中国人民大学'))
#[(0, 1), (2, 2), (3, 8)]
接下来,我们来计算上述提到的五个指标:
def prf(gt:list,pred:list,dic):
A_size = 0
B_size = 0
A_cap_B_size = 0
OOV = 0
IV = 0
OOV_R = 0
IV_R = 0
for g,p in list(zip(gt,pred)):
A,B = set(to_region_set(g)),set(to_region_set(p))
A_size += len(A)
B_size += len(B)
A_cap_B_size += len(A & B)
org_text = g.replace(" ", "") # 还原回分词前的文档
for(start,end) in A:
word = org_text[start:end+1]
if word in dic:
IV += 1
else:
OOV += 1
for(start,end) in A & B:
word = org_text[start:end+1]
if word in dic:
IV_R += 1
else:
OOV_R += 1
precision = A_cap_B_size / B_size
recall = A_cap_B_size / A_size
F1 = 2 * precision * recall / (precision + recall)
OOV_Recall_Rate = OOV_R / OOV
IV_Recall_Rate = IV_R / IV
return precision,recall,F1,OOV_Recall_Rate,IV_Recall_Rate
gt_list = ['就读 于 中国人民大学','电视 上 的 电影 节目','项目 的 研究','角色 本人 将 会 参与 配音']
pred_list = ['就读 于 中国 人民 大学','电视 上 的 电影 节目','项 目的 研究','角色 本人 将 会 参与 配音']
print("Precision:%.2f,Recall:%.2f,F1:%.2f,OOV_R:%.2f,IV_R:%.2f" % prf(gt_list,pred_list,dict_set))
从代码上,有几点需要注意的地方(如有理解不到位的地方还望指正):
1)计算 OOV Recall Rate和IV Recall Rate的时候,分子分母都没有去重,如果中国人民大学出现了两次,那么在分母中算作2,而非1。不去重的话,可以看到整个新词发现的影响面。比如只有两个新词,中国人民大学和休斯顿马赛克队,中国人民大学被识别,而休斯顿马赛克队未被识别,去重结果OOV Recall Rate=0.5,如果不去重,中国人民大学出现1次,休斯顿马赛克队出现9次,那么OOV Recall Rate=0.1,由此可以看出新词发现的能力比较弱,休斯顿马赛克队对于分词结果的影响较大。
2)即使是词典分词,IV Recall Rate也没有达到1,如‘项目 的 研究’,分词结果为'项 目的 研究',可以看到词典分词的消岐能力一般,没有基于上下文给出最优的分词结果。
本文的介绍就到这里了,主要介绍了五个分词结果的评价指标,分别是精确率、召回率、F1值、OOV Recall Rate和IV Recall Rate,你都搞清楚了么?