文章目录
- 一、中英文分词的区别
- 二、中文分词技术
- 2.1 基于规则的分词
- 正向最大匹配算法
- 逆向最大匹配算法
- 双向匹配算法
- 2.2 基于统计的分词
- 语言模型
- 隐马尔科模型HMM
- 三、总结
一、中英文分词的区别
英文的分词相较于中文分词比较简单,因为英文中一个词可代表一个名词、形容词、副词等,且词与词之间用空格隔开,在写程序进行切分的时候只要匹配到空格即可。
而在中文本词语没有明显的区分标记,而中文分词的目的就是由机器在中文文本中加上词与词之间的标记。中文分词存在困难是由于存在交集型歧义、组合型歧义和混合型歧义,交集型歧义如对ATB,有AT、TB同时成词,eg.成为了,有成为/为了;组合型歧义如对AB,有A、B、AB同时成词,eg.门把手坏了,有门/把手/坏/了,混合型歧义由交集型歧义和组合型歧义组成。
二、中文分词技术
中文分词技术有三种组成:基于规则的、基于统计的、混合分词
基于规则的分词在已经建立好词库的前提下,通过扫描文本内容匹配到词库中,若词库中存在文本中某词,则把该词单独提取出来。
基于统计的分词需要建立语料库并设计分词模型,将中文文本通过训练好的模型进行自动分词。
混合分词先进行基于规则的分词、再进行基于统计的分词,这样分词效果最好,但是也最麻烦。
2.1 基于规则的分词
算法思想:在切分语句时,将语句中的每个字符串与词表中的词进行逐一匹配,找到则切分,否则不切分。按照匹配切分方式,可分为正向匹配、逆向匹配、双向匹配。
正向最大匹配算法
算法思想与步骤:
- 假定分词词典中的最长词有m个汉字字符,将待分词的中文文本中当前的前m个字符作为匹配字段,查找匹配字典中的词,若存在这样一个m字词,则匹配成功,该匹配字段被作为一个词切分出来
- 若文本中找不到词典中最长m字词,则匹配失败,将匹配字段的最后一个字去掉,对剩下的m-1字串重新进行匹配处理
- 不断循环处理下去,直到匹配成功,即成功切分一个词或者剩余字符长度为0,这样完成了一轮匹配。然后取下一个m字字串进行匹配处理,直到文本扫描完毕。
class MM(object):
def __init__(self, window_size, dict):
self.window_size = window_size
self.dict = dict
def cut(self, text):
result = []
index = 0
text_length = len(text)
while text_length > index:
for size in range(self.window_size + index, index, -1):
peice = text[index:size]
if peice in self.dict:
index = size - 1
break
index = index + 1
result.append(peice)
return result
逆向最大匹配算法
逆向最大匹配算法算法思想与正向最大匹配算法的差不多,区别在于正向的切分匹配方向从文档的首部开始,逆向的从尾部开始切分。算法思想步骤如下:
- 每次取末端的m个字符作为匹配字段,查找字典并匹配,若匹配失败,则需要去掉匹配字段最前面的一个字,继续匹配。
- 直到匹配成功或者剩余字符数目为0,即完成了且切分
- 切分好的词是逆序词典,每个词条做一个逆序方式存放
class RMM(object):
def __init__(self, window_size, dict):
self.window_size = window_size
self.dict = dict
def cut(self,text):
result = []
index =len(text)
while index>0:
for size in range(index-self.window_size,index):
peice = text[size:index]
if peice in self.dict:
index = size+1
break
index= index-1
result.append(peice)
result.reverse()
return result
实际过程中,我们可以先把文档内容进行倒序排版,然后采用正向最大匹配算法进行切分。
双向匹配算法
算法思想:
分别采用正向最大匹配算法和逆向最大匹配算法的出来的两个切分结果,
- 若两者的切分结果词数不同,取两者中分词数较少的那个结果
- 若两者结果分词数相同,取单字词数目较少的那个。
class BMM()
def __init__(self, dict):
self.dict = dict
def cut(self,text):
# 正向
token_mm = MM(3, self.dict)
result_mm=token_mm.cut(text)
token_rmm = RMM(3, self.dict)
result_rmm = token_rmm.cut(text)
# 双向最大匹配
if len(result_mm) == len(result_rmm):
if result_rmm == result_mm:
result = result_mm
else:
temp_mm = 0
for i in range(len(result_mm)):
if len(result_mm[i]) == 1:
temp_mm+=1
temp_rmm = 0
for i in range(len(result_rmm)):
if len(result_rmm[i]) == 1 :
temp_rmm+=1
result = [result_rmm if temp_mm>temp_rmm else result_mm ]
else:
result = [ result_rmm if len(result_mm)>len(result_rmm) else result_mm]
2.2 基于统计的分词
基本思想:
把某个词看做是由词的最小单位的各个字组成,如果相连的字在不同的文本中出现的次数越多,就证明这是一个出现频率很高的词,可靠度很高。
一般步骤:
- 建立语言统计模型,训练模型
- 对句子进行单词划分,对划分结果进行概率计算,获得概率最大的分词结果。
语言模型
语言模型用数学语言描述就是:长度为m的字符串确定其概率分布P(w1.w2,…,wm),其中w1到wm依次表示文本中每个词,采用链式法则计算其概率值,如下式:
当文本过长时,计算难度加大,使用N元模型在估计条件概率时,忽略距离大于n的上文词的影响可以减少计算量
一元模型:
二元模型:
三元模型:
当n越来越大时,计算量成指数增长,长度越长的文本序列出现的次数也会越少,使用频率计数的比例来计算n元条件概率
其中公式分母指词语在语料库中出现的总次数
注意:估计n元条件概率时,容易出现分子分母为0的情况,需要配合相应的平滑算法解决该问题。
隐马尔科模型HMM
HMM模型是将分词作为字在字串中的序列标注任务来完成的,基本思路:每个字在构造一个特定的词语时都占据一个确定的构词位置(即词位),现规定标签B(词首)、M(词中)、E(词尾)、S(单独成词),
eg.研究生/要/读/三年使用词位标注是
研/B究/M生/E/要/S/读/S/三/B年/E
用数学语言表达是,
用贝叶斯公式转换可得
这里可以进一步优化,每个输出仅仅与上一个输出有关,这叫齐次马尔可夫假设,也叫二元模型:
于是有:
使用HMM求解
常用一个Veterbi算法,该算法是一种动态规划算法:每一个节点Oi只会影响其前后两个的节点P(Oi-1 | Oi) 和 P(Oi | Oi+1) ,所以如果最终的最优路径经过某个Oi,那么从初始节点到Oi-1的路径必然也是一个最优路径根据这个思想,可以通过递推的方法在求每个Oi时只需要求出所有经过各Oi-1的候选点的最优路径,然后再和当前的Oi结合比较,就可以逐步找出最优路径。
统计分词实现步骤如下:
- 使用已经分好词的训练集去训练HMM模型,计算频数得到HMM的三要素(初始状态概率,状态转移概率和发射概率)
- 使用Viterbi算法以及训练好的三个概率矩阵,将待分词的句子转换为’BMES’类型的状态序列。
- 根据已经求出的状态序列,划分句子进行分词,得出分词结果。
实现代码可以参考Github上的代码。代码链接地址:基于统计分词实现代码
三、总结
对文本进行中文分词,当文本内容不多时且比较简单,采用基于规则的分词技术,比较快;当随着输入量比较大,采用基于统计的分词技术,通过训练模型进行快速分词,取得比较好的效果,多用于大型企业比较多。