ner(命名实体识别)一般是词典和模型方式结合,词典负责已有词识别,模型负责未知词识别。
在不需发现未知词的情况下基于词典的实体识别已足够
基于字典的ner也有两种做法:字符串多模匹配 和 切词(词典加入自定义词库)
字符串多模匹配
多模匹配有两种基本算法:trie树 和 记录长度集合的最长匹配
trie树匹配效率更高,但占用内存更多
而记录长度集合的最长匹配,计算时间效率相比trie稍低(但比切词高很多),内存空间比较省,这里重点介绍一下
记录长度集合的最长匹配方式不依赖分词,会存储以字典中每个词开头两个字的长度集合,并对字典中每个字做hashmap。
举个例子,刘德华的歌曲 ,先查 刘德 开头的词的长度有 5 3 两个长度,然后再取5个长度的“刘德华的歌”,字典里没有,则再取3个长度“刘德华”,字典里有,则命中
采用该种方式相比切词更容易出现错误匹配,比如 “研究生命科学“ ,假如“研究生“在字典里,就会错误识别为“{实体}命科学“,因为该方式不考虑上下文,而切词会考虑
实验:采用该最长匹配方式测试700万数据,实体字典占600M
4000问句平均每个耗时16微秒,而切词方式平均每个耗时300微秒;
最长匹配相比之下效率有20倍提升:
- 一方面是因为切词规则复杂
- 一方面是最长匹配实际用到字符串匹配的次数很少,我统计了一下4000问句平均每句只用了2.3次字符串匹配
切词匹配
将字典加入切词工具的自定义词库,便可正常识别,这也是业界通用做法
但经测试,700万数据,python版内存占用7G,c++版内存占用11G
切词内部的词库使用trie树实现,会占用较多内存
总结:最长匹配方式,时间空间相比切词都更好,但是准确率低不少;切词准确率高,但时空效率低,召回率低(一些特殊词加入自定词典无效,比如“新疆天业(集团)有限公司“,"ST德棉”)
优化:两种方式结合
两种方式各有千秋,这里考虑将两种方式结合使用:先最长匹配,然后将取出的实体放回切词结果看是否“完整”,注意不用再将词典放入切词工具的自定义词库。
怎么判断“完整”:如果最长匹配得到的词开始位置的字在切词结果中不与前一个字组成词 且 结束位置的字在切词结果中不与后一个字组成词,则认为“完整”
举例:最长匹配得到“国航”,切词上下文“中国 航展“,说明”国航“不“完整”;最长匹配得到“南国置业”,切词上下文“昨天 南国 置业 发布”,说明“南国置业” “完整”
该算法实验结果表明:ner准确率提升到近100%(评测的500项数据里没有发现提取错误的),而且没有占用更多内存,很适合拥有大规模词典的ner
另外,当最长匹配提取的词较长时,无匹配的情况极少了,对这种长词可以不用放回切词结果验证。
注:实验用的切词工具主要是jieba python版,
pyltp最初也有使用,但发现有两个问题:
- 加入自定义词库的词有时不起作用,如果存在包含关系的两个词同时加入自定词词典,很可能切词结果是短词而非长词
- 切词准确率偏低,比如切词结果“黑化 股份公布”,“飞乐股份公告”,“中小板 个 股世荣兆业”,“南国 置业证 代 回应 称”,“金 螳螂,002081”,“* ST 天发股”,“* ST 嘉瑞变 身 为 ”