[nlp] 命名实体识别中的中文名识别算法

命名实体识别

命名实体识别是自然语言处理中的一项基础性工作,需要把文本中出现的命名实体包括人名、地名、组织机构名、日期、时间、和其他实体识别出来并加以归类。

基于CRF的命名实体识别方法

特征模板一般采用当前位置的前后n(n≥1)个位置上的字(或词、字母、数字、标点等,不妨统称为“字串”)及其标记表示,即以当前位置的前后n个位置范围内的字串及其标记作为观察窗口:(…w-n/tag-n,…,w-1/tag-1w0/tag0,w1/tag1,…,wn/tagn,…)。考虑到,如果窗口开得较大时,算法的执行效率会太低,而且模板的通用性较差,但窗口太小时,所涵盖的信息量又太少,不足以确定当前位置上字串的标记,因此,一般情况下将n值取为2~3,即以当前位置上前后2~3个位置上的字串及其标记作为构成特征模型的符号。

由于不同的命名实体一般出现在不同的上下文语境中,因此,对于不同的命名实体识别一般采用不同的特征模板。例如,在识别汉语文本中的人名时,考虑到不同国家的人名构成特点有明显的不同,一般将人名划分为不同的类型:中国人名、日本人名、俄罗斯人名、欧美人名等。同时,考虑到出现在人名左右两边的字串对于确定人名的边界有一定的帮助作用,如某些称谓、某些动词和标点等,因此,某些总结出来的“指界词”(左指界词或右指界词)也可以作为特征。

特征函数确定以后,剩下的工作就是训练CRF模型参数λ。

大量的实验表明,在人名、地名、组织机构名三类实体中,组织机构名识别的性能最低。一般情况下,英语和汉语人名识别的F值都可以达到90%左右,而组织机构名识别的F值一般都在85%左右,这也反映出组织机构名是最难识别的一种命名实体。当然,对于不同领域和不同类型的文本,测试性能会有较大的差异。

基于多特征的命名实体识别方法、专家知识的评测结果

混合模型的人名、地名、机构名识别性能(F-测度值)比单独使用词形特征模型时的性能分别提高了约5.4%,1.4%,2.2%,比单独使用词性特征模型时分别提高了约0.4%,2.7%,11.1%。也就是说,结合词形和词性特征的命名实体识别模型优于使用单一特征的命名实体识别模型。另外,实验还表明,结合了专家知识的统计模型对人名、地名和机构名的识别能力(F-测度值)与纯统计模型相比,分别提高了约14.8%,9.8%,13.8%,而且,系统的识别速度也有所提高。

上述结果表明,基于多特征模型的命名实体识别方法综合运用了词形特征和词性特征的作用,针对不同实体的结构特点,分别建立实体识别模型,并利用专家知识限制明显不合理的实体候选的产生,从而提高了识别性能和系统效率。

SVM和最大熵相结合的中文机构名自动识别

这篇论文针对未登录词的识别提出了一种支持向量机(Support Vector Machine,SVM)和最大熵相结合的自动识别方法。它将中文机构名识别范围限定在以机构名特征词为结尾的完整机构名,根据机构名的特点,将机构名识别分为两个部分:后界判断和前部标注。对文本中出现在特征词典的词基于SVM判断是否是机构名特征词(后界判断),从识别出的机构名特征词前词开始向前基于最大熵标注,直到标注到非机构名成分停止标注(前部标注)

后界判断问题是二值分类问题,而SVM是一种优秀的二值分类器,因此基于SVM的后界判断模型可以有效地解决机构名特征词识别问题。根据机构名特征词的统计分析和语法特征,建立基于SVM的后界判断模型。机构名前部词组成比较复杂,由于最大熵可以灵活地将许多分散,零碎的知识组合起来。

中文名识别

由于在项目中主要考虑使用字典配合规则的方法进行已登录的中文人名/机构的命名实体识别,所以收集的算法多为非深度学习,以及已有较为成熟的模型的算法。

盘古分词中的算法

盘古分词中作者另辟它径,采用一种新的算法,对要分解的句子按预处理和消除歧义两个步骤进行处理,识别中文人名的效果相比规则和统计方式要好很多。与其他较为成熟的算法相比,盘古分词算法的缺点为不能识别人名的词根词缀,但它十分简洁易懂。

预处理

