中文分词之左右完整性及稳定性

来源:互联网 发布:网络电视找不到电视猫 编辑:程序博客网 时间:2024/05/18 05:38

一、      概念:

新闻案例:

“out-100”的说法也在考生父母之间流传,即在全校排名100名开外时,基本与名牌大学无缘的意思。此外,“入学考试代理父母”也成为新风尚,主要指子女就读于名牌大学的父母受别人委托,辅导其他家庭的子女高考。

     在这条新闻的两句话中,两次出现了“名牌大学”的字样,但是,在分词的时候出现这样的结果:



很明显,在这里“名牌”两字单独拿出来,没有任何意义;“大学”两字单独拿出来语义又有所偏差。只有联合起来“名牌大学”才有完整的意义。这就是说,在文章中,一些特定的组合词需要凑在一起才能表达其中的意思。如果候选词B在文中与候选词A和候选词C都一直同时出现并且出现不只一次,那么词“ABC”的组合很有可能是一个有意义的对象词。对于候选词B来讲,它既是左非完整,也是右非完整,只有“ABC”组合了,这个词才是左右完整。

稳定性:

3.3 非稳定性评价对象的过滤

定义评价对象的稳定性:针对本文中候选评价对象 Object是基于规则获得的,通常是由多个词(w1w2…w3)组成的。用各个词之间的紧密耦合程度,来衡量 Object的稳定性,本文采用下式计算获得:


其中, f(Object) 表示 Object在一篇文档中出现的频率;f(wi )表示组成 Object 的词wi在该文档中出现的频率; m表示组成该 Object的词个数; S(Object ) 表示评价对象的稳定性。

如“刻录 /n  /qv”候选对象是由“刻录”和“盘”2个词组成的,即 m 的值为 2,假设在文本中出现了 2次,即 f(Object)的值为 2“刻录”出现 2 (它始终和“盘”在一起出现 ),即fw1)的值为 2“盘”出现了 3 (它除了与“刻录”在一起出现,还在其他位置出现 ),即fw2)的值为 3,那么的值为 5。此时,

S(Object) =2/(5 − (2 − 1)×2)=0.67 ,说明“刻录盘”在一起出现可能性比分开出现的可能性大,那么更能表示一个词。

Object 仅是一个词组成的时候,即 m =1时,或者组成Object的词出现的次数与 Object 出现的次数相同,即它们始终在一起出现时,S (Object) =1,此时 Object最稳定;当组成 Object的词,仅在一起出现一次 (或很少次 ),而分

散在文本中不同位置的次数趋于无穷时, SObject的值趋于 0,此时 Object 最不稳定。


二、      算法实现:

