弄了好几天正向最大匹配法分词,终于弄完了吧。Python写的。Python确实是一门好语言,写起来很简单、顺手。


一、关于正向最大匹配法分词

中文分词(Chinese Word Segmentation)指的是将一个汉字序列切分成一个一个单独的词。中文分词是文本挖掘的基础,对于输入的一段中文,成功的进行中文分词,可以达到电脑自动识别语句含义的效果。


正向最大匹配法

例子: 将句子 ’ 今天来了许多新同事 分词。  最大词长为5

今天来了许
今天来了
今天来
今天  ====》 得到一个词 – 今天
来了许多新
来了许多
来了许
来了
来   ====》 得到一个词 –
了许多新同
了许多新
了许多
了许
了   ====》 得到一个词 –
许多新同事
许多新同
许多新
许多 ====》得到一个词 – 许多
新同事
新同
新   ====》得到一个词 –
同事 ====》得到一个词 – 同事


最后正向最大匹配的结果是:/今天/来/了/许多/新/同事/


二、正向最大匹配分词算法

1364266488_8537.png


三、语料库的处理与算法的输入


语料库的处理流程

1364266605_4506.png

输入:人民日报语料库199801.txt

输出:dict.txt词表文件


分词算法

输入:将dict.txt处理后得到的list集,以及最大词长;待分词的句子

输出:分词后的句子


四、Python实现

1. 语料库的初步处理 ( MaxBuildDict.py )


[python] view plain copy
  1. # -*- coding: cp936 -*-

  2. #最大匹配法进行分词----创建词表文件.

  3. #author 徐能

  4. #date 2013/3/23

  5. import string  

  6. import re  

  7. #输入:语料库199801.txt文件; 输出:换行分割后的词表文件dict.txt(已经去重复, 去日期)

  8. def create_dict(filename):  

  9. print("读取文件......")  

  10.    src_data = open(filename,'r').read()  

  11.    sp_data = src_data.split()#分割

  12. print("原始词数为:",len(sp_data))  

  13.    set_data = set(sp_data) #去重复

  14.    data = list(set_data) #set转换成list, 否则不能索引

  15. print("去除重复后总词数为:",len(data))  

  16. print("正在建立词表文件......")  

  17.    tmp = []  

  18. for i in range(0,len(data)):  

  19. if re.compile(r'\d+\-\S+').match(data[i]):  #去除类似这样的词'19980101-01-001-002/m'

  20. continue

  21. else:  

  22.            p_ok_data = re.compile(r'\/\w+').sub('\n',data[i]) #将类似的词'埃特纳/ns'替换为'埃特纳'

  23. if re.compile(r'(\[\S+)|(\]\S+)').match(p_ok_data):    #找到以'['或']'开头的词

  24.                ok_data = re.compile(r'(\]\w+\[)|(\])|(\[)').sub('',p_ok_data) #去除']nt[澳门',']澳门','[澳门'三类词的头部无用部分(先匹配长的部分)

  25.                tmp.append(ok_data)  

  26. continue

  27.            tmp.append(p_ok_data)  

  28. print("最终得到的词表文件中总词数为:",len(tmp))  

  29.    open('dict_tmp.txt','w').writelines(tmp)  

  30. print("初步词表文件建立完成! (dict_tmp.txt)")  

  31. #运行

  32. if __name__ == '__main__':  

  33.    create_dict('199801.txt')  



2. 进一步对词表的优化 ( MaxBuildDictModify.py )


[python] view plain copy
  1. # -*- coding: cp936 -*-

  2. #修正词表文件.

  3. #author 徐能

  4. #date 2013/3/24

  5. import string  

  6. import re  

  7. #输入:dict_tmp.txt文件; 输出:dict.txt(已经去重复, 去特殊符号)

  8. def create_dict(filename):  

  9. print("读取文件......")  

  10.    src_data = open(filename,'r').read()  

  11.    data = src_data.split()#分割

  12. print("正在建立词表文件......")  

  13.    tmp = []  

  14. for i in range(0,len(data)):  

  15.       ok_data = re.compile(r'\]..').sub('',data[i]) #将类似的词']..埃特纳'前面的东西去掉

  16.       tmp.append(ok_data+'\n')  

  17. print("去重复前的词数为:",len(tmp))  

  18.    set_data = set(tmp) #去重复

  19.    lalst_data = list(set_data) #set转换成list, 否则不能索引

  20. print("去除重复后总词数为:",len(lalst_data))  

  21.    open('dict.txt','w').writelines(lalst_data)  

  22. print("最终词表文件建立完成! (dict.txt)")  

  23. #运行

  24. if __name__ == '__main__':  

  25.    create_dict('dict_tmp.txt')  

  26. ##    create_dict('testdict1.txt')

  27. ##    create_dict('testdict2.txt')



