zoukankan      html  css  js  c++  java
  • 最大匹配算法

    中文分词:最大匹配算法

    (一)引言

    分词是自然语言处理中非常常见的操作,也是必不可少的文本数据预处理步骤。各国语言的表达方式和书写方式截然不同,因此分词的方式和难度也不同。英文分词是最简单的,因为每个单词已经用空格自动分词了,比如"I like Chinese" 这个句子已经被分成了三个单词。当然,英文分词也是有难点的,比如单词大小写所代表的含义不同以及各种符号的用法,这里暂不讨论。中文是汉字为基本书写单位,词语甚至句子之间并没有明显的区分标记,并且不同的词组合容易产生歧义。比如:“结婚的和尚未结婚的”,计算机很难判断是分成“结婚/的/和/尚未/结婚/的”还是“结婚/的/和尚/未/结婚/的”。因此,中文分词是一项非常具有挑战性的工作。
    现今,中文分词方法一般被分为三类:
    (1)基于字典的分词方法
    (2)基于统计的分词方法
    (3)基于机器学习的分词方法
    本篇文章主要介绍最直接粗暴的方法----基于词典的分词方法。

    (二)正向最大匹配算法

    顾名思义,正向最大匹配是从左到右扫描字符串,在一个给定的词典中寻找词的最大匹配。先看一个例子:
    给定一个句子:“他是研究生物化学的”。
    给定一个词典:["他","是","研究","研究生","生物","物化","化学","学","的"]。
    思路:先获得词典中词的最大长度m,这个例子中m为3;给字符串初始位置一个指针pi,即在“他”的位置;从当前指针起取m个字作为词(也可以直接到字符串末尾作为词,但是效率低),即“他是研”;选出的词如果在词典中,就在词的后面进行划分,然后指针移动到这个词后面的一个字,如果选出的词不在词典中,就把选出的词长度减一(即m-1),“他是研”就变成了“他是”,然后在进行此步骤的操作。
    算法流程:
    输入:字符串 s
    过程:

    1. 令指针 pi 指向 s 的初始位置
    2. repeat
    3. 计算当前指针 pi 到字串末端的字数(即未被切分字串的长度) n
    4. 令 m=词典中最长单词的字数,如果 n<m, 令 m=n
    5. 从当前 pi 起取 m 个汉字作为词 wi
    6. **if  wi **在词典中
    7. then 在 wi 后添加一个切分标志,根据 wi 的长度修改指针 pi
    8. ** else**
    9. 将 wi 从右端去掉一个字
    10. until pi 指向字串末端
      输出: 添加切分标志后的字符串 s

    示例代码:

    text = "他是研究生物化学的"
    Dict = ["他","是","研究","研究生","生物","物化","化学","学","的"]
    
    def forword_Match(text, Dict):
        '''前向最大匹配'''
        word_list = []
        pi = 0    #初始位置
        #找出字典中的最长的词的长度
        m = max([len(word) for word in Dict])
        while pi != len(text):
            n = len(text[pi:])    #当前指针到字符串末尾的长度
            if n < m:
                m = n
            for index in range(m,0,-1):      #从当前 pi 起取 m 个汉字作为词 
                if text[pi:pi+index] in Dict:
                    word_list.append(text[pi:pi+index])
                    pi = pi + index         # 根据词的长度修改指针pi
                    break
        print('/'.join(word_list))
        
    forword_Match(text, Dict)    
     ## 输出:  他/是/研究生/物化/学/的
    

    (三)逆向最大匹配算法

    可以想到,逆向最大匹配是从右到左扫描字符串,在一个给定的词典中寻找词的最大匹配。先看一个例子:
    给定一个句子:“他是研究生物化学的”。
    给定一个词典:["他","是","研究","研究生","生物","物化","化学","学","的"]。
    思路:先获得词典中词的最大长度m,这个例子中m为3;给字符串末尾位置一个指针pi,即在“的”的位置;从当前指针向左取m个字作为词(也可以直接到字符串开头作为词,但是效率低),即“化学的”;选出的词如果在词典中,就在词的前面进行划分,然后指针移动到这个词前面的一个字,如果选出的词不在词典中,就把选出的词长度减一(即m-1),“化学的”就变成了“学的”,然后在进行此步骤的操作。
    算法流程:
    输入:字符串 s
    过程:

    1. 令指针 pi 指向 s 的末尾位置
    2. repeat
    3. 计算当前指针 pi 到字串开头的字数(即未被切分字串的长度) n
    4. 令 m=词典中最长单词的字数,如果 n<m, 令 m=n
    5. 从当前 pi 起取往左取m个汉字作为词 wi
    6. **if  wi **在词典中
    7. then 在 wi 前面添加一个切分标志,根据 wi 的长度修改指针 pi
    8. ** else**
    9. 将 wi 从左端去掉一个字
    10. until pi 指向字串开头
      输出: 添加切分标志后的字符串 s

    示例代码:

    text = "他是研究生物化学的"
    Dict = ["他","是","研究","研究生","生物","物化","化学","学","的"]
    
    def back_Match(text, Dict):
        '''逆向最大匹配'''
        word_list = []
        pi = len(text) - 1
        m = max(len(word) for word in Dict)
        while pi >= 0:
            n = len(text[0:pi+1])
            if n < m:
                m = n
            for index in range(m-1,-1,-1):
                if text[pi-index:pi+1] in Dict:
                    word_list.append(text[pi-index:pi+1])
                    pi = pi - index -1
                    break
    
        print('/'.join(word_list[::-1]))
    
    back_Match(text, Dict)
    ## 输出:  他/是/研究/生物/化学/的
    

    至此就完成了基于词典的中文分词方法,但是这种方法过度依赖于词典。如果词典质量不高(比如容量小、记录不全等)会影响分类效果,还有一些会产生歧义的句子也不适合用这种方法。接下来我们会一起学习基于统计的分词方法......

  • 相关阅读:
    [转贴]Linux内核LTS长期支持版生命周期
    【转贴】Debian 10 "buster" 正式发布
    [百度经验]重置组策略的方法
    【转贴】我对测试工作的一些认识
    【转贴】使用sar进行性能分析
    【转贴】龙芯内核发展策略 已经支持k8s
    【转贴】优秀的龙芯Docker虚拟机解决方案
    Windows 2016 安装单机版本Oracle ASM 的简单说明
    【转贴】中标麒麟操作系统(龙芯版)与360安全浏览器完成产品兼容性互认证测试
    AQTime教程
  • 原文地址:https://www.cnblogs.com/dahuang123/p/11990651.html
Copyright © 2011-2022 走看看