N-Gram
(N元模型)是自然语言处理中一个非常重要的概念。N-gram
模型也是一种语言模型,是一种生成式模型。
假定文本中的每个词 w i w_{i} wi和前面 N − 1 N-1 N−1 个词有关,而与更前面的词无关。这种假设被称为N-1阶马尔可夫假设,对应的语言模型称为N元模型。习惯上,1-gram
叫unigram
,2-gram
称为bigram
(也被称为一阶马尔可夫链),3-gram
是trigram
(也被称为二阶马尔可夫链)。还有four-gram、five-gram
等,不过大于n>5
的应用很少见。常用的是 Bi-gram (N = 2)
和 Tri-gram (N = 3)
,一般已经够用了。
用于构建语言模型的文本称为训练语料(training corpus
)。对于n元语法模型,使用的训练语料的规模一般要有几百万个词。语料库的选取也十分重要,如果训练语料和模型应用的领域相脱节,那么模型的效果通常要大打折扣。
N-gram
的第一个特点是某个词的出现依赖于其他若干个词,第二个特点是我们获得的信息越多,预测越准确。
假设句子S是由词序列 w 1 , w 2 , w 3 . . . w n w_1,w_2,w_3...w_n w1,w2,w3...wn组成,用公式表示N-Gram
语言模型如下(每一个单词 w i w_i wi都要依赖于从第一个单词 w 1 w_1 w1到它之前一个单词 w i − 1 w_{i−1} wi−1的影响):
P ( S ) = P ( w 1 , w 2 , … , w n ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 1 , w 2 ) … P ( w n ∣ w 1 , w 2 , … , w n − 1 ) P(S) = P(w_1, w_2, …,w_n ) = P(w_1)P(w_2 |w_1)P(w_3|w_1,w_2)…P(w_n|w_1,w_2,…,w_{n-1}) P(S)=P(w1,w2,…,wn)=P(w1)P(w2∣w1)P(w3∣w1,w2)…P(wn∣w1,w2,…,wn−1)
N-gram
的不足引入马尔科夫假设(Markov Assumption):一个词的出现仅与它之前的若干个词有关。通常取1或者2。
此时 Bi-gram
:
P ( S ) = P ( w 1 , w 2 , … , w n ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 2 ) … P ( w n ∣ w n − 1 ) P(S) = P(w_1, w_2, …,w_n ) = P(w_1)P(w_2 |w_1)P(w_3|w_2)…P(w_n|w_{n-1}) P(S)=P(w1,w2,…,wn)=P(w1)P(w2∣w1)P(w3∣w2)…P(wn∣wn−1)
Tri-gram
:
P ( S ) = P ( w 1 , w 2 , … , w n ) = P ( w 1 ) P ( w 2 ∣ w 1 ) P ( w 3 ∣ w 1 , w 2 ) … P ( w n ∣ w n − 2 , w n − 1 ) P(S) = P(w_1, w_2, …,w_n ) = P(w_1)P(w_2 |w_1)P(w_3|w_1,w_2)…P(w_n|w_{n-2},w_{n-1}) P(S)=P(w1,w2,…,wn)=P(w1)P(w2∣w1)P(w3∣w1,w2)…P(wn∣wn−2,wn−1)
根据大数定律,只要统计量足够,频率就无限接近概率。
P ( w n ∣ w n − 1 ) = P ( w n , w n − 1 ) P ( w n − 1 ) = C ( w n , w n − 1 ) C ( w n − 1 ) P(w_n|w_{n-1}) = \frac{P(w_n, w_{n-1})}{P(w_{n-1})} = \frac{C(w_n, w_{n-1})}{C(w_{n-1})} P(wn∣wn−1)=P(wn−1)P(wn,wn−1)=C(wn−1)C(wn,wn−1)
P ( w n ∣ w n − 2 , w n − 1 ) = C ( w n , w n − 2 , w n − 1 ) C ( w n − 2 , w n − 1 ) P(w_n|w_{n-2},w_{n-1}) = \frac{C(w_n,w_{n-2},w_{n-1})}{C(w_{n-2},w_{n-1})} P(wn∣wn−2,wn−1)=C(wn−2,wn−1)C(wn,wn−2,wn−1)
nltk
是一个用于英文自然语言处理NLP
的python
包,它提供了ngrams
的实现方式。
如果我们想要进行中文ngrams
模型,需要使用jieba
等库首先进行中文分词。
from nltk import ngrams,bigrams,trigrams
import re
import jieba
text = '我喜欢吃苹果,他不喜欢吃香蕉。'
tokens = jieba.lcut(text)
tokens = [x for x in tokens if x and x not in '-\s.,;!?,。?!;、']
tokens
['我', '喜欢', '吃', '苹果', '他', '不', '喜欢', '吃', '香蕉']
ngramsres = [u' '.join(w) for w in ngrams(tokens, 2)]
ngramsres
['我 喜欢', '喜欢 吃', '吃 苹果', '苹果 他', '他 不', '不 喜欢', '喜欢 吃', '吃 香蕉']
nltk还提供了bigrams和trigrams等常见的n-gram模型的实现方式。
ngramsres = [w for w in bigrams(tokens)]
ngramsres
[('我', '喜欢'),
('喜欢', '吃'),
('吃', '苹果'),
('苹果', '他'),
('他', '不'),
('不', '喜欢'),
('喜欢', '吃'),
('吃', '香蕉')]
实际上n-gram
模型实现方式很简单,在考虑语序的情况下,每一个n-gram
子块内部是有顺序的。只需要按次遍历就可以实现,在nltk
内部是通过迭代器的方式实现的,防止整个词汇字典过大时内存不足。