在看源码之前,先看几遍论文《基于角色标注的中国人名自动识别研究》
关于命名识别的一些问题,可参考下列一些issue:
<!--[if !supportLists]-->u <!--[endif]-->u名字识别的问题 #387
<!--[if !supportLists]-->u <!--[endif]-->u机构名识别错误
<!--[if !supportLists]-->u <!--[endif]-->u关于层叠HMM中文实体识别的过程
HanLP参考博客:
词性标注
层叠HMM-Viterbi角色标注模型下的机构名识别
分词
在HMM与分词、词性标注、命名实体识别中说:
分词:给定一个字的序列,找出最可能的标签序列(断句符号:[词尾]或[非词尾]构成的序列)。结巴分词目前就是利用BMES标签来分词的,B(开头),M(中间),E(结尾),S(独立成词)
分词也是采用了维特比算法的动态规划性质求解的,具体可参考:文本挖掘的分词原理
角色观察
以“唱首张学友的歌情已逝”为例,
先将起始顶点 始##始,角色标注为:NR.A 和 NR.K,频次默认为1
对于第一个词“唱首”,它不存在于 nr.txt中,EnumItem<NR> nrEnumItem = PersonDictionary.dictionary.get(vertex.realWord);返回null,于是根据它本身的词性猜一个角色标注:
由于"唱首"的Attribute为 nz 16,不是nr 和 nnt,故默认给它指定一个角色NR.A,频率为nr.tr.txt中 NR.A 角色的总频率。
此时,角色列表如下:
接下来是顶点“张”,由于“张”在nr.txt中,因此PersonDictionary.dictionary.get(vertex.realWord)返回EnumItem对象,直接将它加入到角色列表中:
加入“张”之后的角色列表如下:
“唱首张学友的歌情已逝” 整句的角色列表如下:
至此,角色观察 部分 就完成了。
总结一下,对句子进行角色观察,首先是通过分词算法将句子分成若干个词,然后对每个词查询人名词典(PersonDictionary)。
<!--[if !supportLists]-->u <!--[endif]-->若这个词在人名词典中(nr.txt),则记录该词的角色,所有的角色在com.hankcs.hanlp.corpus.tag.NR.java中定义。
<!--[if !supportLists]-->u <!--[endif]-->若这个词不在人名词典中,则根据该词的Attribute “猜一个角色”。在猜的过程中,有些词在核心词典中可能已经标注为nr或者nnt了,这时会做分裂处理。其他情况下则是将这个词标上NR.A角色,频率为 NR.A 在转移矩阵中的总词频。
维特比算法(动态规划)求解最优路径
在上图中,给每个词都打上了角色标记,可以看出,一个词可以有多个标记。而我们需要将这些词选择一条路径最短的角色路径。参考隐马尔可夫模型维特比算法详解
List<NR> nrList = viterbiComputeSimply(roleTagList);//some code....return Viterbi.computeEnumSimply(roleTagList, PersonDictionary.transformMatrixDictionary);
而这个过程,其实就是:维特比算法解码隐藏状态序列。在这里,五元组是:
<!--[if !supportLists]-->u <!--[endif]-->隐藏状态集合 com.hankcs.hanlp.corpus.tag.NR.java 定义的各个人名标签
<!--[if !supportLists]-->u <!--[endif]-->观察状态集合 已经分好词的各个tagList中元素(相当于分词结果)
<!--[if !supportLists]-->u <!--[endif]-->转移概率矩阵 由 nr.tr.txt 文件生成得到。具体可参考:
<!--[if !supportLists]-->u <!--[endif]-->发射概率 某个人名标签(隐藏状态)出现的次数 除以 所有标签出现的总次数
Math.log((item.getFrequency(cur) + 1e-8) / transformMatrixDictionary.getTotalFrequency(cur)
<!--[if !supportLists]-->u <!--[endif]-->初始状态(始##始) 和 结束状态(末##末)
维特比解码隐藏状态的动态规划求解核心代码如下:
for (E cur : item.labelMap.keySet())
{
double now = transformMatrixDictionary.transititon_probability[pre.ordinal()][cur.ordinal()] - Math.log((item.getFrequency(cur) + 1e-8) / transformMatrixDictionary.getTotalFrequency(cur));
if (perfect_cost > now)
{
perfect_cost = now;
perfect_tag = cur;
}
}
transformMatrixDictionary.transititon_probability[pre.ordinal()][cur.ordinal()] 是前一个隐藏状态 pre.ordinal()转换到当前隐藏状态cur.ordinal()的转移概率。Math.log((item.getFrequency(cur) + 1e-8) / transformMatrixDictionary.getTotalFrequency(cur)是当前隐藏状态的发射概率。二者“相减”得到一个概率 保存在double now变量中,然后通过 for 循环找出 当前观察状态 对应的 最可能的(perfect_cost最小) 隐藏状态 perfect_tag。
至于为什么是上面那个公式来计算转移概率和发射概率,可参考论文:《基于角色标注的中国人名自动识别研究》
在上面例子中,得到的最优隐藏状态序列(最优路径)K->A->K->Z->L->E->A->A 如下:
nrList = {LinkedList@1065} size = 8
"K" 始##始
"A" 唱首
"K" 张
"Z" 学友
"L" 的
"E" 歌
"A" 情已逝
"A" 末##末
例如:
隐藏状态---观察状态
"K"----------始##始
最大匹配
有了最优隐藏序列:KAKZLEAA,接下来就是:后续的“最大匹配处理”了。
PersonDictionary.parsePattern(nrList, pWordSegResult, wordNetOptimum, wordNetAll);
在最大匹配之前,会进行“模式拆分”。在com.hankcs.hanlp.corpus.tag.NR.java 定义了隐藏状态的具体含义。比如说,若最优隐藏序列中 存在 'U' 或者 'V',
U Ppf 人名的上文和姓成词 这里【有关】天培的壮烈
V Pnw 三字人名的末字和下文成词 龚学平等领导, 邓颖【超生】前
则会做“拆分处理”
switch(nr)
{
case U:
//拆分成K B
case V:
//视情况拆分
}
拆分完成之后,重新得到一个新的隐藏序列(模式)
String pattern = sbPattern.toString();
接下来,就用AC自动机进行最大模式匹配了,并将匹配的结果存储到“最优词网”中。当然,在这里就可以自定义一些针对特定应用的 识别处理规则
trie.parseText(pattern, new AhoCorasickDoubleArrayTrie.IHit<NRPattern>(){
//.....
wordNetOptimum.insert(offset, new Vertex(Predefine.TAG_PEOPLE, name, ATTRIBUTE, WORD_ID), wordNetAll);
}
将识别出来的人名保存到最优词网后,再基于最优词网调用一次维特比分词算法,得到最终的分词结果---细分结果。
if (wordNetOptimum.size() != preSize)
{
vertexList = viterbi(wordNetOptimum);
if (HanLP.Config.DEBUG)
{
System.out.printf("细分词网:\n%s\n", wordNetOptimum);
}
}
总结
源码上的人名识别基本上是按照论文中的内容来实现的。对于一个给定的句子,先进行下面三大步骤处理:
角色观察
维特比算法解码求解隐藏状态(求解各个分词 的 角色标记)
对角色标记进行最大匹配(可做一些后处理操作)
最后,再使用维特比算法进行一次分词,得到细分结果,即为最后的识别结果。
这篇文章里面没有写维特比分词算法的详细过程,以及转移矩阵的生成过程,以后有时间再补上。看源码,对隐马模型的理解又加深了一点,感受到了理论的东西如何用代码一步步来实现。由于我也是初学,对源码的理解不够深入或者存在一些偏差,欢迎批评指正。
关于动态规划的一个简单示例,可参考:动态规划之Fib数列类问题应用
文章来源hapjin 的博客
相关推荐
由于中文人名构成复杂,规律多样,其识别成为了中文分词及句法分析中的重点和难点。葛文英等人(2010)的研究聚焦于利用条件随机场(CRF)这一统计机器学习方法,针对中文人名识别进行了深入探讨,并在第四届Bakeoff...
本文将详细探讨InfoExtra人名识别系统,它利用了CocoNLP库中的InfoExtra.py以及其他相关程序,如Hanlp.py、Corgi_Demo.py和CorgiHMM.py,旨在高效准确地从文本中提取出人名信息。 人名识别,也称为命名实体识别...
中文人名识别是自然语言处理领域中的一个重要子任务,它涉及到中文文本的理解和分析。在这个过程中,系统需要能够准确地定位和识别出文本中的人名,这对于信息提取、搜索引擎优化、社交媒体监控以及机器翻译等应用至...
藏文人名识别是自然语言处理领域中的一个重要任务,它涉及到藏文文本的结构化表示和信息抽取。本文主要探讨了使用深度学习技术来解决这一问题。深度学习模型的优势在于其能够自动学习特征,减少了传统机器学习方法中...
3. **命名实体识别**:在信息抽取、情感分析等场景中,识别出人名、地名、组织名等实体对于理解文档内容非常关键。 4. **依存句法分析**:分析句子的语法结构,帮助构建更精准的查询语句,提高检索效果。 总的来说...
### 中文人名自动识别的有效方法 #### 一、引言 中文信息处理技术发展至今已有数十年的历史,但仍存在不少未解决的技术难题。其中,中文姓名自动识别问题尤为突出,因为它不仅涉及到基础的文本处理技术,还直接...
在IT领域,实体提取是一项重要的自然语言处理任务,主要用于从文本中识别出具有特定意义的信息,如人名、地点、时间等。在这个场景中,我们关注的是如何利用Java语言和HanLP分词库来实现从网络片段中抽取省份和城市...
**Elasticsearch与HanLP中文插件详解** 在搜索引擎领域,Elasticsearch(简称ES)是一种广泛使用的开源全文检索引擎,它基于Lucene构建,提供分布式、RESTful接口以及实时数据分析能力。为了更好地支持中文处理,...
本文探讨的是基于深度学习和指代消解的中文人名识别技术在自然语言处理(NLP)中的应用。命名实体识别(NER)是NLP中的关键任务,旨在准确地识别文本中的特定实体,如人名。人名识别在各种信息资源中至关重要,但...
在命名实体识别方面,HanLP支持人名、地名、机构名等多种实体类型,这对于信息抽取和知识图谱构建非常重要。 其次,`data-for-1.7.2.zip`包含的是模型数据,这是HanLP进行高效准确处理的前提。这些模型通常经过大...
3. **命名实体识别**:HanLP可以识别文本中的专有名词,如人名、地名、机构名等,这在信息抽取、问答系统和搜索引擎优化等领域有着广泛的应用。 4. **情感分析**:通过对文本的情感色彩分析,HanLP可以判断用户的...
本资源包含使用CRF++工具进行人名识别的所有资源,包括: 1.CRF++工具 2.语料库、程序、文档、实验结果等 2.1 语料库 2.2 语料库划分后的训练集、测试集 2.3 训练集,测试集进行处理后的结果 2.4 crf_learn用到...
中国人名识别 音译人名识别 日本人名识别 地名识别 实体机构名识别 关键词提取 TextRank关键词提取 自动摘要 TextRank自动摘要 短语提取 基于互信息和左右信息熵的短语提取 拼音转换 多音字 声母 韵母 声调 简繁转换...
中文分词器jcseg支持人名识别mmseg四种过滤算法分词准确率达到了97%以上。支持自定义词库。在lexicon文件夹下可以随便添加删除更改词库和词库内容并且对词库进行了分类.zip,太多无法一一验证是否可用,程序如果跑不...
未登录词识别是中文词法分析中的一个主要难点,中国人名在未登录词中占有较大比重。为了解决这个问题,本文提出了一种基于N最短路径方法的中文词语粗分模型,通过对中文文本进行粗切分,然后采用Viterbi算法对切分...
3. **命名实体识别**:HanLP可以识别文本中的专有名词,如人名、地名、机构名等。训练数据会包含实体及其类型,帮助模型学习识别这些特定实体的能力。 4. **依存句法分析**:HanLP通过构建词语间的依存关系来解析...
HanLP是一系列模型与算法组成的NLP工具包,由大快搜索主导并完全开源,目标是普及自然语言处理在生产环境中的应用.HanLP具备功能完善,性能高效,架构清晰,语料时新,可自定义的特点。 HanLP提供下列功能: 中文...