python双向最大匹配算法_中文分词引擎 python实现 — 正向最大、逆向最大、双向最大匹配法...

正向最大匹配法

分词目标:

在词典中进行扫描,尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配。

算法流程:

假设词典中最长的单词为 5 个(MAX_LENGTH),那么最大匹配的起始子串字数也为 5 个

(1)扫描字典,测试读入的子串是否在字典中

(2)如果存在,则从输入中删除掉该子串,重新按照规则取子串,重复(1)

(3)如果不存在于字典中,则从右向左减少子串长度,重复(1)

分词实例:

比如说输入 “北京大学生前来应聘”,

第一轮:取子串 “北京大学生”,正向取词,如果匹配失败,每次去掉匹配字段最后面的一个字

“北京大学生”,扫描 5 字词典,没有匹配,子串长度减 1 变为“北京大学”

“北京大学”,扫描 4 字词典,有匹配,输出“北京大学”,输入变为“生前来应聘”

第二轮:取子串“生前来应聘

“生前来应聘”,扫描 5 字词典,没有匹配,子串长度减 1 变为“生前来应”

“生前来应”,扫描 4 字词典,没有匹配,子串长度减 1 变为“生前来”

“生前来”,扫描 3 字词典,没有匹配,子串长度减 1 变为“生前”

“生前”,扫描 2 字词典,有匹配,输出“生前”,输入变为“来应聘””

第三轮:取子串“来应聘”

“来应聘”,扫描 3 字词典,没有匹配,子串长度减 1 变为“来应”

“来应”,扫描 2 字词典,没有匹配,子串长度减 1 变为“来”

颗粒度最小为 1,直接输出“来”,输入变为“应聘”

第四轮:取子串“应聘

“应聘”,扫描 2 字词典,有匹配,输出“应聘”,输入变为“”

输入长度为0,扫描终止

正向匹配法最终的切分结果为:”北京大学 / 生前 / 来 / 应聘”

dictionary = ["北京大学","生前","前来","来","北京","大学","应聘","大学生"]

MAX_LENGTH = 5

def leftMax(inputstr):

results = list()

while( len(inputstr) > 0 ):

subSeq = "";

# 每次取小于或者等于最大字典长度的子串进行匹配

if len(inputstr) < MAX_LENGTH :

subSeq = inputstr

else:

subSeq = inputstr[:MAX_LENGTH]

while len(subSeq) > 0 :

# 如果字典中含有该子串或者子串颗粒度为1,子串匹配成功

if (subSeq in dictionary) or (len(subSeq) == 1) :

results.append(subSeq)

# 输入中从前向后去掉已经匹配的子串

inputstr = inputstr[len(subSeq):]

# 退出循环,进行下一次匹配

break;

else:

# 去掉匹配字段最后面的一个字

subSeq = subSeq[:len(subSeq)-1]

return results;

leftMax("北京大学生前来应聘")

逆向最大匹配法

分词目标:

在词典中进行扫描,尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配。

在实践中,逆向最大匹配算法性能优于正向最大匹配算法。

算法流程

假设词典中最长的单词为 5 个(MAX_LENGTH),那么最大匹配的起始子串字数也为 5 个

(1)扫描字典,测试读入的子串是否在字典中

(2)如果存在,则从输入中删除掉该子串,重新按照规则取子串,重复(1)

(3)如果不存在于字典中,则从左向右减少子串长度,重复(1)

分词实例

比如说输入 “北京大学生前来应聘”,

第一轮:取子串 “生前来应聘”,逆向取词,如果匹配失败,每次去掉匹配字段最前面的一个字

“生前来应聘”,扫描 5 字词典,没有匹配,字串长度减 1 变为“前来应聘”

“前来应聘”,扫描 4 字词典,没有匹配,字串长度减 1 变为“来应聘”

“来应聘”,扫描 3 字词典,没有匹配,字串长度减 1 变为“应聘”

“应聘”,扫描 2 字词典,有匹配,输出“应聘”,输入变为“大学生前来”

第二轮:取子串“大学生前来”

“大学生前来”,扫描 5 字词典,没有匹配,字串长度减 1 变为“学生前来”

“学生前来”,扫描 4 字词典,没有匹配,字串长度减 1 变为“生前来”

“生前来”,扫描 3 字词典,没有匹配,字串长度减 1 变为“前来”

“前来”,扫描 2 字词典,有匹配,输出“前来”,输入变为“北京大学生”

第三轮:取子串“北京大学生”

“北京大学生”,扫描 5 字词典,没有匹配,字串长度减 1 变为“京大学生”

“京大学生”,扫描 4 字词典,没有匹配,字串长度减 1 变为“大学生”

“大学生”,扫描 3 字词典,有匹配,输出“大学生”,输入变为“北京”

第四轮:取子串“北京”

“北京”,扫描 2 字词典,有匹配,输出“北京”,输入变为“” 输入长度为0,扫描终止

dictionary = ["北京大学","生前","前来","来","北京","大学","应聘","大学生"]

MAX_LENGTH = 5

def rightMax(inputstr):

# 采用堆栈处理结果,后进先出

store = []

results = [];

i = 0

while( len(inputstr) > 0 ):

subSeq = ""

# 每次取小于或者等于最大字典长度的子串进行匹配

if len(inputstr) < MAX_LENGTH :

subSeq = inputstr

else:

subSeq = inputstr[len(inputstr)-MAX_LENGTH:]

while( len(subSeq) > 0 ) :

# 如果字典中含有该子串或者子串颗粒度为1,子串匹配成功

if (subSeq in dictionary) or (len(subSeq) == 1) :

store.append(subSeq)

# 输入中从后向前去掉已经匹配的子串

inputstr = inputstr[:len(inputstr) - len(subSeq)]

break;

else:

# 去掉匹配字段最前面的一个字

subSeq = subSeq[1:]

for _ in range(len(store)):

results.append(store.pop())

return results

rightMax("北京大学生前来应聘")

双向最大匹配法

分词目标

将正向最大匹配算法和逆向最大匹配算法进行比较,从而确定正确的分词方法。

算法流程:

比较正向最大匹配和逆向最大匹配结果

如果分词数量结果不同,那么取分词数量较少的那个

如果分词数量结果相同

分词结果相同,可以返回任何一个

分词结果不同,返回单字数比较少的那个

分词实例:

就上例来看,

正向匹配最终切分结果为:北京大学 / 生前 / 来 / 应聘,分词数量为 4,单字数为 1

逆向匹配最终切分结果为:”北京/ 大学生/ 前来 / 应聘,分词数量为 4,单字数为 0

返回单字数量少的匹配方式

逆向匹配单字数少,因此返回逆向匹配的结果。

双向最大匹配法实现如下:

def segment(inputstr):

fmm = leftMax(inputstr)

bmm = rightMax(inputstr)

print(fmm)

print(bmm)

# 如果分词的结果不同,返回长度较小的

if len(fmm) > len(bmm):

return bmm

elif len(fmm) < len(bmm):

return fmm

else :

# 如果分词的词数相同

fmmSingle = 0

bmmSingle = 0

isEqual = True

for i in range(len(bmm)):

if fmm[i] != bmm[i]:

isEqual = False

if len(fmm[i]) == 1:

fmmSingle =+ 1

if len(bmm[i]) == 1:

bmmSingle =+ 1

# 如果正向、逆向匹配结果完全相等,返回任意结果

if isEqual:

return fmm;

# 否则,返回单字数少的匹配方式

elif fmmSingle > bmmSingle:

return bmm;

else :

return fmm;

segment("北京大学生前来应聘")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值