隐马尔科夫模型分词器分析.docx
- 文档编号:11637596
- 上传时间:2023-06-01
- 格式:DOCX
- 页数:19
- 大小:314.03KB
隐马尔科夫模型分词器分析.docx
《隐马尔科夫模型分词器分析.docx》由会员分享,可在线阅读,更多相关《隐马尔科夫模型分词器分析.docx(19页珍藏版)》请在冰点文库上搜索。
隐马尔科夫模型分词器分析
隐马尔科夫模型
中文分词工程报告
一,研究背景
随着互联网技术的发展,计算机在人们的生产生活当中起着不可或缺的作用,而计算机对中文的分词,理解,以及翻译也随着社会生产力的发展,需求量也越来越大,而中文词汇多,语义繁杂,语法不清晰的问题也随之暴露出来,所以一个好的中文分词模型对建立中文分词系统起着至关重要的作用。
二,模型方法
本工程主要采用了隐马尔科夫模型。
隐马尔可夫模型可以表示为一个五元组(S,O,A,B,)
S是一组状态的集合。
S={‘S’,‘I’,‘B’,‘E’}
O是一组输出符号的集合。
A是状态转移矩阵。
符号B输出概是率分布
B={P(vk|j)}P(vk|j)表示在状态j时输出符号vk的概率
π是初始状态概率分布π={i}
πi=P(q1=i)表示初始选择某个状态的概率。
首先,在A矩阵中求出各个状态之间转移的概率,再算出B中在状态J时输出符号vk的概率,然后算出各种情况下的概率情况,最后所得的最大概率的序列就是中文分词的序列
例如:
模型的参数已知,评价某个分词结果
我爱你程序员
SSSBIE
Value=½*P(S->S)*P(S->S)*P(S->B)*P(B->I)*P(I->E)*
P(我|S)*P(爱|S)*P(你|S)*P(程|B)*P(序|I)*P(员|S)
求得最佳的转换序列,再进行相应的匹配,就能得到所求的中文分词了
三,系统设计
首先,我们需要统计很多词语来用程序训练。
选取人民日报上的语料库的格式如下:
我们在一个单独的程序里一行一行的读入这些语料,并依据JAVA中String包的split()函数对这一行的许多元组按照”\\s+”来拆分成一个个小元组,例如:
迈向/vt,充满/vt.然后对单个的小元组按照”/”来拆分,并统计重复的词的个数。
最终在新的文件里形成:
词组词性词出现的个数,这样的形式。
所用到的源代码如下:
Vector
Vector
Vector
Vector
Files=newFile("D:
\\we.txt");
Filew=newFile("D:
\\result.txt");
FileWriterfw=newFileWriter(w);
FileReaderfr=null;
fr=newFileReader(s);
@SuppressWarnings("resource")
BufferedReaderfis=newBufferedReader(fr);
Stringstr=null;
inti,j;
while((str=fis.readLine())!
=null)
{
i=0;
j=1;
String[]sp=str.split("\\s+");
for(i=0;i { all.add(i,sp[i]); } if(! all.isEmpty()) { for(j=0;j { Stringcizu=all.elementAt(j); String[]sic=cizu.split("/"); //System.out.println(sic[0]+""); if(sic[0].length()<15&&sic[0].length()>0&&sic.length==2) { intweizhi=vocabu.indexOf(sic[0]); //System.out.println(sic[0]); if(weizhi==-1) { vocabu.add(sic[0]); grammar.add(sic[1]); num.add (1); } else{ intcount=num.remove(weizhi); count=count+1; num.add(weizhi,count); } } } } //System.out.println(all); all.removeAllElements(); //str=fis.readLine(); } //System.out.println(vocabu); //System.out.println(grammar); //System.out.println(num); longnumber=0; for(intas=0;as { number=number+num.get(as); } System.out.println(number); for(inte=0;e { Stringa0=String.valueOf(e+1); Stringa1=vocabu.get(e); Stringa2=grammar.get(e); Stringa3=String.valueOf(num.get(e)); Stringa=a1+"\t"+a2+"\t"+a3+"\r\n"; char[]buffer1=newchar[a.length()]; buffer1=a.toCharArray(); fw.write(buffer1); } fw.close(); fr.close(); 结果如下图所示: 然后对每个词分析,如果是单字,则用S表示,如果是一个词,则词首用B表示,词尾用W表示,词中用E表示,并统计次数。 例如迈向===BW中共中央===BEEW 程序源代码如下: Vector Vector Filew=newFile("D: \\result.txt"); Files=newFile("D: \\Aun.txt"); FileWriterfs2=newFileWriter(s); FileReaderfr=newFileReader(w); @SuppressWarnings("resource") BufferedReaderfis=newBufferedReader(fr); Stringstr=null; while((str=fis.readLine())! =null) { String[]spr=str.split("\t"); if(spr[0].length()==1) { if(vocabu.contains(spr[0]+""+"S")) { inti=vocabu.indexOf(spr[0]+""+"S"); intj=num.remove(i); intm=j+Integer.parseInt(spr[2]); num.add(i,m); } else{ vocabu.add(spr[0]+""+"S"); num.add(Integer.parseInt(spr[2])); } } else{ if(vocabu.contains(String.valueOf(spr[0].charAt(0))+""+"B")) { inti=vocabu.indexOf(String.valueOf(spr[0].charAt(0))+""+"B"); intj=num.remove(i); intm=j+Integer.parseInt(spr[2]); num.add(i,m); } else{ vocabu.add(String.valueOf(spr[0].charAt(0))+""+"B"); num.add(Integer.parseInt(spr[2])); } if(vocabu.contains(String.valueOf(spr[0].charAt(spr[0].length()-1))+""+"W")) { inti=vocabu.indexOf(String.valueOf(spr[0].charAt(spr[0].length()-1))+""+"W"); intj=num.remove(i); intm=j+Integer.parseInt(spr[2]); num.add(i,m); } else{ vocabu.add(String.valueOf(String.valueOf(spr[0].charAt(spr[0].length()-1))+""+"W")); num.add(Integer.parseInt(spr[2])); } if(spr.length>2){ for(inte=1;e { if(vocabu.contains(String.valueOf(spr[0].charAt(e))+""+"E")) { inti=vocabu.indexOf(String.valueOf(spr[0].charAt(e))+""+"E"); intj=num.remove(i); intm=j+Integer.parseInt(spr[2]); num.add(i,m); } else{ vocabu.add(String.valueOf(spr[0].charAt(e))+""+"E"); num.add(Integer.parseInt(spr[2])); } } } } } for(inte=0;e { Stringa1=vocabu.get(e); Stringa3=String.valueOf(num.get(e)); Stringa=a1+"\t"+a3+"\r\n"; char[]buffer1=newchar[a.length()]; buffer1=a.toCharArray(); fs2.write(buffer1); } fs2.close(); // 并形成新的文件如下: 根据这些SWEB来分析S->BB->ES->SB->WE->EE->WW->SW->B的次数,并得到A矩阵,A矩阵分别是以上SWEB的概率次数。 A矩阵的代码如下: double[][]anun=newdouble[4][4]; for(inti=0;i { Stringa=sweb.get(i); Stringb=sweb.get(i+1); if(a.equalsIgnoreCase("S")&&b.equalsIgnoreCase("S")) { anun[0][0]+=1; } if(a.equalsIgnoreCase("S")&&b.equalsIgnoreCase("B")) { anun[0][1]+=1; } if(a.equalsIgnoreCase("B")&&b.equalsIgnoreCase("E")) { anun[1][2]+=1; } if(a.equalsIgnoreCase("B")&&b.equalsIgnoreCase("W")) { anun[1][3]+=1; } if(a.equalsIgnoreCase("E")&&b.equalsIgnoreCase("W")) { anun[2][3]+=1; } if(a.equalsIgnoreCase("W")&&b.equalsIgnoreCase("S")) { anun[3][0]+=1; } if(a.equalsIgnoreCase("W")&&b.equalsIgnoreCase("B")) { anun[3][1]+=1; } if(a.equalsIgnoreCase("E")&&b.equalsIgnoreCase("E")) { anun[2][2]+=1; } } 其中sweb为一个Vector向量,存储SWEB的序列。 求得A矩阵后,我们输入一串中文字符,以每个字出现SWEB的次数来代替其概率构造出B矩阵。 在B矩阵中,用魏特碧算法,从第二个字开始,计算前一个字的每一种状态的概率乘上后一个的某一种状态的概率再乘上A矩阵中对应的两中状态之间的概率。 比较并取得最大值,依次计算存储并获得一个矩阵,定义为T1,然后将每种状态概率最大值对应的前一种状态记录(SWEB分别用0123代替)并存储为新的矩阵T2,最后在T1矩阵的最后一列中找到最大值,并在T2矩阵中找到对应的位置,依次向前取相应位置的值并记录,得到一个和输入的中文字符串长度一样的数字串。 源代码如下: intj=zhongwen.length(); doubleps[][]=newdouble[4][j]; for(inti=0;i<4;i++) { for(intm=0;m { ps[i][m]=0; } } for(intq=0;q { if(vocabu.contains(String.valueOf(zhongwen.charAt(q))+""+"S")){ intstrw=vocabu.indexOf(String.valueOf(zhongwen.charAt(q))+""+"S"); ps[0][q]=Math.pow(num.get(strw),0.1); } if(vocabu.contains(String.valueOf(zhongwen.charAt(q))+""+"B")){ intstrw=vocabu.indexOf(String.valueOf(zhongwen.charAt(q))+""+"B"); ps[1][q]=Math.pow(num.get(strw),0.1); } if(vocabu.contains(String.valueOf(zhongwen.charAt(q))+""+"E")){ intstrw=vocabu.indexOf(String.valueOf(zhongwen.charAt(q))+""+"E"); ps[2][q]=Math.pow(num.get(strw),0.1); } if(vocabu.contains(String.valueOf(zhongwen.charAt(q))+""+"W")){ intstrw=vocabu.indexOf(String.valueOf(zhongwen.charAt(q))+""+"W"); ps[3][q]=Math.pow(num.get(strw),0.1); } } intlocation[][]=newint[4][j]; doublejuli[][]=newdouble[4][j]; juli[0][0]=ps[0][0]; juli[1][0]=ps[1][0]; for(intwe=1;we { for(inter=0;er<4;er++) { for(intrt=0;rt<4;rt++) { if(juli[rt][we-1]*ps[er][we]*anun[rt][er]>juli[er][we]) { juli[er][we]=juli[rt][we-1]*ps[er][we]*anun[rt][er]; location[er][we]=rt; } } } } doubletemp=0; for(inti=0;i<4;i++) { if(juli[i][j-1]>temp) { temp=juli[i][j-1]; } } intjer=0; //for(inti=0;i<4;i++) //{ //if(juli[i][j-1]==temp) //{ //break; //} //} while(juli[jer][j-1]! =temp) { jer++; } //System.out.println(jer); Stringsptr=String.valueOf(3); for(intsd=j-1;sd>0;sd--) { intjs=location[jer][sd]; sptr=String.valueOf(js)+sptr; jer=js; } System.out.println(sptr); 由于次数过大可能超出INT的范围,所以我用MATH的方法对其进行了等比缩小。 最后得出的数字串中,与中文相对应的,0或3对应的中文字后被拆分。 就完成了隐马尔科夫模型对中文的分词,将被分的词与之前的词相对应的词比较并取得词性(同词不同性暂不能考虑)最后我用JAVA创建了一个简单的GUI,可以多次输入与分析中文分词: 四,系统演示与分析 如三中事例的那样,对于“结婚的和尚未结婚的”这一有歧义的中文字符串成功地避免了“和尚”一词的出现,但对于像“欢迎新老师生前来就餐”,“大学生前来应聘”等,并不能把“生前”给分开: 还有一些其他的语法语义有歧义的地方不能很好的解决句式杂糅和歧义的问题。 另外,对于三个字,四个字词的分析还不够好,例如“中国人”只能拆分成“中”“国人”,“中共中央”拆成“中”“,共”和“中央”,目前测试成功的只有“干什么”不会被拆分开。 究其原因,我想是首先是语料库的不充分,对于一些词在不同位置出现的概率并没有很好地统计,导致所求出来的结果出现误差。 其次是运用词在不同位置的概率来分词,本身具有一定的局限性,不可能做到太完美。 但相比最长路径,已经好太多。 五,对本门课的感想、意见和建议 学习了这门课,让我掌握了对中文分词的基本概念的理解。 中文不比英文,德文,有着良好的语法系统,不如拉丁文只有26个字母。 它个数众多,每个字的意思不尽相同,语法比较杂乱无章。 古代汉语和现代汉语的语法又不相同。 同时伴随着时代的发展,中文的语法也在日新月异地变化着。 我觉得解决中文词法分析是一种比较困难的工程,需要长时间的探索与研究,并能跟上时代的步伐。 如果形成一套完善的系统,既能处理好中文分词,又能对新词,新意词进行同步地学习并完善系统,中文在计算机系统中的地位将提高很大一步。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 隐马尔科夫 模型 分词 分析
![提示](https://static.bingdoc.com/images/bang_tan.gif)