识别中文人名的第一步是进行预处理,预处理的过程是找出要识别的句子中所有可能的中文人名。查找的方式是首先根据姓氏来匹配,找到姓氏后再根据常见的单字中文名和双字中文名来匹配。盘古分词字典目录下有三个文件分别是 ChsSingleName.txtChsDoubleName1.txtChsDoubleName2.txt,它们分别表示单字人名,双字人名的首字和双字人名的尾字,根据这三个文件中指定的常用中文名,我们可以完成预处理的过程。

张三丰 李世民

其中 “张”、“李”是姓,“三”是常用单字名和常用双字名首字,“世”是常用双字名首字,“民”和“丰”是常用双字名尾字

这样预处理的结果就是

张三
张三丰
李世民

消除歧义

由于汉语非常复杂,预处理完了以后,还存在歧义的问题。比如“张三说的确实在理”和“李三买了一张三角桌子”这两句话中都包括“张三”这个词,但第一句话中张三是人名,第二句话则不是。

所以要提高中文人名的识别率,消除歧义是关键的一步。

eaglet给出的办法是将第一步预处理出来的中文人名和字典中匹配的所有词全部输出出来,然后找到词和词之间空隙最小且分出来的词最少的那种组合。

拿“李三买了一张三角桌子”这句话来举例,在字典中我们分解出如下的词:

三   买   了   一张   张   三角   三   桌子   子  

再加上之前预处理找到的人名李三和张三,最后分解出下面这些词:

李三    三   买   了   一张   张三   张   三角   三   桌子   子  

这时候我们再对这些词进行组合,组合的规则是在一组词中不能有交错的词出现,比如“一张”和“张三”就不能出现在一组词中。组合完后,根据我上面说的规则排序,找到最匹配的组合。我们可以看看最匹配的组合是:

李三/买/了/一张/三角/桌子/

这个组合词和词之间没有间隙,即间隙为0,分出的单词数为6

如果把“张三”作为一个词分出来,其组合为:

李三/买/了/ /张三/ /桌子/

这个组合由于“张”前面的“一”和后面的“角”在字典中没有,所以间隙为1+1=2,其没有前面的最佳组合间隙小,所以我们不取这个组合。如果我们在字典中加入了“一” 和 “角”这两个词,是不是就会分错呢?答案是否定的。因为加入“一” 和 “角”这两个词后,如果要把“张三”作为一个词分出来,其组合为:

李三/买/了/一/张三/角/桌子/

这时间隙为0不错,但分出来的单词数为7,大于前面的最佳组合,所以这个组合还是会被忽略掉。

总结

算法在中文人名的识别上比盘古之前采用的方法有了很大的进步,但并不是万能的。首先,人名字典不可能涵盖所有的人名,这会导致一些不太常见的人名无法被分出来;其次,对于一些只有人名没有姓的情况,这种方面目前也无法识别;再次,由于双字人名被分为首字和尾字分别存储,这样虽然增加了组合的数量,但也难免会组合出一些非人名的情况。

基于词典的实体识别

词典和模型方式结合,词典负责已有词识别,模型负责未知词识别。这种方法在不需发现未知词的情况下基于词典的实体识别已足够,具体做法有“字符串多模匹配”和“切词”(词典加入自定义词库)

两种方式各有千秋,这里考虑将两种方式结合使用:先最长匹配,然后将取出的实体放回切词结果看是否“完整”,注意不用再将词典放入切词工具的自定义词库。

  • 怎么判断“完整”:如果最长匹配得到的词开始位置的字在切词结果中不与前一个字组成词 且 结束位置的字在切词结果中不与后一个字组成词,则认为“完整”
  • 举例:最长匹配得到“国航”,切词上下文“中国 航展“,说明”国航“不“完整”;最长匹配得到“南国置业”,切词上下文“昨天 南国 置业 发布”,说明“南国置业” “完整”

该结合算法的实验结果表明:可以将准确率提升到近100%(评测的500项数据里没有发现提取错误的),而且没有占用更多内存,很适合拥有大规模词典的

另外,当最长匹配提取的词较长时,无匹配的情况极少了,对这种长词可以不用放回切词结果验证。

jcseg中文姓名识别算法

jcseg的姓名识别算法很简单,但是从实际效益来看,确实达到了预期的效果:中文人名识别正确率达94%以上,中文人名可以维护lex-lname.lexlex-dname-1.lexlex-dname-2.lex来提高准确率,引入规则和词性后会达到98%以上的识别正确率。其中,消歧算法的讲解十分细致。

首先说明:jcseg使用的不是机械匹配中文姓名(虽然词库里面有一些人名),本人觉得这样太机械了,这么的中文姓名不可能都存词库。

