这几天写完了人名识别模块,与分词放到一起形成了两层隐马模型。虽然在算法或模型上没有什么新意,但是胜在训练语料比较新,对质量把关比较严,实测效果很满意。比如这句真实的新闻“签约仪式前,秦光荣、
这是我将自己的分词与ansj作比较得出的结果,由于自己可以随时调整算法,所以主场占了很大便宜。但是第一句绝对没有放水,说实话能识别出“仇和”这么冷僻的名字着实让我惊喜了一下。
开源项目
本文代码已集成到HanLP中开源:http://www.hankcs.com/nlp/hanlp.html
原理
推荐仔细阅读《基于角色标注的中国人名自动识别研究.doc》这篇论文,该论文详细地描述了算法原理和实现。从语料库的整理、标注到最后的模式匹配都讲得清清楚楚。我在这篇论文的基础上做了改进,主要步骤我总结如下:
1、对熟语料库自动标注,将原来的标注转化为角色标注。角色标注一共有如下几种:
编码 |
代码 |
意义 |
例子 |
B |
Pf |
姓氏 |
张华平先生 |
C |
Pm |
双名的首字 |
张华平先生 |
D |
Pt |
双名的末字 |
张华平先生 |
E |
Ps |
单名 |
张浩说:“我是一个好人” |
F |
Ppf |
前缀 |
老刘、小李 |
G |
Plf |
后缀 |
王总、刘老、肖氏、吴妈、叶帅 |
K |
Pp |
人名的上文 |
又来到于洪洋的家。 |
L |
Pn |
人名的下文 |
新华社记者黄文摄 |
M |
Ppn |
两个中国人名之间的成分 |
编剧邵钧林和稽道青说 |
U |
Ppf |
人名的上文和姓成词 |
这里有关天培的壮烈 |
V |
Pnw |
人名的末字和下文成词 |
龚学平等领导, 邓颖超生前 |
X |
Pfm |
姓与双名的首字成词 |
王国维、 |
Y |
Pfs |
姓与单名成词 |
高峰、汪洋 |
Z |
Pmt |
双名本身成词 |
张朝阳 |
A |
Po |
以上之外其他的角色 |
表1 中国人名的构成角色表
我在此基础上拓展了一个S,代表句子的开始。
2、统计标签的出现频次,标签的转移矩阵。
3、对粗分结果角色标注,模式匹配。
我对论文中的几个模式串做了拓充,并且采用了AC模式匹配算法。
体会
论文中将三字名称拆分为BCD,我实测在2-gram模型下,C很容易被识别为E,导致人名缺一半。
人民日报2014中的人名并不能覆盖所有常用字,所以我去别的地方找了个人名库,拆成BCD或BE补充了进去。
人民日报2014语料库中有很多错误,比如
去/vf 年老/vi 张中秋/nr 去/vf “/w 泡茶/vi ”/w ,/w 送礼/vi 遭到/v 了/ule 拒绝/v ,/w 老张/nz 担心/v 金额/n 不够/a
中秋很明显不是人名的组成部分,这个必须手工剔除。
“中秋安全”会识别出“中 秋安全”来,因为2-gram词典中没有“中秋@安全”这种接续,而有“中@未##人”这种接续。初步的解决方法是手工往2-gram词典里面加一条“中秋@安全”。这反映了这种方法的局限性,另一方面也说明词典的重要性。
博主 你好,你只是训练了分词模型,对吗,实体识别只是在分词的基础上用veterbi
博主你好,在做人名识别的时候,发现复姓人名识别不是很准确,比如:欧阳娜娜借了长孙无忌三块钱,识别为:[欧阳/nz, 娜娜/nz, 借/v, 了/ule, 长/a, 孙无忌/nr, 三/m, 块钱/q],复姓人名识别该如何优化,请指点一二,不胜感激。
博主你好,最近在用HanLP做人名识别,发现当三字人名中的前两个字也是一个人名时,识别不出来三字人名。例如:证明原告孙辉与被告姚宏旭之间的借款关系。识别为:[证明/v, 原告/n, 孙辉/nr, 与/p, 被告/n, 姚宏/nr, 旭/nr, 之间/f, 的/uj, 借款/n, 关系/n]
姚宏旭被拆开了,怎么处理下呢?
nShortSegment.seg可以用这个试一下
博主你好,为什么我直接跑 DemoChineseNameRecognition.java 跑出来的人名都是 /nz呢?
博主,您好,我想咨询下,在训练转移概率的时候。XYZA怎么标识。比如王/B 国/C 维/D。那其他位置的王国/X。如果这样,康复 X 2 L 1这种只是优先统计出来,并不是角色语料中统计出来的吗?
博主,您好。我目前尝试自定义一个人物关系词典作追加词典,然后用hanlp的词性标注功能将关系词识别出来。但是结果不理想。例如,实验结果还是将“丈夫”识别为n,而不是自定义词典中我自己定义的词性,似乎自定义词典并没有起到作用?请问这个问题要怎么解决?谢谢!
楼主,您好,我想问您人名、地名、机构名由普通词类标注转成角色标注的代码在哪里?
楼主你好,我再用HanLP进行命名实体识别时,效果感觉不太好,远远低于我的预期,尤其是人名识别和机构名识别。我采用的语料主要集中在汽车行业。如果对于机构名识别效果差的话,我还能从测试语料与训练语料的差异上给出解释,但是对于人名识别,感觉比较难以理解。 比如 “都带长”,“都一处”,"那就来","方是为",咋一看感觉都是基于一些姓得到的。
感谢反馈,暂时的办法是用黑名单,长远的改进还在探索中。
你好,我想识别出这句话中的人名“卢凡”,参考你的说明我添加在“data\dictionary\person\nrf.txt”中,并删除“data\dictionary\person\nrf.txt.trie.dat”,可是还是不能识别出“卢凡是先进事迹报告团的成员。”中的“卢凡”呢?
几个词典我都试了,好像只有加到data\dictionary\CoreNatureDictionary.txt才有效果?
有关天培养的猪,这句话也识别不了[嘻嘻]
测试了一个问题例子,反馈一下。可能是核心词典缺少工号之类的词。
“谭彬林工号,杨军工号,陆江工号,姚曼青工号,”
博主,请问在通过维特比算法进行人名角色序列判断时,为何在前向计算的过程中即可以判断角色,而不是在回溯路径的时候判断角色
你还没理解,回溯是最短路算法的术语。
博主,请问root目录必须是绝对路径吗?我用的是 web项目怎么写相对路径,能给个实例吗?thank you!
File file=new File(“.”);
String path=file.getAbsolutePath();
根据这个path配相对路径就行了。
博主你好!你的标准分词利用了用户词典,而用户词典中很多是实体,导致分词时有好多单词组合在一起成为实体了,这样会不会不符合分词标准啊?
你好,没有绝对的标准,你觉得不标准可以关掉|修改用户词典,我只提供工具,不提供标准。
博主,我自己定义的人名应该加到哪个词典里才能在分词的时候直接分出来。
比如:“毛瑞斯莫曾在2006年夺得了澳网和温网的女单冠军” 这句话,分词结果是:“[毛/n, 瑞斯莫/nrf, 曾/d, 在/p, 2006/m, 年/qt, 夺得/v, 了/ule, 澳网/n, 和/cc, 温网/nz, 的/ude1, 女单/n, 冠军/nnt]”。
我想让“毛瑞斯莫” 做为一个人名分割出来,应该怎么做?多谢博主了
data/dictionary/person/nrf.txt即可。
博主,我这样加了还是不行?
https://github.com/hankcs/HanLP#储存形式
非常感谢博主,我最后是加在datadictionaryCoreNatureDictionary.txt中,并且删除缓存后使用的。着急用,没仔细看原理。多谢!
博主你好,想请教一个小问题。多层隐马模型,若将人民识别放在第二层,那第二层的输入依赖于第一层的输出,此时语料库作为训练集,是不是需要经过第一层后再做标识?
对,在粗分的基础上标注。
请教博主:“人民日报2014语料库”是个怎样的语料库,好像只听说过1998的人民日报语料库。难道又有人大规模标注了2014年人民日报?这可是个大事,要花很多人力物力的。请博主指教,谢谢!
有,不过我没有得到授权,请参考:https://github.com/hankcs/HanLP/wiki/%E8%AE%AD%E7%BB%83%E5%88%86%E8%AF%8D%E6%A8%A1%E5%9E%8B#%E8%AF%AD%E6%96%99%E6%A0%BC%E5%BC%8F
博主你好,最近在拜读你的HanLP代码,在阅读人名识别这部分的代码时,有一个疑问:PersonRecognition中的Recognition在求最优标签序列时调用了viterbiExCompute,viterbiExCompute又调用了Viterbi.computeEnumSimply,但computeEnumSimply我看了一下应该是贪心算法,不是维特比,不知道是不是这里是个bug还是故意为之?烦请解答,谢谢!
你好,是为了效率才这么做的,去掉simply就是标准版的维特比。
你好,是为了效率才这么做的,去掉simply就是标准版的维特比。
哦,是这样啊,那从效果上来说两者差距并不大咯?
是的,主观上看是这样的
好的,非常感谢!
博主你好,我在在阅读HanLP的人名识别这部分代码时发现了一个问题,Viterbi.java中的computeEnumSimply应该是贪心算法吧,而不是维特比?
你好,是为了效率才这么做的,去掉simply就是标准版的维特比。
博主,你好,请问2gram词典是干嘛用的?
在序列标注模型中并无用处。
博主,你好,我有一个疑问,观测状态为文本里面的词,隐含状态为角色序列。HMM的参数统计出来,即模型确定后。如果来了一个新的文本进行veterbi求解,而该文本里面有新的词,即新的观测状态,请问怎么标记?谢谢
新的词只能置为A,代表非人名成分。这也是HMM的缺陷,没有太大的泛化能力。
不知道是我想错了还是你写错了,请大神指点
你好,在你的PersonDictionary.java中我个人觉得发现了一个bug,就是在parsePattern这函数中,对V这个进行拆分时,感觉你拆分代码不对,个人觉得应该是这样的:listIterator.previous();
String nowED = current.realWord.substring(0,1);
String nowL = current.realWord.substring(1);
listIterator.set(new Vertex(nowED));
listIterator.next();
listIterator.add(new Vertex(nowL));
这样不对,标签并不是这样定义的,你可以试试 龚学平等领导说 。