使用Witten Bell Smoothing在nltk中使用NgramModel训练和评估bigram / trigram分布

时间:2013-03-29 05:00:34

标签: python nltk n-gram

我想在一组句子上训练NgramModel,使用Witten-Bell平滑来估计看不见的ngrams,然后用它来获得由该分布生成的测试集的对数似然。我想做的几乎与在这里找到的文档示例中做同样的事情:http://nltk.org/_modules/nltk/model/ngram.html,但是使用Witten-Bell平滑。这里有一些玩具代码试图做我想做的事情:

from nltk.probability import WittenBellProbDist
from nltk import NgramModel

est = lambda fdist, bins: WittenBellProbDist(fdist)
fake_train = [str(t) for t in range(3000)]
fake_test = [str(t) for t in range(2900, 3010)]

lm = NgramModel(2, fake_train, estimator = est)

print lm.entropy(fake_test)

不幸的是,当我尝试运行它时,我收到以下错误:

Traceback (most recent call last):
  File "ngram.py", line 8, in <module>
    lm = NgramModel(2, fake_train, estimator = est)
  File "/usr/lib/python2.7/dist-packages/nltk/model/ngram.py", line 63, in __init__
    self._model = ConditionalProbDist(cfd, estimator, len(cfd))
  File "/usr/lib/python2.7/dist-packages/nltk/probability.py", line 2016, in __init__
    **factory_kw_args)
  File "ngram.py", line 4, in <lambda>
    est = lambda fdist, bins: WittenBellProbDist(fdist)
  File "/usr/lib/python2.7/dist-packages/nltk/probability.py", line 1210, in __init__
    self._P0 = self._T / float(self._Z * (self._N + self._T))
ZeroDivisionError: float division by zero

导致此错误的原因是什么?据我所知,我根据文档正确使用了所有内容,当我使用Lidstone而不是Witten-Bell时,这种方法正常。

作为第二个问题,我的数据形式是一系列不相交的句子。我怎样才能使用像字符串列表这样的句子,或者做一些能产生相同分布的东西呢? (当然,我当然可以使用一个列表,其中所有句子都带有分隔后续句子的虚拟标记,但这不会产生相同的分布。)一个地方的文档说允许列出字符串列表,但后来我发现了一个错误报告,其中据说编辑了文档以反映不允许的文件(当我只是尝试一个字符串列表时我得到一个错误)。

3 个答案:

答案 0 :(得分:2)

almost 3 years显然是一个众所周知的问题。 ZeroDivisionError的原因是由于__init__中的以下行,

if bins == None: 
    bins = freqdist.B() 
self._freqdist = freqdist 
self._T = self._freqdist.B() 
self._Z = bins - self._freqdist.B() 

每当未指定bins参数时,默认为None,因此self._Z实际上只是freqdist.B() - freqdist.B()

self._P0 = self._T / float(self._Z * (self._N + self._T))

减少到,

self._P0 = freqdist.B() / 0.0

此外,如果您将bins指定为大于freqdist.B()的任何值,则在执行此代码行时,

print lm.entropy(fake_test)

您将收到NotImplementedError,因为在WittenBellProbDist班级内

def discount(self): 
    raise NotImplementedError()

discount方法显然也用于prob类的logprobNgramModel,因此您也无法调用它们。

在不更改NLTK的情况下修复这些问题的一种方法是从WittenBellProbDist继承并覆盖相关方法。

答案 1 :(得分:0)

暂时我会远离NLTK的NgramModel。当n> 1时,目前存在平滑错误导致模型极大地高估了可能性。这适用于所有估算器,包括WittenBellProbDist甚至LidstoneProbDist。我认为这个错误已经存在了几年,这表明这部分NLTK没有经过充分的测试。

请参阅: https://github.com/nltk/nltk/issues/367

答案 2 :(得分:0)

2018年12月更新

NLTK 3.4包含可导入为nltk.lm

的重新设计的ngram建模模块