如何使用nltk计算困惑

时间:2019-03-01 09:48:25

标签: python-3.x nltk

我尝试对文本进行一些处理。这是我的代码的一部分:

fp = open(train_file)
raw = fp.read()
sents = fp.readlines()
words = nltk.tokenize.word_tokenize(raw)
bigrams = ngrams(words,2, left_pad_symbol='<s>', right_pad_symbol=</s>)
fdist = nltk.FreqDist(words)

在旧版本的nltk中,我在StackOverflow上找到了perplexity的这段代码

estimator = lambda fdist, bins: LidstoneProbDist(fdist, 0.2) 
lm = NgramModel(5, train, estimator=estimator)
print("len(corpus) = %s, len(vocabulary) = %s, len(train) = %s, len(test) = %s" % ( len(corpus), len(vocabulary), len(train), len(test) ))
print("perplexity(test) =", lm.perplexity(test))   

但是,此代码不再有效,因此,在nltk中没有找到任何其他包或函数。我应该实施吗?

1 个答案:

答案 0 :(得分:1)

困惑

让我们假设我们有一个模型,该模型将一个英语句子作为输入,并给出一个概率分数,该分数对应于它是一个有效英语句子的可能性。我们想确定这个模型有多好。一个好的模型应该给有效的英语句子打高分,给无效的英语句子打低分。困惑度是一种常用的度量,用于量化这种模型的“良好”程度。如果句子 s 包含 n 个单词,那么就会感到困惑

pic

建模概率分布p(建立模型)

pic可以使用概率链规则进行扩展

pic

因此,给定一些数据(称为火车数据),我们可以计算上述条件概率。但是,实际上是不可能的,因为这将需要大量的训练数据。然后,我们假设要计算

pic

假设:所有单词都是独立的(字母组合)

pic

假设:一阶马尔可夫假设(二元图)

下一个单词仅取决于前一个单词

pic

假设:n阶马尔可夫假设(ngram)

接下来的单词仅取决于前面的 n 个单词

MLE估计概率

最大似然估计(MLE)是一种估计个体概率的方法

Unigram

pic其中

  • count(w)是单词w在火车数据中出现的次数

  • count(vocab)是火车数据中唯一词(称为词汇)的数量。

比格勒姆

pic其中

  • count(w_ {i-1},w_i)是单词w_ {i-1},w_i在火车数据中以相同顺序(字母组合)一起出现的次数

  • count(w_ {i-1})是单词w_ {i-1}在列车数据中出现的次数。 w_ {i-1}称为上下文。

计算困惑

我们已经看到$ p(s)$以上是通过将许多小数字相乘来计算的,因此由于计算机上浮点数的精度有限,因此在数值上不稳定。让我们使用log的漂亮属性来简化它。我们知道pic

pic

示例:会标模型

火车数据[“一个苹果”,“一个橙色”] 词汇:[一个,苹果,橘子,UNK]

MLE估计

pic

对于测试句子“苹果”

l =  (np.log2(0.5) + np.log2(0.25))/2 = -1.5
np.power(2, -l) = 2.8284271247461903

对于测试语句“一只蚂蚁”

l =  (np.log2(0.5) + np.log2(0))/2 = inf
import nltk
from nltk.lm.preprocessing import padded_everygram_pipeline
from nltk.lm import MLE

train_sentences = ['an apple', 'an orange']
tokenized_text = [list(map(str.lower, nltk.tokenize.word_tokenize(sent))) 
                for sent in train_sentences]
n = 1
train_data, padded_vocab = padded_everygram_pipeline(n, tokenized_text)
model = MLE(n)
model.fit(train_data, padded_vocab)

test_sentences = ['an apple', 'an ant']
tokenized_text = [list(map(str.lower, nltk.tokenize.word_tokenize(sent))) 
                for sent in test_sentences]

test_data, _ = padded_everygram_pipeline(n, tokenized_text)
for test in test_data:
    print ("MLE Estimates:", [((ngram[-1], ngram[:-1]),model.score(ngram[-1], ngram[:-1])) for ngram in test])

test_data, _ = padded_everygram_pipeline(n, tokenized_text)

for i, test in enumerate(test_data):
  print("PP({0}):{1}".format(test_sentences[i], model.perplexity(test)))

示例:Bigram模型

火车数据:“一个苹果”,“一个橙色” 填充的火车数据:“(s)一个苹果(/ s)”,“(s)一个橙子(/ s)” 词汇:(s),(/ s)an,苹果,橙子,UNK

MLE估计

pic

对于测试句子“一个苹果”,填充:“(s)一个苹果(s)”

l =  (np.log2(p(an|<s> ) + np.log2(p(apple|an) + np.log2(p(</s>|apple))/3 = 
(np.log2(1) + np.log2(0.5) + np.log2(1))/3 = -0.3333
np.power(2, -l) = 1.

对于测试语句“一只蚂蚁”,填充:“(s)只蚂蚁(s)”

l =  (np.log2(p(an|<s> ) + np.log2(p(ant|an) + np.log2(p(</s>|ant))/3 = inf
import nltk
from nltk.lm.preprocessing import padded_everygram_pipeline
from nltk.lm import MLE
from nltk.lm import Vocabulary

train_sentences = ['an apple', 'an orange']
tokenized_text = [list(map(str.lower, nltk.tokenize.word_tokenize(sent))) for sent in train_sentences]

n = 2
train_data = [nltk.bigrams(t,  pad_right=True, pad_left=True, left_pad_symbol="<s>", right_pad_symbol="</s>") for t in tokenized_text]
words = [word for sent in tokenized_text for word in sent]
words.extend(["<s>", "</s>"])
padded_vocab = Vocabulary(words)
model = MLE(n)
model.fit(train_data, padded_vocab)

test_sentences = ['an apple', 'an ant']
tokenized_text = [list(map(str.lower, nltk.tokenize.word_tokenize(sent))) for sent in test_sentences]

test_data = [nltk.bigrams(t,  pad_right=True, pad_left=True, left_pad_symbol="<s>", right_pad_symbol="</s>") for t in tokenized_text]
for test in test_data:
    print ("MLE Estimates:", [((ngram[-1], ngram[:-1]),model.score(ngram[-1], ngram[:-1])) for ngram in test])

test_data = [nltk.bigrams(t,  pad_right=True, pad_left=True, left_pad_symbol="<s>", right_pad_symbol="</s>") for t in tokenized_text]
for i, test in enumerate(test_data):
  print("PP({0}):{1}".format(test_sentences[i], model.perplexity(test)))