Update some code from pycorrector.
contact: [email protected]
pycorrector的纠错过程:
1,白名单纠错。在data/custom_confusion.txt中配置。命中就直接取词典的正确词。
2,分词后按词纠错。jieba分词后,未登录词加入疑似错误词典 (用过滤规则+词典(包含切词词典及自定义词典)判断未登录词),然后使用同音字等规则取候选词(首选保留词的第一个字,后面的字取同音字)。
3,单字纠错。根据ngram语言模型查找错字:按字符计算2阶,3阶的ngram值,2阶与3阶的ngram对应一组求平均值,对每个平均值在全部score的平均值上下n倍(n=2)标准差之间的属于正常点,否则算异常点字,取疑似错字的位置。
4,对所有候选的错字、错词,取同音字或异形字做候选集,再通过ngram模型计算句子(所有符号都作为截断标记得到句子)的PPL混淆度,取混淆度最低的做最后纠错候选。
5,可以在data/custom_word_freq.txt中配置纠错黑名单,使误纠错的词,不纠错。而且,jieba的分词错误,也可以把新词加入该文件,纠正分词结果,因为该文件的词会添加到jieba的定制词典。比如:高堆重,分词错误:高堆/重,添加“堆重”后分词正确。
pycorrectorUB的主要修改点:
1, 原代码中如果句子中包含白名单的词就纠错,不做分词进行匹配。这样做不合理,应该先分词,不然会误纠错,已发现多个误纠错的badcase。但是,先分词也有可能因为分词不正确,无法匹配到白名单。经测试,总体来说增加分词利大于弊。 pycorrectorUB/corrector.py中增加配置参数:segment_word_confusion 默认为True,先进行分词。
badcase:
《通知》确定了国家重点支持的集成电路涉及领域包括重点集成电路设计领域 ['家重', '加重', 8, 10]
香港光膜股权对应的遗产受益人为唐翔千先生的四名子女唐英敏、唐英年、唐庆年、唐圣年, [['名子', '名字', 93, 95]]
2,原代码直接取PPL最低的候选词(字)做纠错,误纠错率很高。修改代码,在计算完PPL后,候选词的PPL比原词的PPL大于阈值的才做纠错(在pycorrectorUB/corrector.py的self.ppl_threshold_than_cur中设置.)。如果纠错文本只有1个词(小于4个字),使用该阈值:self.ppl_threshold_than_cur_one_word ,因为当文本内容很短时,PPL会非常高。
3,增加一个定制的filter.py,使用jieba的POS判断人名等词性(jieba的POS不是很准),对人名,公司名进行过滤,此类文本不进行纠错,因为此类名称很容易造成误纠错,特别是招股书中的人名,企业名,都很特殊,难以判断正确性,而且经过审核的招股书,人名和企业名应该是不会错的。(因为每个符号都会分block,还有POS有误的场景,所以是整段文本过滤。) 如果需要,也可以在该filter中对其他POS和场景进行过滤处理。如果需要取消该filter,可以设置:corrector.use_custom_filter = False。
4,使用2.8G的语言模型过大,部署有困难。经测试,基于字的中文语言模型,纠错效果好于基于词的中文语言模型,主要原因是不同使用场景下,不同的分词本身会带来不同的影响,基于词的语言模型PPL的差异波动比较大,不如基于字的语言模型稳定。PPL对于纠错主要是个评价坐标系的作用,需要比较稳定。经测试对比后,使用144M的基于人名日报的训练的基于字的语言模型效果比较好。
5,因为准确率和召回率,是相互制约的两个指标。追求很高的准确率(即很低误纠错率),必然造成召回率降低,即减少误纠错时,也会减少错误识别率。审核后的招股书是很特殊的使用场景,文档本身非常严谨,错误极少,所以该场景的纠错系统,并不适用于手写错误的场景。为此设计了两种纠错模式,在corrector纠错接口增加了一个参数crafted_type=True时,表示手写错误的模式,召回率高,准确率会降低。不使用该参数时,默认是招股书的模式,阈值设置很高,误纠错很少。crafted_type=True时,不使用人名,公司名的filter,同时也可以重新调整PPL阈值self.ppl_threshold_crafted_type(常规阈值),self.ppl_threshold_one_word_crafted_type(句子小于4个字时的阈值)。代码中的默认阈值,已经经过大量的测试分析,是比较合适的设置,测试用的用例见readme.txt文档。