浅谈分词算法基于词典的分词方法

xlturing xlturing     2022-10-18     772

关键词:

前言

浅谈分词算法(1)分词中的基本问题中我们探讨了分词中的基本问题,也提到了基于词典的分词方法。基于词典的分词方法是一种比较传统的方式,这类分词方法有很多,如:正向最大匹配(forward maximum matching method, FMM)、逆向最大匹配(backward maximum matching method,BMM)、双向扫描法、逐词遍历法、N-最短路径方法以及基于词的n-gram语法模型的分词方法等等。对于这类方法,词典的整理选择在其中占到了很重要的作用,本文主要介绍下基于n-gram的分词方法,这类方法在平时的分词工具中比较常见,而且性能也较好。

目录

浅谈分词算法(1)分词中的基本问题
浅谈分词算法(2)基于词典的分词方法
浅谈分词算法(3)基于字的分词方法(HMM)
浅谈分词算法(4)基于字的分词方法(CRF)
浅谈分词算法(5)基于字的分词方法(LSTM)

基本原理

贝叶斯公式

提到基于N-Gram的概率分词方法,首先我们就要说下伟大的贝叶斯理论,说到贝叶斯理论,先说贝叶斯公式:

贝叶斯公式也是概率论当中的基础,这里我们不再赘述,推荐一篇文章数学之美番外篇:平凡而又神奇的贝叶斯方法,讲的很不错。下面我们主要关注下在分词当中怎么利用贝叶斯原理。

分词中的贝叶斯

我们知道通常P(Y)是一个常数,所以在使用贝叶斯公式的时候我们更多用如下的公式:

当贝叶斯理论应用在离散数据集上的时候,可以使用频率作为概率来进行计算,在分词算法中,在给定训练语料库中,我们以词为单位进行统计,统计出每个词出现的频率,当出现一句待切分的句子时,我们将所有可能的分词结果统计出来,计算概率最大的作为切分结果。用形式化的语言描述下:
假设训练数据集为,其中词典集为D,为长度N的句子中的第i个词,那么一句话的联合概率可以表示为:

也就是说句子当中的每个词的概率都是一个依赖于其前面所有词的条件概率。说到这里我们就是惯用套路,显然这东东没法计算,那怎么办呢,那就是贝叶斯理论中常用的,做些条件独立假设呗,这也就是所谓n-gram中n的由来。

  • 1-gram(unigram), 一元模型,句子中的每个词都是相互独立的,那么上面的公式可以简化如下:
  • 2-gram(bigram),二元模型,句子中的每个词仅仅依赖于其前面的一个词:
  • 3-gram(trigram),三元模型,句子中的每个词依赖于其前面两个词:

一般来说,我们最多只看到前两个词,有研究表明,大于4个以上的模型并不会取得更好的效果(显然n越大,我们需要找寻n元组的词出现的频率就越低,会很直接的导致数据稀疏问题),通常情况下我们使用的是2-gram模型居多。

2-gram分词举例

假设待切分语句为:“研究生物学”,我们要怎样进行切分呢,直观的讲我们可以看出就这么一句简单的话包含了“研究”、“研究生”、“生物”、“生物学”多个词语,那么直观上我们有如下几种切分方式:

  • 研究/生物学
  • 研究生/物/学
  • 研究/生物/学
  • 研/究/生/物/学

我们将这些切法构建为一幅有向无环图,结点为词语,边为条件概率

(摘自[4])
那么根据最大似然原理,我们分词的过程转为了在图中求解最佳路径的问题,我们只需要选取任意一种搜索算法,例如在结巴分词中是利用动态规划找寻最大概率路径。

1-gram实例

上面说了那么多,还是上code比较有干货,我们以1-gram为例,来进行一个阐述,这里我们主要参考了结巴分词。在实现的过程中涉及到的核心问题:建立前缀字典树、根据句子建立DAG(有向无环图)、利用动态规划得到最大概率路径。

建立前缀字典树

代码如下:

        with open(dict_path, "rb") as f:
            count = 0
            for line in f:
                try:
                    line = line.strip().decode('utf-8')
                    word, freq = line.split()[:2]
                    freq = int(freq)
                    self.wfreq[word] = freq
                    for idx in range(len(word)):
                        wfrag = word[:idx + 1]
                        if wfrag not in self.wfreq:
                            self.wfreq[wfrag] = 0  # trie: record char in word path
                    self.total += freq
                    count += 1
                except Exception as e:
                    print("%s add error!" % line)
                    print(e)
                    continue

