文章目录
1. 前向最大匹配算法
1.1 前向最大匹配算法的原理
首先,我们分词的目的是将一段中文分成若干个词语,前向最大匹配就是从前向后寻找在词典中存在的词。
废话不多说,直接上例子:
首先我们假设Max_len = 5,即假设单词的最大长度为5。
再假设我们现在词典中存在的词有:
[“我们”, “经常”,“常有”, “有意见”,“有意”, “意见”, “分歧”,
“我”,“们”,“经”,“常”,“有”,“意”,“见”]
现在,我们用前向最大匹配算法来划分 我们经常有意见分歧 这句话。
例:我们经常有意见分歧(max_len = 5)
第一轮:取子串 “我们经常有”,正向取词,如果匹配失败,每次去掉匹配字段最后面的一个字。
- “我们经常有”,扫描词典中的5字单词,没有匹配,子串长度减 1 变为“我们经常”。
- “我们经常”,扫描词典中的4字单词,没有匹配,变为“我们经”。
- “我们经”,扫描词典中的3字单词,没有匹配, 变为“我们”。
- “我们”,扫描词典中的2字单词,匹配成功,输出“我们”,输入变为“经常有意见分歧”。
第二轮:取子串“经常有意见”
- “经常有意见”,扫描词典中的5字单词,没有匹配,子串长度减 1 变为“经常有意”。
- “经常有意”,扫描词典中的4字单词,没有匹配,子串长度减 1 变为“经常有”。
- “经常有”,扫描词典中的3字单词,没有匹配,子串长度减 1 变为“经常”。
- “经常”,扫描词典中的2字单词,有匹配,输出“经常”,输入变为“有意见分歧”。
以此类推,直到输入长度为0时,扫描终止。
最终,前向最大匹配算法得出的结果为:
我们 / 经常 / 有意见 / 分歧
1.2 前向最大匹配算法的Python实现
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 19 08:57:56 2018
@author: Lenovo
"""
test_file = 'train/train.txt'#训练语料
test_file2 = 'test/test.txt'#测试语料
test_file3 = 'test_sc/test_sc_zhengxiang.txt'#生成结果
def get_dic(test_file): #读取文本返回列表
with open(test_file,'r',encoding='utf-8',) as f:
try:
file_content = f.read().split()
finally:
f.close()
chars = list(set(file_content))
return chars
dic = get_dic(test_file)
def readfile(test_file2):
max_length = 5
h = open(test_file3,'w',encoding='utf-8',)
with open(test_file2,'r',encoding='utf-8',) as f:
lines = f.readlines()
for line in lines:#分别对每行进行正向最大匹配处理
max_length = 5
my_list = []
len_hang = len(line)
while len_hang>0 :
tryWord = line[0:max_length]
while tryWord not in dic:
if len(tryWord)==1:
break
tryWord=tryWord[0:len(tryWord)-1]
my_list.append(tryWord)
line = line[len(tryWord):]
len_hang = len(line)
for t in my_list:#将分词结果写入生成文件
if t == '\n' :
h.write('\n')
else:
h.write(t + " ")
h.close()
readfile(test_file2)
代码摘录于https://www.cnblogs.com/Jm-15/p/9403352.html
2. 后向最大匹配算法
2.1 后向最大匹配算法的原理
与前向最大匹配算法类似,只是方向相反,即从后向前寻找词典中存在的词并输出。
例:我们经常有意见分歧(max_len = 5)
第一轮:取子串 “有意见分歧”,后向取词,如果匹配失败,每次去掉匹配字段最前面的一个字。
- “有意见分歧”,扫描词典中的5字单词,没有匹配,子串长度减 1 变为“意见分歧”。
- “意见分歧”,扫描词典中的4字单词,没有匹配,变为“见分歧”。
- “见分歧”,扫描词典中的3字单词,没有匹配, 变为“分歧”。
- “分歧”,扫描词典中的2字单词,匹配成功,输出“分歧”,输入变为“我们经常有意见”。
第二轮:取子串“经常有意见”
- “经常有意见”,扫描词典中的5字单词,没有匹配,子串长度减 1 变为“常有意见”。
- “常有意见”,扫描词典中的4字单词,没有匹配,子串长度减 1 变为“有意见”。
- “有意见”,有匹配,输出“有意见”,输入变为“我们经常”。
以此类推,直到输入长度为0时,扫描终止。
最终,后向最大匹配算法得出的结果为:
我们 / 经常 / 有意见 / 分歧
可见,在此例子中,前向和后向最大匹配算法得到的结果相同。
但是,如果我们去掉词典中的[有意见]一词,
我们使用前向所得到的结果是: 我们 / 经常 / 有意 / 见 / 分歧
我们使用后向所得到的结果是: 我们 / 经 / 常有 / 意见 / 分歧
可以看到,前向和后向最大匹配算法得到得结果不一样了,一般来说,80%的情况是一样的,20%的可能不一样。同时可以看出,词典或者叫做词库 对于分词结果的质量的影响非常大!
2.2 后向最大匹配算法的python实现
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 19 08:57:56 2018
@author: Lenovo
"""
test_file = 'train/train.txt'
test_file2 = 'test/test.txt'
test_file3 = 'test_sc/test_sc.txt'
def get_dic(test_file):
with open(test_file,'r',encoding='utf-8',) as f:
try:
file_content = f.read().split()
finally:
f.close()
chars = list(set(file_content))
return chars
dic = get_dic(test_file)
def readfile(test_file2):
max_length = 5
h = open(test_file3,'w',encoding='utf-8',)
with open(test_file2,'r',encoding='utf-8',) as f:
lines = f.readlines()
for line in lines:
my_stack = []
len_hang = len(line)
while len_hang>0 :
tryWord = line[-max_length:]
while tryWord not in dic:
if len(tryWord)==1:
break
tryWord=tryWord[1:]
my_stack.append(tryWord)
line = line[0:len(line)-len(tryWord)]
len_hang = len(line)
while len(my_stack):
t = my_stack.pop()
if t == '\n' :
h.write('\n')
else:
h.write(t + " ")
h.close()
readfile(test_file2)
代码摘录于https://www.cnblogs.com/Jm-15/p/9403352.html
训练语料和测试语料库:
链接: https://pan.baidu.com/s/1X0coEznut6_s0jsDG9_9Dg 密码: b393
3. 双向最大匹配算法
3.1 双向最大匹配算法的原理
双向最大匹配算法的原理就是将正向最大匹配算法和逆向最大匹配算法进行比较,从而确定正确的分词方法。
步骤如下:
- 比较正向最大匹配和逆向最大匹配结果。
- 如果分词数量结果不同,那么取分词数量较少的那个。
如果分词数量结果相同:
1.分词结果相同,可以返回任何一个。
2.分词结果不同,返回单字数比较少的那个,
如果单字数个数也相同,则任意返回一个。
3.2 双向最大匹配算法的python实现
-- coding: utf-8 --
class MM():
def init(self):
self.window_size = 3
def cut(self,text):
result = []
index = 0
text_length = len(text)
dic = ['研究','研究生','生命','命','的','起源']
while text_length > index:
for size in range(self.window_size+index,index,-1):
piece = text[index:size]
if piece in dic:
index = size - 1
break
index = index + 1
result.append(piece+'----')
return(result)
class RMM():
def init(self):
self.window_size = 3
def cut(self,text):
result = []
index = 0
index = len(text)
dic = ['研究','研究生','生命','命','的','起源']
while index > 0:
for size in range(index - self.window_size,index,):
piece = text[size:index]
if piece in dic:
index = size + 1
break
index = index - 1
result.append(piece+'----')
result.reverse()
return(result)
if __name__ == '__main__':
text = '研究生命的起源'
count1 = 0
count2 = 0
First = MM()
Second = RMM()
a = First.cut(text)
b = Second.cut(text)
if a == b:
print(a)
lena = len(a)
lenb = len(b)
if lena == lenb:
for DY1 in a:
if len(DY1) == 5:
count1 = count1 + 1
for DY2 in b:
if len(DY2) == 5:
count2 = count2 + 1
if count1 > count2:
print(b)
else:
print(a)
if lena > lenb:
print(b)
if lena < lenb:
print(a)
代码摘录于https://blog.csdn.net/weixin_43256799/article/details/86098695