3. 分词算法实现 ( MaxWordSegmentation.py )


[python] view plain copy
  1. # -*- coding: cp936 -*-

  2. #最大匹配法进行分词, 测试文件为MaxWordSegmentationTest.py

  3. #author 徐能

  4. #date 2013/3/25

  5. import string  

  6. import re  

  7. #读入词表文件到内存list

  8. #输入:词典文件名, 输出:词典中所有词的list表,其中最大词长

  9. def load_dict(filename):  

  10.    f = open(filename,'r').read()  

  11.    maxLen = 1

  12.    strList=f.split("\n")  

  13. #寻找最大词长

  14. for i in strList:  

  15. if len(i)>maxLen:  

  16.            maxLen=len(i)  

  17. return strList,maxLen;  

  18. #分词方法.

  19. #输入:词表中所有词的列表与其中的最大词长, 输出:分词后的列表

  20. def segmentation(strList,maxLen,sentence):  

  21.    wordList=[]  #用于输出的词列表

  22. while(len(sentence)>0):  

  23.        word=sentence[0:maxLen] #每次取最大词长的词

  24.        meet=False;   #标记位, 判断是否找到该词

  25. while((not meet) and (len(word)>0)):  

  26. #如果词在词表中

  27. if(word in strList):  

  28.                wordList.append(word)   #添加到输出列表

  29.                sentence=sentence[len(word):len(sentence)]#后移

  30.                meet=True;  

  31. #词不在词表中时

  32. else:  

  33. #当词长为1时, 添加到输出表, 并后移总词位

  34. if(len(word)==1):  

  35.                    wordList.append(word)  

  36.                    sentence=sentence[len(word):len(sentence)]  

  37.                    meet=True;  

  38. else:  

  39. #当词长不为1时, 词长减1(最后一位)

  40.                    word=word[0:len(word)-1]  

  41. return wordList  

  42. #主函数

  43. def main():  

  44.    strList,maxLen=load_dict('dict.txt')  

  45. print("词表中最大词长度为:",maxLen)  

  46. #输入句子

  47.    sentence = input('请输入中文句子:')  

  48. print('输入的句子为:',sentence)  

  49. #   sentence='迈向充满希望的新世纪'

  50. print('输入的句子为:',sentence)  

  51.    length=len(sentence)  

  52. print('输入的句子长度:',length)  

  53. print("****************开始解析**********************")  

  54.    wordl=segmentation(strList,maxLen,sentence)  

  55. #打印分词结果

  56. for eachChar in wordl:  

  57. print(eachChar,end = "/ ")  

  58. print("")#换行

  59. print("****************解析完毕!*********************")  

  60. #运行

  61. if __name__ == '__main__':  

  62.    main()  

五、运行结果


1364267403_1919.png


1364267419_2434.png


六、总结

关于效率:

正向最大匹配法分词占用很大计算量,结果本人测试,100多个字的一段话一般2秒分完。1000个字的一段话,需要20几秒才能分完。以最大词长为20来计算的话,待分的句子为20个字,假设全部分成2字词,词表中有5万个词,则计算量约为22*5*50000=550万。如此可见,当待分词句子很长,最大词长很大时,计算量是惊人的。

关于分词准确度:

正向最大匹配法的缺陷在与精确度不能达到理想的状态。同时也不能解决词的歧义问题。(统计结果表明,单纯使用正向最大匹配的错误率为1/169,单纯使用逆向最大匹配的错误率为1/245。)


(文章如有错误,敬请指正)


运行源码以及全部文档下载地址:http://download.csdn.net/detail/xn4545945/5182311


原创文章,转载请注明出处