我们利用dict来建立这颗前缀字典树,遇到一个词时,会将词路径当中所有的子串都记录在字典树中。(其实这种方式存放是有大量冗余子串的,不过查询是会更加方便)

建立DAG

代码如下:

    def get_DAG(self, sentence):
        DAG = {}
        N = len(sentence)
        for k in range(N):
            tmplist = []
            i = k
            frag = sentence[k]
            while i < N and frag in self.wfreq:
                if self.wfreq[frag]:
                    tmplist.append(i)
                i += 1
                frag = sentence[k:i + 1]
            if not tmplist:
                tmplist.append(k)
            DAG[k] = tmplist
        return DAG

因为在载入词典的时候已经将word和word的所有前缀加入了词典,所以一旦frag not in wfreq,即可以断定frag和以frag为前缀的词不在词典里,可以跳出循环。

利用动态规划得到最大概率路径

值得注意的是,DAG的每个结点,都是带权的,对于在词典里面的词语,其权重为其词频,即wfreq[word]。我们要求得route = (w1, w2, w3 ,.., wn),使得Σweight(wi)最大。

动态规划求解法

满足dp的条件有两个

  • 重复子问题
  • 最优子结构

我们来分析最大概率路径问题。

重复子问题
对于结点Wi和其可能存在的多个后继Wj和Wk,有:

  1. 任意通过Wi到达Wj的路径的权重为该路径通过Wi的路径权重加上Wj的权重{Ri->j} = {Ri + weight(j)} ;
  2. 任意通过Wi到达Wk的路径的权重为该路径通过Wi的路径权重加上Wk的权重{Ri->k} = {Ri + weight(k)} ;

最优子结构
对于整个句子的最优路径Rmax和一个末端节点Wx,对于其可能存在的多个前驱Wi,Wj,Wk…,设到达Wi,Wj,Wk的最大路径分别为Rmaxi,Rmaxj,Rmaxk,有:
Rmax = max(Rmaxi,Rmaxj,Rmaxk…) + weight(Wx)
于是问题转化为:
求Rmaxi, Rmaxj, Rmaxk…
组成了最优子结构,子结构里面的最优解是全局的最优解的一部分。
很容易写出其状态转移方程:
Rmax = max{(Rmaxi,Rmaxj,Rmaxk…) + weight(Wx)}

代码

代码如下:

    def get_route(self, DAG, sentence, route):
        N = len(sentence)
        route[N] = (0, 0)
        logtotal = log(self.total)
        for idx in range(N - 1, -1, -1):
            route[idx] = max((log(self.wfreq.get(sentence[idx:x + 1]) or 1) -
                              logtotal + route[x + 1][0], x) for x in DAG[idx])

这里值得注意的是在求频率时,使用了log函数,将除法变成了减法,防止溢出。

完整代码

对于句子“我是中国人”,我们可以看到如下图所示的效果:

我将完整的代码放在了git上,这里的词典用的就是结巴分词中的词典,其中好多代码都是从结巴分词复用过来的,大家需要可以瞅瞅:
https://github.com/xlturing/machine-learning-journey/tree/master/seg_ngram

参考文献

  1. 数学之美番外篇:平凡而又神奇的贝叶斯方法
  2. 自然语言处理中的N-Gram模型详解
  3. 概率语言模型的分词方法
  4. 《统计自然语言处理》宗成庆
  5. 结巴分词python
  6. jieba分词学习笔记(三)

浅谈文本分析分词及关系图

参考技术A在文本分析中,我们需要对其文本进行分词,并对这些分词统计分析,基于python,jieba是很受欢迎的一种分词库,而后对分词之间的关系,当然PythonMatplotlib基于networkx画关系网络图也是可以的,但是这里我们将借助Gephi... 查看详情

python中文分词的原理你知道吗?

中文分词,即ChineseWordSegmentation,即将一个汉字序列进行切分,得到一个个单独的词。表面上看,分词其实就是那么回事,但分词效参考技术A中文分词,即ChineseWordSegmentation,即将一个汉字序列进行切分,得到一个个单独的词。... 查看详情

基于词典的中文分词算法2:最少分词法

最少切分分词算法该分词算法依据最少切分原则,从几种分词算法切分结果中取切分词数最少一种的。比如,从正向最大匹配和逆向最大匹配两者中选择词数较少的方案,当词数相同时,采取某种策略,选择其中一个。https://blog... 查看详情

基于词典的中文分词算法3:最大概率法

