美文网首页
基于最大概率的汉语分词 (下)具体实现

基于最大概率的汉语分词 (下)具体实现

作者: 4v3r9 | 来源:发表于2019-01-13 18:58 被阅读12次

    本学期(2018秋季学期)完成了基于最大概率的汉语分词实验,本文为博客第二部分,介绍具体实现过程。实验基于人民日报1998年1月中文语料库,使用Python语言进行中文分词实验。实验实现了FMM、BMM和Bigram算法的分词功能,其中Bigram算法借助前两者分词结果发现歧义,使用Laplace平滑计算最大概率。

    1 数据准备

    本实验使用人民日报1998年1月中文语料库,经过去除标点符号、词性标注等预处理步骤后共余下19347条。随机取80%作为训练集,余下作为验证集。

    训练数据格式

    2 构建字典

    本实验需要构造两个字典,一个用来记录每个字典词出现的词频,另一个用来记录每个词后面出现过那些词(bigram组合)。其中前者使用TrieTree数据结构实现,后者使用Python字典实现。

    TrieTree名为字典树、前缀树,用来保存字符串可以提高检索速度。其原理在于,前缀树每一个节点的子节点都拥有相同的前缀。字典树的特点在于每个节点都只含有一个字符,从根节点到某一个节点,路上经过的每个单个字符连起来为该节点对应的字符串。


    字典树结构示意图

    构建TrieTree字典树的过程如下:

        def dict_add(self,word):
            '''
            add 'word' to self.tree
            :param word: the word to be added
            :return: nothing; change the self.tree in-place
            '''
            tree = self.tree
            for char in word:
                if char in tree:
                    tree = tree[char]
                else:
                    tree[char] = {}
                    tree = tree[char]
    
            if "freq" in tree:
                tree["freq"] +=1
            else:
                tree["freq"] =1
    

    得到的字典树结构实例:

    {'迈': {'向': {'freq': 1}}, '充': {'满': {'freq': 1}}, '希': {'望': {'freq': 1}}, '的': {'freq': 1}, '新': {'freq': 1, '年': {'freq': 1}}}
    

    判断某词语是否在字典中时,需要递归遍历字典树:

        def dict_search(self,word):
            '''
            search word frequency in the self.tree
            :param word:
            :return: frequency
            '''
            tree = self.tree
    
            for char in word:
                if char in tree:
                    tree = tree[char]
                else:
                    return False
    
            if "freq" in tree and tree["freq"] >=1:
                return tree["freq"]
            else:
                return 0
    

    对于记录Bigram组合的词典,其结构如下所示:

    {“BEG”:{“你”:3, “今天”:2}, “你”:{“好”:6}}
    

    3 FMM和BMM

    正向最大匹配算法(FMM)是一种基于词典的分词方法。对于每个句子从左到右扫描寻找词的最大匹配,在这里限定匹配词语最大长度为4。而BMM算法则是从句子后往前遍历,仅仅是方向相反。

    FMM匹配过程如下:

     def fmm(self,sent):
            thedict = self.tree
            MAXLEN = self.MAXLEN
            sent = sent.strip()
            ans = []
            while len(sent):
                for i in range(min(len(sent), MAXLEN), 0, -1):
                    tomatch = sent[:i]
                    if self.dict_search(tomatch):
                        ans.append(tomatch)
                        sent = sent[i:]
                        break
                    elif len(sent[:i]) == 1:
                        ans.append(tomatch)
                        sent = sent[i:]
            return ans
    

    4 Bigram模型

    通常情况下,FMM或BMM可以得到正确的分词结果。但对于少部分歧义语句,需要借助概率判断采用哪种分词方案。例如,"你有意见分歧上报"在BMM算法中会被切割成"你/有/意见/分歧/上报",而在FMM算法下则会切割成"你/有意/见/上报".

    自然语言可看作一个马氏链模型,可根据前面的词预测后面出现的词语.依据训练语料中单个词汇出现的频率以及词语两两组合出现的次数(Bigram),我们可以通过概率进行比较.
    对于:
    C = "有意见分歧"
    C1: 有/ 意见/ 分歧/
    C2: 有意/ 见/ 分歧/

    有贝叶斯公式:


    而一个词的概率可以用其出现次数除以预料中总次数得到.

    计算概率时,如果词语不在字典中,会使得概率为0的情况.为避免0值,这里采用拉普拉斯平滑算法,将词语出现频数设为1.

    如果FMM和BMM算法的切分结果相同,说明没有歧义,直接采用其切分结果即可;如果FMM和BMM算法切分结果不同,说明该语句含有歧义。对比FMM和BMM结果得到歧义子串计算概率,概率更大的子串判断为正确切分.(这部分代码见文末Github链接)

    5 评价指标

    本分词实验采用准确率,召回率和F1作为评价指标,它们的计算方法如下:

    Precision = 正确切分出的词的数目/切分出的词的总数
    Recall = 正确切分出的词的数目/应切分出的词的总数
    F1 = 2*Precisiton*Recall/(Precision+Recall)

    本实验结果如下:

    实验结果

    可见进行语义消歧的分词方法具有更高的效果。

    附:
    项目源码

    相关文章

      网友评论

          本文标题:基于最大概率的汉语分词 (下)具体实现

          本文链接:https://www.haomeiwen.com/subject/wojldqtx.html