中文分词算法一般分为三类:
1.基于词表的分词算法
- 正向最大匹配算法FMM
- 逆向最大匹配算法BMM
- 双向最大匹配算法BM
2.基于统计模型的分词算法:基于N-gram语言模型的分词算法
3.基于序列标注的分词算法
- 基于HMM
- 基于CRF
- 基于深度学习的端到端的分词算法
下面介绍三类基于词表的分词算法
一、正向最大匹配算法
概念:对于一般文本,从左到右,以贪心的方式切分出当前位置上长度最大的词。条件是必须基于字典,原理是单词的颗粒度越大,所能表示的含义越确切
步骤:
- 从一个字符串的开始位置选择一个最大长度的词长片段,如果序列不足最大词长,则选择全部序列
- 首先看该片段是否在字典中,如果是,则算为一个分出来的词,如果不是,则从右边开始减少一个字符,然后看短一点的这个片段是否在词典中,依次循环,直至剩下单字
- 此时序列变为第2步截取分词后剩下的部分序列
#使用正向最大匹配算法实现中文分词
words_dict = []#存放载入的词典
def init():
'''
读取词典文件
载入词典
:return:
'''
with open("dic/dic.txt","r",encoding="utf8") as dict_input:
for word in dict_input:
word_dict.append(word.strip())
#实现正向最大匹配算法中的切词方法
def cut_words(raw_sentence,words_dict):
#统计字典中最长的词
max_length = max(len(word) for word in words_dict)#找到句子中最长的词
sentence = raw_sentence
#统计序列长度
word_length = len(sentence)
#存储切分好的词语
cut_word_list = []
while word_length > 0:
max_cut_length = min(max_length,max_cut_length)#选取词长和句子长中最小的一个
subSentence = sentence[0:max_cut_length]
while max_cut_length > 0:
if subSentence in words_dict:#如果这个最长的词在我们的词典中,那么它就是最长的词了
cut_word_list.append(subSentence)
break
elif max_cut_length == 1:#如果是单字作为一个的时候
cut_word_list.append(subSentence)
break
else:#如果这个词不在字典中,并且也不是单字作为一个词的,就要把匹配长度-1
max_cut_length = max_cut_length -1
subSentence = subSentence[0:max_cut_length]#这时要把右边的词去掉
sentence = sentence[max_cut_length:]#把找的最大的词去掉,剩下的继续循环
word_length = word_length - max_cut_length
# words = "/".join(cut_word_list)
return cut_word_list
def main():
"""
用于用户交互
:return:
"""
init()
while True:
print("请输入要分词的序列")
input_str = input()
if not input_str:
break
result = cut_words(input_str,word_dict)
print("分词结果",result)
if __name__ == '__main__':
main()
二、逆向最大匹配算法
BMM与FMM类似,只是分词顺序变为从右至左
但是,BMM和FMM对于歧义词的处理能力一般
#使用逆向最大匹配算法实现中文分词
words_dict = []
def init():
"""
读取字典文件
获取字典
:return:
"""
with open("dict/dic.txt","r",encoding="utf8") as dic_input:
for word in dic_input:
words_dict.append(word.strip())
#实现逆向最大匹配算法中的切词方法
def cut_words(raw_sentence,words_dict):
#统计词典中词的最大长度
max_length = max(len(word) for word in words_dict)
sentence = raw_sentence.strip()
#统计序列长度
words_length = len(sentence)
#存储切分好的词
cut_word_list = []
#判断是否需要继续切词
while words_length > 0:
max_cut_length = min(max_length, max_cut_length) # 选取词长和句子长中最小的一个
subSentence = sentence[-max_cut_length:]#从后往前取max_cut_length这么长
while max_cut_length > 0:
if subSentence in words_dict:
cut_word_list.append(subSentence)
break
elif max_cut_length == 1:
cut_word_list.append(subSentence)
break
else:
max_cut_length = max_cut_length -1
subSentence = subSentence[-max_cut_length:]
sentence = sentence[0:-max_cut_length]
words_length = words_length - max_cut_length
cut_word_list.reverse()#切完之后的词是乱序的 这里为其逆序一下
# words = "/".join(cut_word_list)
return cut_word_list
def main():
"""
用于用户交互
:return:
"""
init()
while True:
print("请输入要分词的序列:")
input_str = input()
if not input_str:
break
result = cut_words(input_str,word_dict)
print("分词结果:",result)
if __name__ == '__main__':
main()
三、双向最大匹配算法
BI是将FMM和BMM得到的结果进行比较,得到正确的分词方法
启发式规则:
- 如果正、反向分词结果词数不同,则取分词数量较少的那个
- 如果分词词数相同:
- 分词的结果相同,则说明没有歧义,可返回任意一个
- 分词结果不同,则返回单字较少的那个
import BMM,FMM
#使用双向最大匹配算法实现中文分词
words_dict = []
def init():
"""
读取字典文件
获取字典
:return:
"""
with open("dict/dic.txt","r",encoding="utf8") as dic_input:
for word in dic_input:
words_dict.append(word.strip())
#实现双向最大匹配算法中的切词方法
def cut_words(raw_sentence,words_dict):
bmm_word_list = BMM.cut_words(raw_sentence,words_dict)
fmm_word_list = FMM.cut_words(raw_sentence,words_dict)
bmm_word_list_size = len(bmm_word_list)
fmm_word_list_size = len(fmm_word_list)
if bmm_word_list_size != fmm_word_list_size:
if bmm_word_list_size < fmm_word_list_size:
return bmm_word_list
else:
return fmm_word_list
else:
FSingle = 0
BSingle = 0
isSame = True
for i in range(len(fmm_word_list)):
if fmm_word_list[i] not in bmm_word_list:#如果fmm和bmm的分词结果是不相同的
isSame = False
if len(fmm_word_list[i]) == 1:
FSingle = FSingle + 1#如果fmm列表里的词长度为1,也就是说是单个词,那么就把单个词的数量+1
if len(bmm_word_list[i]) == 1:
BSingle = BSingle + 1
if isSame:
return fmm_word_list
elif BSingle > FSingle:
return fmm_word_list
else:
return bmm_word_list
def main():
"""
用于用户交互
:return:
"""
init()
while True:
print("请输入要分词的序列:")
input_str = input()
if not input_str:
break
result = cut_words(input_str,words_dict)
print("分词结果:",result)
if __name__ == '__main__':
main()