切分算法
分词算法的核心是速度。
1、完全切分
完全切分:找出一段文本中所有的分词。主要这实际上不是标准意义上的分词,因为这个算法会把单个字全部输出,并没有考虑到是否是有意义的词语序列。例如:“北京大学”切分得到的结果是[‘北’, ‘北京’, ‘北京大学’, ‘京’, ‘大’, ‘大学’, ‘学’]。
代码实现:遍历文本中词是否在词典中即可。
from load_dictionary import load_dictionary
def fully_segment(text, dic):
word_list = []
for i in range(len(text)):
for j in range(i, len(text)+1):
word = text[i:j]
if word in dic:
word_list.append(word)
return word_list
if __name__ == '__main__':
dic = load_dictionary()
word_list = fully_segment("商品和服务", dic)
print(word_list)
2、正向最长匹配
正向最长匹配:其实是在完全切分上做了一个约束,遍历在以某个下标为起点正向遍历的过程中,优先输出最长的单词。
def forward_segment(text, dic):
word_list = []
i = 0
while i <len(text):
longest_word = text[i]
for j in range(i+1, len(text)+1):
word = text[i:j]
# 这里其实只需要判断word是否在词典中,而不用判断是否是最长的
# 因为j是在不断增大的
if word in dic:
longest_word = word
i += len(longest_word)
word_list.append(longest_word)
return word_list
3、逆向最长匹配
逆向最长匹配:顾名思义就是逆向开始匹配,和正向最长匹配正好相反。
def backward_segment(text, dic):
word_list = []
i = len(text)-1
while i > 0:
longest_word = text[i]
for j in range(0, i):
word = text[j:i+1]
if word in dic and len(longest_word)<len(word):
longest_word = word
i -= len(longest_word)
word_list.append(longest_word)
return word_list
4、双向最长匹配
双向最长匹配:
(1)同时执行正向、逆向最长匹配,若词数不同,返回词数少的那个分词;
(2)若词数相同,则返回单字词更少的那个
def count_single_char(word_list):
"""
统计单个字符的单词
:param word_list:
:return:
"""
return sum(1 for word in word_list if len(word))==1
def bidirectional_segment(text, dic):
forward = forward_segment(text=text, dic=dic)
backward = backward_segment(text=text, dic=dic)
# print(f"forward segment: {forward}")
# print(f"backward segment: {backward}")
if len(forward)<len(backward):
return forward
elif len(forward)>len(backward):
return backward
else:
if count_single_char(forward)>count_single_char(backward):
return backward
else:
return forward
5、总结
词典分词的核心在速度,不在精度。其实上面几种切分算法,都只是在借用简单的分词规则或者经验,来进行朴素的分词,达不到消除消除歧义等能力,而且没有借助复杂数据结构,相对于的算法复杂度较高。
就只考虑后三种切分算法而言,显然双向匹配算法速度最慢,正向和逆向差不多。
速度测试代码如下:
import time
from load_dictionary import load_dictionary
from forward_segment import forward_segment
from backward_segment import backward_segment
from bidirectional_segment import bidirectional_segment
def evaluate_speed(segment, text, dic, pressure):
start = time.time()
for i in range(pressure):
segment(text, dic)
elapsed_time = time.time()-start
print("%s :%.2f 万字/秒" %(segment.__name__,len(text)*pressure/10000/elapsed_time))
if __name__ == '__main__':
text = "江西鄱阳湖干枯,中国最大淡水湖变成大草原"
pressure = 10000
dic = load_dictionary()
evaluate_speed(forward_segment, text, dic, pressure)
evaluate_speed(backward_segment, text, dic, pressure)
evaluate_speed(bidirectional_segment, text, dic, pressure)
本机效果:
forward_segment :89.16 万字/秒
backward_segment :84.22 万字/秒
bidirectional_segment :39.64 万字/秒
本文介绍了四种基本的分词算法:完全切分、正向最长匹配、逆向最长匹配和双向最长匹配。这些算法在速度上有显著差异,其中双向匹配速度最慢,而正向和逆向匹配速度相近。通过代码示例展示了每种算法的工作原理,并进行了速度测试。词典分词注重速度而非精度,这些朴素的分词方法无法消除歧义,适用于简单场景。
8455

被折叠的 条评论
为什么被折叠?



