关键词: ngram,n-gram,联合概率,极大似然估计,马尔科夫模型,字标注法
中文分词相关算分:
1). 分词算法2:
正向,逆向,或者双向的最大匹配,逐词遍历匹配等,但是这几种分词方法效果比较差也更陈旧,这里不做介绍了,感兴趣的同学自己去看看。我们着重介绍下面的两种方法。
2).分词算法2: N-gram模型
N-gram 是一种基于HMM假设的模型,在自然语言中非常非常的实用,很多模型算法都是基于这一理论的。它不仅适用于分词,也可以做文本分类,语音识别,实体识别等等,是自然语言乃至机器学习领域的元老重量级算法。也是概率论的一个及其流行的应用。
Gram的概率计算:
假设一句话的字集合是 S={W1,W2,W3...,Wn} 那么这句话的概率表达公式如下
如果我们一句话只有2个字的时候,S={w1,w2} 则有 P(w1,w2)=p(w1)p(w2|w1), 这就是一个联合概率公式。这时候的计算复杂度还是比较正常的。
1. 复杂度过高: 但是如果字数过多,会发现仅仅是最后一项的参数就有O(n)个,参数空间过大,复杂度会很高。
2. 数据稀疏:这里如果字词数量很大,会发现很有可能上面公式的某一项概率是0,因为在自然文本中未必出现过这种组合。这时候的单项条件概率就是0.会很容易导致整体为0. 对于模型泛化是毫无意义的。
3. 容易导致词粒度过细:缺少分词的意义。对于N=all的全联合概率来说,可以断定,中间多个词同时出现的概率一定要小于更细粒度同时出现的概率。尤其是一句话总词数很大的情况下,因此这样n-gram分词器会倾向于把所有词打碎。这样出来的分词是没有意义的。
N-gram的出现:
考虑到上述原因,我们基于马尔科夫假设,制定N-gram模型。马尔科夫简单的意义就是说,当前状态只会与上一个状态有关与其他无关,过去不能预测未来。 放到文本中,我们可以这么理解: HMM假设:每个字出现仅仅与它前面出现的L个字有关:
Bi-Gram模型:
当N=2时就是2-gram模型: 就是说,当前字是否出现仅仅依赖于前一个字,公式如下:
Tri-Gram模型:
同理有3-gram模型, 当前字是否出现只与前两个是否出现有关。
在具体实现中,我们最常用的是使用2-gram,3-gram比较多,或者1-gram 也就是uni-gram。N>4的使用情况比较小。(显然n越大,我们需要找寻n元组的词出现的频率就越低,数据稀疏问题将会变得非常明显)而且有统计显示,当n大于等于4的时候计算复杂度加剧但是效果没有任何明显变好。
如何获得某一项条件概率
我们再看一下,我们怎么获取某一个项条件概率呢?例如拿2-gram来看, P(W2|W1)是怎么得来的呢,其实就是基于最大似然来做.
简单说就是数出现的次数比: W2与W1共同出现的次数 除以 W1出现的次数。(下图表示2-gram,与3-gram的计算方法)
那么第一项p(W1)怎么计算?
W1,是一个句子的开头, P(W1) 就是计算 以W1作为开头的句子个数除以句子总数。就是P(w1)。 这样,每一项我都求出来就得到了最终的P(S)了。
看一个图例:
理论部分已经讲完,具体现实中如何用n-gram来分词呢?
我们看了上面n-gram算法的理论之后,可能云里雾里的,不明白到底怎么去构建条件概率。下面我们来具体讲解一个例子,来大致弄明白如何通过N-gram去做分词吧。
例子:
假设我们有一句话 S="我们的生活富裕了",
采用2-gram的P(S)有多种值。
这些值来自于一下bigram的组合
p(我/),p(们|我),P(的|们), P(生|的),P(活|生),P(富|活),P(裕|富),P(了|裕),P(|了)
第一种: P(S1) = p(我/)*P(的|们)*P(活|生)*P(裕|富)*P(|了)
第二种: P(S2) = p(们|我)*P(生|的)*P(富|活)*P(了|裕)
......
第N种: P(Sn) = ...........
里面任意一项的的条件概率,我们知道通过词频比来获取,
例如 p(们|我) = (Tf(我们)) / Tf(我) 。这里的C表是Term Frequency
假设训练语料中"我们"一词出现了1000次,"我" 这个词出现了10000次那么 p(们|我) = 1/10
然后通过计算我们可以很容易得到,P(S1),P(S2)... 取P值最大的那一种方案作为我们最后的分词结果即可。
但是!注意了: 真正的N-gram分词看下面
N-gram分词工业界做法
上面的分词方法可以做到不依赖词表的最简单2字词,但是这并非我们工业界正常使用的分词方法。因为这种效果极差,不过上面例子基础,主要目的是让大家体会到基础分词的简单思想。
这里我直接引用一个例子来讲解: 我们针对“研究生物学” 来进行分词。
第一步:前缀字典树匹配:
使用字典树(提前加载好词典),进行匹配识别词。关于树结构的构建,我建议使用双数组Trie树的形式(Double-Array Trie)。 DAT本质上是一个确定性有限自动机(DFA),极大梯度提高空间利用率(减少内存)并且保证了Trie树的检索速度。
通过字典树搜索匹配到:研究,研究生,生物,生物学
第二步: 构建有向无环图(DAG):
第三步: 求最短路径(Dijkstra等算法):
基于动态规划算法对词图求得最短路径。 得到最好的分词路径即是最终结果。这里图上的路径用的就是Bi-gram作为路径权重,所以我们求的是带权值的最优路径--最大概率路径。
当然也可以求N-最短路径获取更多分词可能后,再通过优化得到最终分词结果。
3). 分词算法3: 基于训练标注的模型法:
中文分词的字标注法:
4字标注法:{S,B,M,E}
通过4标签来进行标注(single,单字成词;begin,多字词的开头;middle,词语的中间部分;end,多字词的结尾。均只取第一个字母。),这样,“为人民服务”就可以标注为“为/s 人民/be 服务/be”了。
6字标注法: 除了4标注法,还有6标注法。{S,B,M1,M2,M,E} 这里M1,M2,M 表示中间字,超出两个中间字的表示都是M.
例如: 自然语言处理 => "自/B 然/M1 语/M2 言/M 处/M 理/E"
除此之外还有2-tag {BI}
理论上来说,标注的类型越多会越细致也更准确,理论上来说效果也会更好。但是缺陷也很明显,依赖对模型要求偏高,更重要的是标注数据非常难获取,标注难度很高,因此采用4标注的占据多数。
字标注法本质上说不是一种分词算法,而是一种分字标注基础。有非常多的模型是基于字标注法来进行分词的。我们之后要实现的大多数算法都基于字标注的形式进行学习训练。例如,HMM(隐式马尔科夫),ME(最大熵),CRF(条件随机场),还有以后会学习的RNN,LSTM等深度学习模型。在前几年,公开测评最好的中文分词器是基于4标注的CRF模型。
当然了这两年,在非公开测评上效果比较好也比较通用的模型是基于4字标注的Bi-lstm+CRF的形式。双向lstm从句首句尾出发,可以将更多的上下文文本信息带入tag的预测中去,lstm虽然可以学习字与字之间的关系,但是并不能学习到预测出来的标签之间的关系,例如如果上一个字的标签时B,那下一个标签肯定不是B了,因此学者在Bi-lstm又接入一层crf模型,来学习潜在的标签关系优化标签序列。
小智总结:
以上为工业界常用的分词算法,但是具体在使用过程中,仍然有非常多的细节问题。标注数据的数据集大小问题,数据精度问题,常规算法的数据平滑如何怎么做,等等。而且严格来说,现在从模型优化的角度上去提升分词的准确率难度偏高,性价比比较低。因为对于基本分词,开源的模型已经表现很好了,而对于细分领域下的特殊分词,往往使用现有模型训练领域语料效果比较不错,不需要新式模型做太多优化。对于具体的业务场景中,制约我们使用分词的往往不是来自于那96%的正确分词,而是来自于4%的个例,因为越是分不准的词往往对我们的领域具备更大的语义影响力。因此真正在场景中,我们需要很多针对性的操作,例如通过苦力添加个性化词库,针对特殊的case做规则优化。这种粗暴的方法往往比尝试更换新模型带来的收益要大出很多。