zoukankan      html  css  js  c++  java
  • 自然语言处理之中文分词算法

    中文分词算法一般分为三类:

    1.基于词表的分词算法

    • 正向最大匹配算法FMM
    • 逆向最大匹配算法BMM
    • 双向最大匹配算法BM

    2.基于统计模型的分词算法:基于N-gram语言模型的分词算法

    3.基于序列标注的分词算法

    • 基于HMM
    • 基于CRF
    • 基于深度学习的端到端的分词算法

    下面介绍三类基于词表的分词算法

    一、正向最大匹配算法

    概念:对于一般文本,从左到右,以贪心的方式切分出当前位置上长度最大的词。条件是必须基于字典,原理是单词的颗粒度越大,所能表示的含义越确切

    步骤:

    1. 从一个字符串的开始位置选择一个最大长度的词长片段,如果序列不足最大词长,则选择全部序列
    2. 首先看该片段是否在字典中,如果是,则算为一个分出来的词,如果不是,则从右边开始减少一个字符,然后看短一点的这个片段是否在词典中,依次循环,直至剩下单字
    3. 此时序列变为第2步截取分词后剩下的部分序列
    #使用正向最大匹配算法实现中文分词
    words_dict = []#存放载入的词典
    
    def init():
        '''
        读取词典文件
        载入词典
        :return:
        '''
    
        with open("dic/dic.txt","r",encoding="utf8") as dict_input:
            for word in dict_input:
                word_dict.append(word.strip())
    
    #实现正向最大匹配算法中的切词方法
    def cut_words(raw_sentence,words_dict):
        #统计字典中最长的词
        max_length = max(len(word) for word in words_dict)#找到句子中最长的词
        sentence = raw_sentence
        #统计序列长度
        word_length = len(sentence)
        #存储切分好的词语
        cut_word_list = []
        while word_length > 0:
            max_cut_length = min(max_length,max_cut_length)#选取词长和句子长中最小的一个
            subSentence = sentence[0:max_cut_length]
            while max_cut_length > 0:
                if subSentence in words_dict:#如果这个最长的词在我们的词典中,那么它就是最长的词了
                    cut_word_list.append(subSentence)
                    break
                elif max_cut_length == 1:#如果是单字作为一个的时候
                    cut_word_list.append(subSentence)
                    break
                else:#如果这个词不在字典中,并且也不是单字作为一个词的,就要把匹配长度-1
                    max_cut_length = max_cut_length -1
                    subSentence = subSentence[0:max_cut_length]#这时要把右边的词去掉
            sentence = sentence[max_cut_length:]#把找的最大的词去掉,剩下的继续循环
            word_length = word_length - max_cut_length
        # words = "/".join(cut_word_list)
        return cut_word_list
    
    def main():
        """
        用于用户交互
        :return:
        """
        init()
        while True:
            print("请输入要分词的序列")
            input_str = input()
            if not input_str:
                break
            result = cut_words(input_str,word_dict)
            print("分词结果",result)
    
    if __name__ == '__main__':
        main()
    

      

    二、逆向最大匹配算法

    BMM与FMM类似,只是分词顺序变为从右至左

    但是,BMM和FMM对于歧义词的处理能力一般

    #使用逆向最大匹配算法实现中文分词
    words_dict = []
    
    def init():
        """
        读取字典文件
        获取字典
        :return:
        """
        with open("dict/dic.txt","r",encoding="utf8") as dic_input:
            for word in dic_input:
                words_dict.append(word.strip())
    
    #实现逆向最大匹配算法中的切词方法
    def cut_words(raw_sentence,words_dict):
        #统计词典中词的最大长度
        max_length = max(len(word) for word in words_dict)
        sentence = raw_sentence.strip()
        #统计序列长度
        words_length = len(sentence)
        #存储切分好的词
        cut_word_list = []
        #判断是否需要继续切词
        while words_length > 0:
            max_cut_length = min(max_length, max_cut_length)  # 选取词长和句子长中最小的一个
            subSentence = sentence[-max_cut_length:]#从后往前取max_cut_length这么长
            while max_cut_length > 0:
                if subSentence in words_dict:
                    cut_word_list.append(subSentence)
                    break
                elif max_cut_length == 1:
                    cut_word_list.append(subSentence)
                    break
                else:
                    max_cut_length = max_cut_length -1
                    subSentence = subSentence[-max_cut_length:]
            sentence = sentence[0:-max_cut_length]
            words_length = words_length - max_cut_length
        cut_word_list.reverse()#切完之后的词是乱序的  这里为其逆序一下
        # words = "/".join(cut_word_list)
        return  cut_word_list
    
    def main():
        """
        用于用户交互
        :return:
        """
        init()
        while True:
            print("请输入要分词的序列:")
            input_str = input()
            if not input_str:
                break
            result = cut_words(input_str,word_dict)
            print("分词结果:",result)
    
    if __name__ == '__main__':
        main()
    

    三、双向最大匹配算法

    BI是将FMM和BMM得到的结果进行比较,得到正确的分词方法

    启发式规则:

    1. 如果正、反向分词结果词数不同,则取分词数量较少的那个
    2. 如果分词词数相同:
    • 分词的结果相同,则说明没有歧义,可返回任意一个
    • 分词结果不同,则返回单字较少的那个
    import BMM,FMM
    #使用双向最大匹配算法实现中文分词
    words_dict = []
    
    def init():
        """
        读取字典文件
        获取字典
        :return:
        """
        with open("dict/dic.txt","r",encoding="utf8") as dic_input:
            for word in dic_input:
                words_dict.append(word.strip())
    
    #实现双向最大匹配算法中的切词方法
    def cut_words(raw_sentence,words_dict):
        bmm_word_list = BMM.cut_words(raw_sentence,words_dict)
        fmm_word_list = FMM.cut_words(raw_sentence,words_dict)
        bmm_word_list_size = len(bmm_word_list)
        fmm_word_list_size = len(fmm_word_list)
        if bmm_word_list_size != fmm_word_list_size:
            if bmm_word_list_size < fmm_word_list_size:
                return bmm_word_list
            else:
                return fmm_word_list
        else:
            FSingle = 0
            BSingle = 0
            isSame = True
            for i in range(len(fmm_word_list)):
                if fmm_word_list[i] not in bmm_word_list:#如果fmm和bmm的分词结果是不相同的
                    isSame = False
                if len(fmm_word_list[i]) == 1:
                    FSingle = FSingle + 1#如果fmm列表里的词长度为1,也就是说是单个词,那么就把单个词的数量+1
                if len(bmm_word_list[i]) == 1:
                    BSingle = BSingle + 1
            if isSame:
                return fmm_word_list
            elif BSingle > FSingle:
                return fmm_word_list
            else:
                return bmm_word_list
    
    
    def main():
        """
        用于用户交互
        :return:
        """
        init()
        while True:
            print("请输入要分词的序列:")
            input_str = input()
            if not input_str:
                break
            result = cut_words(input_str,words_dict)
            print("分词结果:",result)
    
    if __name__ == '__main__':
        main()
    

      

  • 相关阅读:
    strong和copy的区别
    xib托线出来的为什么是weak而不是strong
    iOS 序列化与反序列化
    iOS开发- 蓝牙后台接收数据(BLE4.0)
    iOS开发拓展篇-XMPP简单介绍
    OS开发拓展篇—应用之间的跳转和数据传
    ERROR 1130: Host '192.168.1.3' is not allowed to connect to this MySQL ERROR 1062 (23000): Duplicate entry '%-root' for key 'PRIMARY'
    什么是低8位?
    Eclipse自动生成作者、日期注释等功能设置
    eclipse重构变量名的快捷键, 批量修改变量名的快捷键
  • 原文地址:https://www.cnblogs.com/bep-feijin/p/9639932.html
Copyright © 2011-2022 走看看