正向最大匹配分词
- 最大正向匹配(FMM)的基本思想是:假设自动分词词典中的最长词条所含汉字个数为L,则从左往右取被处理材料S1的前L个字作为匹配字段,查找分词词典。若词典中有这样的一个长度为L的相同词,则匹配成功,匹配字段作为一个词被切分出来;否则,匹配失败,匹配字段去掉最后一个汉字,剩下的字符作为新的匹配字段,进行新的匹配,如此进行下去,直至切分成功或匹配字段为单字为止。
- 举例说明:词典wordDict={u"计算语言学",u"课程",u"课时"},待处理材料S1=u"计算语言学课程有三个课时",词典中所含最大词条包含的汉字个数为5,那么正向最大匹配分词的过程如下:
(1)S2="",S1不为空,从S1左边取出候选子串W="计算语言学";
(2)查词表,“计算语言学”在词表中,将W加入到S2中,S2=“计算语言学/”,并将W从S1中去掉,此时 S1="课程有三个课时";
(3)S1不为空,于是从S1左边取出候选子串W="课程有三个";
(4)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程有三";
(5)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程有";
(6)查词表,W不在词表中,将W最右边一个字去掉,得到W="课程"
(7)查词表,W在词表中,将W加入到S2中,S2=“计算语言学/课程/”,并将W从S1中去掉,此时S1="有三个课时";
(8)S1不为空,于是从S1左边取出候选子串W="是三个课时";
(9)查词表,W不在词表中,将W最右边一个字去掉,得到W="有三个课";
(10)查词表,W不在词表中,将W最右边一个字去掉,得到W="有三个";
(11)查词表,W不在词表中,将W最右边一个字去掉,得到W="有三"
(12)查词表,W不在词表中,将W最右边一个字去掉,得到W=“有”,这时 W是单字,将W加入到S2中,S2=“计算语言学/课程/有/”,并将W从S1中去掉,此时S1="三个课时";
(13)S1不为空,从S1左边取出候选子串W="三个课时";
(14)查词表,W不在词表中,将W最右边一个字去掉,得到W="三个课";
(15)查词表,W不在词表中,将W最右边一个字去掉,得到W="三个";
(16)查词表,W不在词表中,将W最右边一个字去掉,得到W=“三”,这时 W是单字,将W加入到S2中,S2=“计算语言学/课程/有/三/”,并将W从S1中去掉,此时S1="个课时";
(17)S1不为空,从S1左边取出候选子串W="个课时";
(18)查词表,W不在词表中,将W最右边一个字去掉,得到W="个课";
(19)查词表,W不在词表中,将W最右边一个字去掉,得到W=“个”,这时W是单字,将W加入到S2中,S2=“计算语言学/课程/有/三/个/",并将W从S1中去掉,此时S1="课时";
(20)S1不为空,从S1左边取出候选子串W="课时";
(21)查词表,W在词表中,将W加入到S2中,S2=“计算语言学/课程/有/三/个/课时/",并将W从S1中去掉,此时S1=""。
(22)S1为空,输出S2作为分词结果,分词过程结束。
- 与FMM方法相对应的方法是反向最大匹配分词方法,也称为RMM方法。它的分词过程与FMM方法相同,不过是从句子(或文章)末尾开始处理,每次匹配不成功时去掉的是前面的一个汉字。
- python 代码示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
中文分词算法
"""
def FMM(wordDict, maxLen, match_string):
"""
正向最大匹配算法
:param wordDict: 词典
:param maxLen: 匹配最大长度
:param match_string: 待匹配字符串
:return: 匹配结果
"""
wordList = []
segStrLen = len(match_string)
while segStrLen > 0:
if segStrLen > maxLen:
wordLen = maxLen
else:
wordLen = segStrLen
subStr = match_string[0:wordLen]
while wordLen > 1:#词典中有匹配词/单字,退出
if subStr in wordDict:
break
else:
wordLen = wordLen - 1
subStr = subStr[0:wordLen]
wordList.append(subStr)
match_string = match_string[wordLen:]
segStrLen = segStrLen - wordLen
return "/".join(wordList)
def RMM(wordDict, maxLen, match_string):
"""
逆向最大匹配算法
:param wordDict: 词典
:param maxLen: 匹配最大长度
:param match_string: 待匹配字符串
:return: 匹配结果
"""
wordList = []
segStrLen = len(match_string)
while segStrLen > 0:
if segStrLen > maxLen:
wordLen = maxLen
else:
wordLen = segStrLen
subStr = match_string[-wordLen:]
while wordLen > 1:#词典中有匹配词/单字,退出
if subStr in wordDict:
break
else:
wordLen = wordLen - 1
subStr = subStr[-wordLen:]
wordList.append(subStr)
match_string = match_string[0:-wordLen]
segStrLen = segStrLen - wordLen
return "/".join(wordList)
def exper():
wordDict = [u"计算语言学",u"课程",u"课时"]
S1 = u"计算语言学课程有三个课时"
maxLen = 5
print FMM(wordDict,maxLen,S1)
print RMM(wordDict, maxLen, S1)
if __name__ == '__main__':
exper()
- 与基于词网格分词的第一步是候选词网格构造:利用词典匹配,列举输入句子所有可能的切分词语,并以词网格形式保存。实际上,词网格是一个有向无环图,它蕴含了输入句子所有可能的切分,其中的每一条路径代表一种切分。如下图“中国人民生活“的切分词网:
- 词网分词的第二步是计算词网格中的每一条路径的权值,权值通过计算图中每一个节点(每一个词)的一元统计概率和节点之间的二元统计概率的相关信息。然后根据图搜索算法在图中找到一条权值最小的路径,对应的路径即为最后的分词结果。
- 比较FMM法与RMM法的切分结果,从而决定正确的切分(比较规则可以自定义),可以识别出分词中的交叉歧义。