最大概率法分词是在最大匹配分词算法上的改进。在某些语句切分时,按最大长度切分词语可能并不是最优切分。而不按最优长度切分词语,则同一语句会出现多种切分结果。计算每种切分结果的概率,选取概率最高的切分作为... 查看详情

基于词典的中文分词算法1:最大匹配法

https://www.cnblogs.com/dahuang123/p/11990651.htmlhttps://www.cnblogs.com/by-dream/p/6429615.htmlhttps://zhuanlan.zhihu.com/p/103392455 查看详情

有哪些比较好的中文分词方案?

中文分词是中文文本处理的一个基础步骤,也是中文人机自然语言交互的基础模块。不同于英文的是,中文句子中没有词的界限,因此在进行中文自然语言处理时,通常需要先进行分词,分词效果将直接影响词性、句法树等模块... 查看详情

中文分词常用方法

...基于规则的方法1、基于词典的方法(字符串匹配,机械分词方法)定义:按照一定策略将待分析的汉字串与一个大机器词典中的词条进行匹配,若在词典中找到某个字符串,则匹配成功。按照扫描方向的不同:正向匹配和逆向匹... 查看详情

jiba中文分词原理

中文分词就是将一个汉字序列分成一个一个单独的词。现有的分词算法有三大类:基于字符串匹配的分词:机械分词方法,它是按照一定的策略将待分析的字符串与一个充分大的机器词典中的词条进行匹配,若在词典中找到某个... 查看详情

浅谈中文分词与自然语言处理

参考技术A最近出于兴趣和需要,重新回顾中文分词技术,期间有些心得,以及一些关于自然语言处理的浅薄之见,这里简单分享一下。首先,中文分词_百度百科里面简单介绍了其中主要的分词算法以及相应的优缺点,包括字符... 查看详情

浅谈分词算法分词中的基本问题

[TOC]前言分词或说切词是自然语言处理中一个经典且基础的问题,在平时的工作中也反复的接触到分词问题,用到了不同的模型,不同的方法应用在各个领域中,所以想对分词问题做一个系统的梳理。大多数分词问题主要是针对... 查看详情

中文分词方法以及一些算法

...引擎的搜索准确度影响很大 1.基于字符串匹配(机械分词)  一般作为一个初分手段(1)正向最大匹配法(需要充分大的词典)例子:将句子’ 今天来了许多新同事 ’ 分词。 设最大词长为5 今天来... 查看详情

中文分词(概况)

中文词法分析中文属于分析型语言,词基本上没有专门表示语法意义的附加成分,形态变化很少,语法关系靠词序和虚词来表示中文词法分析难点重叠词,离合词,词缀中文词语的切分歧义中文未定义词词性标注解决方法:基于... 查看详情

基于统计的自动分词算法

简介:利用字与字间、词与词间的同现频率作为分词的依据,不一定需要建立好的词典。需要大规模的训练文本用来训练模型参数。优缺点:不受应用领域的限制;但训练文本的选择将影响分词结果。 概率最大统计分词算法... 查看详情

go语言中文分词技术使用技巧

分词技术就是搜索引擎针对用户提交查询的关键词串进行的查询处理后根据用户的关键词串用各种匹配方法进行分词的一种技术。中文分词(Chinese Word Segmentation)指的是将一个汉字序列(句子)切分成一个一个的单独的... 查看详情

文本分类方法都有哪些

...技术。针对中文文本分类时,很关键的一个技术就是中文分词。特征粒度为词粒度远远好于字粒度,其大部分分类算法不考虑词序信息,基于字粒度的损失了过多的n-gram信息。下面简单总结一下中文分词技术:基于字符串匹配的... 查看详情

词汇与分词技术

中文分词主要分为三个流派:机械式分词法(基于词典):简单来说就是建立一个巨大的词典,然后将词典中的词语和文章中的词语相匹配,找到这个词语就算匹配成功,但是词典的完备性得不到保证。也就是文章中的有的词语... 查看详情

中文分词(代码片段)

算法  正向最大匹配法;  基于最大概率分词方法数据结构  在本次实验中最重要的事情就是建立合理的字典的索引结构,使得查询的速度、存储的空间需求达到较好的性能。  通过观察字典内容可知,存在多个词语有... 查看详情

百度中文分词如何分词

参考技术A而百度中文分词就是把词按照一定的规格,将一个长尾词分割成几个部分,从而概括一段话的主要内容。在百度中文分词中,百度强调的是:一、字符串匹配的分词方法。我们需要有一定的字符串做基础,就是一段词... 查看详情