介绍一种基于角色标注+字词体位法的人名识别方式-Ansj中文分词
大家好.最近在做分词.在分词中遇到了各种各样的问题.在这里选择一个比较有意思的与大家分享.
在这里说分词有点老生常谈了.的确.中文分词已经非常成熟了.但是在实体名识别上一直是中文分词的软肋.最近通过对ictclas的学习,和自己的总结.得出了一个还算不错的人名识别系统.
目前这种方式已经开源.大家可以参看:https://github.com/ansjsun/ansj_seg , 在线测试:http://www.ansj.org/demo/seg.jsp
主要思路是..先粗分,粗分的办法很多.但是在粗分的时候要尽量减少歧异.
比如
祝海林在孙健的右面!进过第一步粗分的结果应当为祝/ 海/ 林/ 在/ 孙/ 健/ 的/ 右面/
孙强朱海林孙海林祝健....
孙 2:1:1 \\戴表 孙 这个字在 2个词中的第1个位置出现了1次孙 3:1:1强 2:2:1朱 3:1:1海 3:2:2,,,
public void recogntion(Term[] terms) {for (int i = 0; i < terms.length; i++) { //已名识别从前向后进行识别,4个字,3个字2字人名分别识别for (int j = 4; j > 1; j--) {freq = term.getTermNatures().personAttr.getFreq(j, 0);\\取得词位频率if ((freq > 0) ) {//进行初始化校验.当此字在识别位置出现时tempTerm = nameFind(i, beginFreq, j);//以序列结构进行人名识别}}}}public Term nameFnd(int i , int beginFreq , j){StringBuilder sb = new StringBuilder();int undefinite = 0;skip = false;PersonNatureAttr pna = null;int index = 0;int freq = 0;double allFreq = 0;Term term = null;int i = offe;for (; i < terms.length; i++) {// 走到结尾处识别出来一个名字.term = terms[i] ;pna = term.getTermNatures().personAttr;// 在这个长度的这个位置的词频,如果没有可能就干掉,跳出循环if ((freq = pna.getFreq(size, index)) == 0) {return null;}//增加人名sb.append(term.getName()); //这个人名的概率计算allFreq += Math.log(term.getTermNatures().allFreq+1) ;allFreq += -Math.log((double) (freq));index++;if (index == size + 2) {//当达到制定长度后跳出循环break;}}double score = -Math.log(factory[size]);score += allFreq ;double endFreq = 0;// 开始寻找结尾词,endFreq = terms[i].getTermNatures().personAttr.end + 1;//根据上下文.概率进行公司计算score -= Math.log(endFreq);score -= Math.log(beginFreq);term = new Term(sb.toString(), offe, TermNatures.NR);term.selfScore = score; //识别出来的人名进行返回return term;}
-------->祝祝海林--->海林在孙建的右面