最大匹配分词方法只考虑词有没有在字典中出现,没有考虑词在词典中的频率。
基于统计学的分词即考虑词在词典中的频率的一种简单的分词方法。
注:下面的代码参考snownlp作者的博客 :http://www.isnowfy.com/python-chinese-segmentation/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import mathimport codecsd = {} log = lambda x: float ('-inf' ) if not x else math.log(x) prob = lambda x: d[x] if x in d else 0 if len (x)>1 else 1 def init (filename='SogouLabDic.dic.utf8' ): """读取字典""" d['_t_' ] = 0.0 with open (filename, "r" ) as f: for line in f: word, freq = line.split('\t' )[:2 ] d['_t_' ] += int (freq)+1 d[word] = int (freq)+1 init()
小插曲:
搜狗提供的这个词典本身是GB2312编码的,我使用file SogouLabDic.dic
显示的却是ISO-8859
,以至于写代码的时候绕了很大的弯子。
后面在网上找到enca 这个工具,可以更精准地识别编码。
先安装:sudo apt-get install enca
。
智能识别编码:enca -L zh_CN SogouLabDic.dic
,输出:Simplified Chinese National Standard; GB2312
。
转换编码:enca -L zh_CN -x utf-8 <SogouLabDic.dic> SogouLabDic.dic.utf8
。 另,词典的格式是:词 词频 词性
。
1 2 3 4 5 6 7 8 9 10 [('_t_', 301869553991.0), ('一个', 818357167), ('我们', 770027798), ('时间', 767969295), ('中国', 727787726), ('可以', 685520166), ('公司', 640938771), ('没有', 632008127), ('信息', 622926082), ('下载', 591771675)]
对于一个中文字符串:$a_1a_2…a_n$如何正确的用词:$c_1,c_2…c_m$表示就是中文分词的任务,也就是说我们要去找寻$P(c_1c_2..c_m)$最大的分词。
假设词跟词之间互相独立,转换成求$P(c_1)×P(c_2)×…×P(c_m)$最大,概率即这个词在词典中的频数除以所有词的频数之和(加入平滑)。
加入log,求$logP(c_1)+logP(c_2)+…+logP(c_m)$最大。
使用动态规划 (DP)求解这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def solve (s ): l = len (s) sum_log_p = [0 for i in range (l + 1 )] word_len = [0 for i in range (l)] for i in range (l-1 , -1 , -1 ): sum_log_p[i], word_len[i] = max ((log(prob(s[i: i+k]) / d['_t_' ]) + sum_log_p[i+k], k) for k in range (1 , l-i+1 )) start_index = 0 while start_index < l: yield s[start_index: start_index + word_len[start_index]] start_index += word_len[start_index] s = u'其中最简单的就是最大匹配的中文分词' print (' ' .join(list (solve(s))))
1 其中 最简单 的 就是 最大 匹配 的 中文 分词