【问题标题】:Training and evaluating bigram/trigram distributions with NgramModel in nltk, using Witten Bell Smoothing使用 Witten Bell Smoothing 在 nltk 中使用 NgramModel 训练和评估二元/三元分布
【发布时间】:2013-03-29 05:00:34
【问题描述】:

我想在一组句子上训练一个 NgramModel,使用 Witten-Bell 平滑来估计看不见的 ngram,然后用它来获得由该分布生成的测试集的对数似然。我想做与此处找到的文档示例几乎相同的事情: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 时,这可以正常工作。

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

【问题讨论】:

  • 谢谢大家的回答。我最终选择了 SRILM,因为该代码实际上是完整且看似正确的......

标签: python nltk n-gram


【解决方案1】:

这显然是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 方法显然也用于NgramModel 类的problogprob,因此您也无法调用它们。

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

【讨论】:

    【解决方案2】:

    2018 年 12 月更新

    NLTK 3.4 包含重新设计的 ngram 建模模块,可导入为 nltk.lm

    【讨论】:

      【解决方案3】:

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

      见: https://github.com/nltk/nltk/issues/367

      【讨论】:

      • 这是有道理的——我注意到当对所有可能的标记求和时,给定标记的条件概率加起来不等于 1。我有点担心,然后才意识到,因为突然基线正在扼杀我更复杂的方法,呵呵。
      猜你喜欢
      • 2012-01-30
      • 2015-07-12
      • 2015-07-10
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多