/** * 判断候选词是否完整,0 完整,1 不完整。 * 判断依据是根据左右完整性。如果在整篇文章中词A的左边总是跟着另一个词B,那么这个词A左边不完整,否则词A左边完整 * 如何判断是否总是跟着一个词?遍历文中的词A,在每个出现地方的前一个词装入到leftSet<String>集合中,如果最后leftSet长度==1 *     那么证明这个词要么只出现一次,要么就是非完整的。 * @param regexsFile * @param inputFile * @param outputFile */public static  void filterIntegrityWords(String regexsFile,String inputFile,String outputFile,String primitiveCadidateFile){List<String> regexsLists = StringUtil.getListContentFromPath(regexsFile);BufferedReader br=null;BufferedWriter bw = null;try { br = new BufferedReader(new FileReader(inputFile)); String result ="";String content =  StringUtil.getContent(inputFile);String[] words = content.split(" ");for(String regex : regexsLists){regex = regex.trim();String[] regexWords = regex.split(" ");int left = 0;//0 是完整,1是不完整的int right = 0;Set<String> leftSet = new HashSet<String>();//如果左边不完整,那么循环过后,set的length一定大于1Set<String> rightSet = new HashSet<String>();int count = 0; //判断候选词在文章出现的次数String str = "";//追加字符串float left_stability =  0;float right_stability =  0;//如果候选词的词组是一个if(regexWords.length == 1){for(int i=0;i<words.length;i++){if(regexWords[0].equals(words[i])){count ++;if(i == 0) {//如果是文中的第一个词left = 0;rightSet.add(words[i+1]);}else if (i == words.length-1){leftSet.add(words[i-1]);right = 0;}else{leftSet.add(words[i-1]);rightSet.add(words[i+1]);}}}// forif(leftSet.size() == 1 && count>1) {left =1;String leftWord =leftSet.iterator().next();str = leftWord;//稳定性计算String object = leftWord +" " + regexWords[0];int count_object = StringUtil.getCountSpiltWord(object, primitiveCadidateFile);int count_leftWord = StringUtil.getCountSpiltWord(leftWord, primitiveCadidateFile); int count_regexWord =  StringUtil.getCountSpiltWord(regexWords[0], primitiveCadidateFile); float Denominator = (count_leftWord+count_regexWord)-count_object;if(Denominator !=0 ){left_stability = count_object/Denominator;}}else left =0;if(rightSet.size() == 1 && count>1) {right =1;String rightWord =rightSet.iterator().next();str +=" , " +rightWord;//稳定性计算String object = rightWord +" " + regexWords[0];int count_object = StringUtil.getCountSpiltWord(object, primitiveCadidateFile);int count_rightWord = StringUtil.getCountSpiltWord(rightWord, primitiveCadidateFile); int count_regexWord =  StringUtil.getCountSpiltWord(regexWords[0], primitiveCadidateFile);float Denominator = (count_rightWord+count_regexWord)-count_object;if(Denominator !=0 ){right_stability = count_object/Denominator;}}else right =0;}else if(regexWords.length == 2){for(int i=0;i<words.length;i++){if(regexWords[0].equals(words[i]) && regexWords[1].equals(words[i+1])){count ++;if(i == 0) {//如果是文中的第一个词left = 0;rightSet.add(words[i+2]);}else if (i == words.length-1){leftSet.add(words[i-1]);right = 0;}else{leftSet.add(words[i-1]);rightSet.add(words[i+2]);}}}// forif(leftSet.size() == 1 && count>1) {left =1;// 稳定性计算String leftWord =leftSet.iterator().next();str = leftWord;String object = leftWord +" " + regexWords[0]+regexWords[1];int count_object = StringUtil.getCountSpiltWord(object, primitiveCadidateFile);int count_leftWord = StringUtil.getCountSpiltWord(leftWord, primitiveCadidateFile); int count_regexWord =  StringUtil.getCountSpiltWord(regexWords[0]+regexWords[1], primitiveCadidateFile); float Denominator = (count_leftWord+count_regexWord)-count_object;if(Denominator !=0 ){left_stability = count_object/Denominator;}str += leftSet.iterator().next();}else left =0;if(rightSet.size() == 1 && count>1) {right =1;//稳定性计算String rightWord =leftSet.iterator().next();str +=" , " +rightWord;String object = rightWord +" " + regexWords[0]+regexWords[1];int count_object = StringUtil.getCountSpiltWord(object, primitiveCadidateFile);int count_rightWord = StringUtil.getCountSpiltWord(rightWord, primitiveCadidateFile); int count_regexWord =  StringUtil.getCountSpiltWord(regexWords[0]+regexWords[1], primitiveCadidateFile);float Denominator = (count_rightWord+count_regexWord)-count_object;if(Denominator !=0 ){right_stability = count_object/Denominator;}}else right =0;}else if(regexWords.length == 3){for(int i=0;i<words.length;i++){if(regexWords[0].equals(words[i]) && regexWords[1].equals(words[i+1]) && regexWords[2].equals(words[i+2])){count ++;if(i == 0) {//如果是文中的第一个词left = 0;rightSet.add(words[i+3]);}else if (i == words.length-1){leftSet.add(words[i-1]);right = 0;}else{leftSet.add(words[i-1]);rightSet.add(words[i+3]);}}}// forif(leftSet.size() == 1 && count>1) {left =1;str += leftSet.iterator().next();}else left =0;if(rightSet.size() == 1 && count>1) {right =1;str +=" , " +rightSet.iterator().next();}else right =0;}//result += regex+"  "+"left:"+left+"/sta:"+left_stability+"  right:"+right+"/sta:"+right_stability+"  "+str+ConstantString.WIN_NextLine;}StringUtil.String2File(result, outputFile); } catch (Exception e) {e.printStackTrace();}}

部分效果截图:(在原来分词不当的情况下,能识别出高频词组。)





(left:0 代表左完整,1代表左不完整;stat代表稳定性,越接近1代表越稳定)

如上图:

在这片文章中:“名牌“ 与“大学”合在一起的稳定性是1;“人“和”文学系“的稳定性是0.6666;这两个稳定性都超过一半,所以是个可靠的对象词。但是”就业“和”形势“这两个词组合的稳定性是0.4;”说法“和”的“组合的稳定性更是低至0.09,说明在这篇文章中它们组合起来是对象词的可能性很低。



1 0