草庐IT

分词算法----正向和逆向最大匹配算法(含Python代码实现)

Gaolw1102 2023-04-08 原文

文章目录


分词算法(Segmentation Method)

在文本处理流程中,对语句进行分词(Segmentation)操作对于计算机认识并理解人类语言是基础且重要的。

对于中文来讲,不同于英文直接采用空格符进行分隔,并且中文词语内涵丰厚,语义丰富,所以只有采用合适的分词算法,才能准确迅速地向计算机表达原有的意思,提高工作效率。


最大匹配算法(Maximum Matching)

最大匹配算法是基于词表进行分词操作的,主要包括正向正向最大匹配算法逆向最大匹配算法双向最大匹配算法等。 其主要原理都是切分出单字串(词语),然后和词库进行比对,如果对比成功就记录下来,从整句切除下来, 否则减少一个单字,继续比较,直到字符串全部切除完毕,即分词成功,数组中的所有词语即是分词结果。

以下详细介绍算法的主要思想及具体代码实现。

需要的前提

进行匹配算法的执行前,一定自己要设定一个字典库,通常作为测试即可。
这里我自己使用
字典库

ch_dict = [‘我们’,‘经常’,‘有’,‘有意见’,‘意见’,‘分歧’]

测试语句

sentence = ‘我们经常有意见分歧’

最大匹配值

max_match_len = 5

正向最大匹配算法(Forwards Maximum Match,FMM)

算法主要思想

从字符串的正方向出发,先截取前5个字符,与词典库中的词语进行对比。若比对不成功,则截取前4个字符进行对比,依次类推,直到仅剩第一个字符,自动进行截取,此次截取结束;若对比成功,则将该词语记录下来,并从句子中截取下来。直至句子全部被拆分为词语,以数组进行存储。

算法思想示意图


具体代码实现

'''
(分词算法)正向最大匹配算法
'''
if __name__ == '__main__':

    ch_dict = ['我们','经常','有','有意见','意见','分歧']       #中文的词典库,用于匹配句子中的词语
    sentence = '我们经常有意见分歧'          #例句,需要进行分词
    segment_list = []                      #存放分词后的分词词组

    #例句不为空时,循环地进行分词操作
    while len(sentence) >= 1:
        # 最大匹配单词的长度为5,当然实际意义从3开始即可,因为词典最大单词长度为3
        max_match_len = 5
        #当匹配单词长度大于1时,循环判断分词
        while max_match_len > 1:

            #判断前 max_match_len 个字符是否存在于字典
            if sentence[0:max_match_len] in ch_dict:
                segment_list.append(sentence[0:max_match_len])              #追加到分词词组中
                sentence = sentence[max_match_len:len(sentence)]            #将符合的词语从原例句中截取
                break                   #退出循环,重新从max_match_len最长匹配数开始匹配截取

            max_match_len -= 1          #max_match_len累减,开始匹配4个字符,3个字符,,,

        #只剩下一个汉字时,说明当前不再存在任何符合的词语,直接截取一个汉字作为词组
        if max_match_len == 1:
            segment_list.append(sentence[0:1])          #追加单个汉字词语
            sentence = sentence[1:len(sentence)]        #截取例句

	#输出存放分词的列表
    print(segment_list)
    #输出进行分词后的例句
    print('/'.join(segment_list))               #我们/经常/有意见/分歧

运行结果

['我们', '经常', '有意见', '分歧']
我们/经常/有意见/分歧

Process finished with exit code 0

逆向最大匹配算法(Reverse Maximum Match,RMM)

算法主要思想

刚好与正向最大匹配算法相反,该算法旨在从句子末尾对句子进行分词操作,基本原理同正向最大匹配算法。

算法思想示意图

具体代码实现

'''
(分词算法)后向最大匹配算法
'''

if __name__ == '__main__':

    ch_dict = ['我们','经常','有','有意见','意见','分歧']       #中文的词典库,用于匹配句子中的词语
    sentence = '我们经常有意见分歧'          #例句,需要进行分词
    segment_list = []                      #存放分词后的分词词组

    #例句不为空时,循环地进行分词操作
    while len(sentence) >= 1:
        # 最大匹配单词的长度为5,当然实际意义从3开始即可,因为词典最大单词长度为3
        max_match_len = 5
        #当匹配单词长度大于1时,循环判断分词
        while max_match_len > 1:

            #判断前 max_match_len 个字符是否存在于字典
            if sentence[-max_match_len:] in ch_dict:
                segment_list.append(sentence[-max_match_len:])              #追加到分词词组中
                sentence = sentence[:-max_match_len]            #将符合的词语从原例句中截取
                break                   #退出循环,重新从max_match_len最长匹配数开始匹配截取

            max_match_len -= 1          #max_match_len累减,开始匹配4个字符,3个字符,,,

        #只剩下一个汉字时,说明当前不再存在任何符合的词语,直接截取一个汉字作为词组
        if max_match_len == 1:
            segment_list.append(sentence[-1:])          #追加单个汉字词语
            sentence = sentence[:-1]                    #截取例句

    # 输出进行分词后的例句
    print('/'.join(segment_list))               #分歧/有意见/经常/我们

    #对分词列表进行倒序
    segment_list = segment_list[::-1]
    #再次输出进行分词后的例句
    print('/'.join(segment_list))               # 我们/经常/有意见/分歧

运行结果

分歧/有意见/经常/我们
我们/经常/有意见/分歧

Process finished with exit code 0

双向最大匹配算法

算法的主要思想

双向最大匹配算法是同时采用正向最大匹配算法逆向最大匹配算法,根据对比不同的执行结果,选择最优解。

有以下几种选择方案:

  1. 如果分词数量结果不同:选择数量较少的那个。
  2. 如果分词数量结果相同。
    A. 分词结果相同,返回任意一个。
    B. 分词结果不同,返回单个字数较少的一个。
    C. 若单个字数也相同,任意返回一个。

小结

最大匹配算法在简单场景往往能够发挥出较好的分词效果,但其算法的时间复杂度较高,理解中文歧义问题不够准确,故存在一定的局限性,仅作为低级的分词算法使用。

有关分词算法----正向和逆向最大匹配算法(含Python代码实现)的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  5. ruby - 匹配未转义的平衡定界符对 - 2

    如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。

  6. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  7. ruby - 匹配大写字母并用后续字母填充,直到一定的字符串长度 - 2

    我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种

  8. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  9. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  10. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

随机推荐