姓名识别过程:

  1. 先确认整个chunk的长度(词语的个数)大于1,并且这个chunk的第一个词长度(字的个数)小于等于2。(大于2那就没必要分析了,说明是从词库里面匹配的结果,而一个中文姓氏最长为2,当然是指汉族)

  2. 判断是否满足中文姓名查找条件:

    1. 中文姓氏确认

      获取word的值:w.getValue()返回词的字符串表示形式,去姓氏词库里面查找(ILexicon.CN_LNAME,表示姓氏词库,词库文件为:lex-lname.lex,包含中文姓名中所有单复姓氏),确认w是否为一个中文姓氏,这是姓名查找最基本的要求吧。(记得有双字姓氏哦,所以“诸葛亮”可以识别出来)

    2. 姓氏修饰词确认(姓氏修饰词库lex-ln-adorn.lex

      获取word的值:w.getValue()返回词的字符串表示形式,去姓氏修饰词库里面查找(ILexicon.CN_LNAME_ADORN,表示姓氏修饰词库),确认w是否为一个中文姓氏修饰词。

  3. 姓名查找:

    满足姓名查找条件(满足上述中一个就可以了),就可以开始查找姓名了,由:findCHName(chars, 0, chunk)这个方法来实现。

    主要思路为:(需要根据chunk的词数和词长分情况分析,这里笼统的概述下)

    1. 查看是否满足双姓名的要求(很简单,加上姓氏至少需要三个字吧)

      -> 确认是否为双姓名,查看姓氏后的第一个词是否为双姓名首字(词库:lex-dname-1.lex保存了所有可能做双姓名的首字的单字)

    2. 如果不是双姓名,则看看是否为单姓名:

      -> 先确认姓氏后的第一个词是否为单字姓名词库(lex-sname.lex)中的词。
      -> 如果是,在确认姓氏后的第二个词的“成词自由语素度”是否满足要求(通常情况下,姓名都和哪些“成词自由语素度”很高的词在一起,而且姓名中的词“自由语素度”都偏低,这个假设得到了统计的验证)。可以更改jcseg.properties配置文件中的阈值Config.NANE_SINGLE_THRESHOLD实现自主更改。

  4. 歧义分析(姓名中的词和周围的词成词的情况)

    1. 双姓名:

      -> 双字姓名中,首字和尾字成词的情况,例如:“陈美丽是对的”

      chunk: 陈_美丽_是(美丽成词)

      这个jcseg是基于姓名周围的单字“成词自由语素度”偏高的情况,来去除歧义的。也就是查看最后一个词的最后一个字的“语素自由度“和Config.NANE_SINGLE_THRESHOLD对比结果。

      -> 双字姓名中,尾字和后面的词成词的情况,例如:“这本书是陈志高的”,“ 陈美丽的人生”

      chunk:陈_志_高的

      chunk:陈_美丽的_人生

      同上一解决办法一样。

    2. 单姓名:

    ​ -> 尾字和其后的一个字成词的情况:例如:"这本书是陈高的"

    ​ chunk:陈_高的 (single name)

    ​ 通过查看“自由语素度”可以去除歧义。

    1. 不知是“单字姓名”还是”双字姓名“的情况:

      -> chunk的词数为3,但是中间这个词的字数为1的情况。

      例如:“ 陈志高兴奋极了”,“陈高兴奋极了”,“陈志高的”

      chunk:陈_志_高兴 (兴和后面成词)

      chunk:陈_高_兴奋 (single name)

      chunk:陈_志_高的

      同时这也是这个算法的最麻烦的部分之一,按照上述过程这个姓名到底是”陈高“这个单字姓名还是“陈高兴”这个双子姓名呢?正确的结果我们都知道。

      jcseg是通过在此位置再向后取一个chunk来分析去除歧义的。

      基于这样的一个情况,如果最后一个词语(高兴,兴奋,高的)中的“兴,奋,的”和后面的词成词,并且这个词的首字,("高", “兴”, “高”)又是lex-double-2.lex(双字姓名的尾字词库)中的词,则认为是双字姓名,如果不成词,并且这些词的“自由语素度”偏高则,认为为单字姓名,如果“自由语素度”偏高本身就可以成词,至少可以达到统计的切分效果。

  • 另外还有一种情况是jcseg目前没有处理的,就是双字姓名中的姓氏和双字姓名的首字成词的情况:

    例如:“我很喜欢陈述高的演讲,我很不喜欢陈述高调的样子。”

    其中,第一个名字“陈述高”中“陈述”成词,但是第二个不成词。目前我见过的所有支持中文姓名识别的分词系统中,没有一个可以正确识别的,包括“哈尔滨工程学院”的NLP系统,都识别成:“陈述”。本文的第一断代码中有一块注释就是用来处理这种情况的,但是反而带来了更多的负面影响,很不成熟,所以我注释掉了。

总结

jcseg姓名识别歧义:

  1. 多个姓氏排在一起的情况就会出问题

    例如:“向林俊德同志表示问候”中的向和林都是姓氏,jcseg目前处理这种情况会出问题。(目前我吧“向”这个姓氏在词库中注释掉了)。

  2. 姓氏用作非姓氏的情况

    例如:心血和智慧,中的“和”是姓氏词,但是在这个地方不是用作姓氏。导致分词结果为:心血|和智慧 (目前我吧“和”这个姓氏在词库中注释掉了)。

这些问题会可能会在jcseg 1.7.2版本中解决。那么jcseg的姓名识别正确率可以达到94%以上。目前我通过使用人名日报的新闻进行姓名识别,有90%以上的正确率。

HENU汉语分词系统中的中文人名识别算法

这个方法只对词典里有的姓+名组合有效,并且要求姓名必须是多个单字,如果名字可以跟后面的词组成词语,就不能被识别出来。

同姓异名对的冲突处理

在排除潜在人名冲突的过程中,最不易处理的是同姓异名对的冲突。所谓同姓异名对,指的是有着相同起点,但终点不同 的两个潜在人名。具体地说,就是指以同一个切分单位一“姓氏”为起点。而终点分别落在“姓氏”后的第一个或第二个切分单位的两个潜在姓名。像这样含有重合部分的潜在姓名对是不可能同时成立的。通常利用右边界否定规则可以解决此类冲突,即同姓异名对中有一个姓名的右边界确定,则否定另一个姓名。

例如:“县委书记赵志祥出席了晚会”,在分词之后“赵志祥”会被作为三个孤立字处理,由“赵”字姓氏触发,进行中文人 名的识别,就会产生“赵志”和“赵志祥”这样一个同姓异名对,但在“赵志祥”之后有右边界动词“出席”,则由右边界词否定规则将潜在人名“赵志”否定。然而在大多数语句中,姓名之后并没有右边界词,本算法对这类同姓异名对的冲突主要通过计算并比较这两个潜在姓名的概率值,以及在适当的情形下利用局部回溯分词校验的方法来解决的。

局部回溯分词

本算法中所谓的局部回溯分词,指的是初次分词后,算法识别出无法使用边界、概率否定规则排除的同姓异名对冲突,从而利用在一个小范围内重新切分语义不确定的部分句子的方法,以区分同姓异名对中两个潜在人名的真实性,以使算法对中文人名识别的准确率和召回率得到显著提高。

其具体方法是:当中文人名识别过程中发现有不能用规则排除的同姓异名对冲突时,对其中长度较长,且包含状态不确定的切分单位的潜在人名进行局部回溯分词,以检测确定其在当前句中是否能构成人名,从而与另一潜在人名比较选定某一个作为识别出的中文人名。

例如:“韩宁为此沾沾自喜。”,分词之后的同姓异名对为“韩宁”和“韩宁为”,无边界规则可利用,且“为”还可能与“此” 结合,有不同的切分状态。故将长度较长的潜在姓名“韩宁为”进行局部回溯分词。在“为”和“此”这个小范围内重新切分,并检测到“为此”在本句中没有其他切分可能,即据此否定“韩宁为”,将潜在人名“韩宁”识别出来。

基于支持向量机的中国人名的自动识别

直接用SVM进行二分判断,对训练文本进行自动分词、词性标注及分类标注,然后按字抽取特征,并将其转化为二进制表示,在此基础上建立了训练集。然后通过对多项式Kernel函数的测试,得到了用支持向量机进行人名识别的机器学习模型,实验结果表明,所建立的SVM人名识别模型是有效的。

基于可信度模型的中文人名识别研究

该文根据中国人名的形成方式,总结和统计了人名的用字特征和边界模板特征,提出了一种可信度模型的计算方式:通过计算人名内聚度、人名区分度和边界模板可信度的综合概率作为人名可信度,对文本中人名进行识别或对已识别的人名进行纠正。

原文地址:https://www.cnblogs.com/winng/p/nlp_ner.html