python中文分词


相对于英文而言,中文在计算机处理方面有个必须要面对的问题就是中文分词,英文的单词都是空格间隔的,而中文的词语则不同,所以用程序解决中文分词,在很多自然语言处理方面都是首要进行的步骤。

其中最简单的就是最大匹配的中文分词了,比如“今天天气不错”可以分词为“今天/天气/不错”,但是面对一些有歧义的句子时却显得捉襟见肘,于是“南京市长江大桥”就会被分成“南京市长/江/大桥”而不是“南京市/长江/大桥”,于是更好的是基于统计学原理的分词,也就是说看哪种出现的频率更高。

对于一个中文字符串“a1a2a3...an”如何正确的用词语c1,c2..cm表示就是中文分词的任务,也就是说我们要去找寻P(c1c2..cm)最大的分词,按照马尔科夫链的想法就是说我们就是求P(c1)*P(c1|c2)*P(c1c2|c3)*...P(c1c2...cm-1|cm)最大。按照阿卡姆剃刀的想法我们可以假设一个最可能的实现,于是google黑板报的假设就是每个词只跟前面的词有关,于是变为求P(c1)*P(c1|c2)*P(c2|c3)*...P(cm-1|cm)最大。进一步的其实我们可以假设每个词都是相对独立的,也就是求P(c1)*P(c2)*...P(cm)最大,那么这个怎么求呢,就是用dp的方法。ok,上代码。

  1. # -*- coding: UTF-8 -*-
  2.  
  3. import collections
  4. d=collections.defaultdict(lambda:1)
  5.  
  6. def init(filename='SogouLabDic.dic'):
  7.     f=open(filename,'r')
  8.     total=0
  9.     while True:
  10.         line=f.readline()
  11.         if not line: break
  12.         word, freq = line.split('\t')[0:2]
  13.         total+=int(freq)+1#smooth
  14.         try:
  15.             d[word.decode('gbk')]=int(freq)+1
  16.         except:
  17.             d[word]=int(freq)+1
  18.     f.close()
  19.     d['_t_']=total
  20.  
  21. def solve(s):
  22.     l=len(s)
  23.     p=[0 for i in range(l+1)]
  24.     p[l]=1
  25.     div=[1 for i in range(l+1)]
  26.     t=[1 for i in range(l)]
  27.     for i in range(l-1,-1,-1):
  28.         for k in range(1,l-i+1):
  29.             tmp=d[s[i:i+k]]
  30.             if k>1 and tmp==1:
  31.                 continue
  32.             if(d[s[i:i+k]]*p[i+k]*div[i] > p[i]*d['_t_']*div[i+k]):
  33.                 p[i]=d[s[i:i+k]]*p[i+k]
  34.                 div[i]=d['_t_']*div[i+k]
  35.                 t[i]=k
  36.     i=0
  37.     while i<l:
  38.         print s[i:i+t[i]],
  39.         i=i+t[i]
  40.  
  41.  
  42. if __name__ == '__main__':
  43.     init()
  44.     s="其中最简单的就是最大匹配的中文分词"
  45.     s=s.decode('utf8')
  46.     solve(s)

词库用到了搜狗实验室提供的不错的词库,程序还是很清晰的,值得注意的就是乘法不要直接去乘因为频率都是小于1的,乘的太多可能就会变为0就要影响整个算法了,所以我是分子分母分开存放的,话说直接用了python的原生大整数,连gcd都懒得写了啊。。。

ps:注意到如果词在字典里没有出现会导致概率乘积是0的情况,所以需要进行smooth

参考资料:
http://scturtle.is-programmer.com/posts/26648.html
http://www.matrix67.com/blog/archives/4212
http://www.google.com.hk/ggblog/googlechinablog/2006/04/blog-post_7327.html
http://mindhacks.cn/2008/09/21/the-magical-bayesian-method/

------------我是分割线--------------------
理论上用log相加的方法是最好的,于是修改了下代码,变得更简短了,只要34行哎,代码在github

您可能喜欢:
我猜您可能还喜欢:
, , , ,

《python中文分词》有 27 条评论

  1. leslie | #2

    没看出来有什么效果啊

    $ python 中文分词.py
    其 中 最 简 单 的 就 是 最 大 匹 配 的 中 文 分 词

    这就是最后的结果么?

  2. raya | #3

    赞,搜东西经常能路过你这里膜拜一下~~

  3. Balloon | #4

    Hi,
    我试了一下你的脚本,感觉很不错,现在有一个小问题一直很纠结。我对一批文件做分词,把你的脚本import进去,然后发现内存画画的往上涨。总共100M的文件(大概3000个),最后64G的内存都吃不下来,我稍微查了一下,发现占用最多的是Unicode类型,我觉得应该只有dictionary了吧,文本内容是扫一遍,最多在1G以下。我查了一下,觉得应该是没有回收,不知道是不是?怎么修改?

  4. hongzhi | #5

    着手中文分词,不知如何下手,多谢啦

Trackbacks/Pingbacks:

  1. python实现websocket服务器 | 吃杂烩
  2. 如何比较两句句子的相似度 | 理想乡
  3. 几种中文分词算法的比较 | isnowfy
  4. 浅谈中文分词 | isnowfy
  5. 浅谈中文分词 - IT牛人博客聚合

发表评论