Обучение и оценка распределений биграмм/триграмм с помощью NgramModel в nltk с использованием сглаживания Witten Bell

Я хотел бы обучить NgramModel на одном наборе предложений, используя сглаживание Виттена-Белла для оценки невидимых ngrams, а затем использовать его для получения логарифмической вероятности тестового набора, сгенерированного этим распределением. Я хочу сделать почти то же самое, что и в примере документации, найденном здесь: http://nltk.org/_modules/nltk/model/ngram.html, но вместо этого со сглаживанием Виттена-Белла. Вот какой-то игрушечный код, пытающийся сделать то, что я хочу сделать:

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.

В качестве второго вопроса у меня есть данные в виде набора непересекающихся предложений. Как я могу использовать предложения как список списков строк или сделать что-то эквивалентное, чтобы получить такое же распределение? (то есть, конечно, я мог бы просто использовать список, в котором есть все предложения с фиктивным токеном, разделяющим последующие предложения, но это не дало бы такого же распределения.) В документации в одном месте говорится, что разрешен список строк, но затем я нашел отчет об ошибке, в котором документация якобы была отредактирована, чтобы отразить, что это не разрешено (и когда я просто пробую список списков строк, я получаю сообщение об ошибке).


person DJLamar    schedule 29.03.2013    source источник
comment
Спасибо за ответы, всем. Вместо этого я остановился на SRILM, так как этот код на самом деле завершен и кажется правильным...   -  person DJLamar    schedule 14.04.2013


Ответы (3)


Судя по всему, эта проблема известна уже почти 3 года. Причина 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 и logprob класса NgramModel, поэтому вы также не сможете их вызвать.

Одним из способов решения этих проблем без изменения NLTK было бы наследование от WittenBellProbDist и переопределение соответствующих методов.

person Jared    schedule 02.04.2013

Обновление декабрь 2018 г.

NLTK 3.4 содержит переработанный модуль моделирования ngram, который можно импортировать как nltk.lm.

person Ilia Kurenkov    schedule 06.07.2016

Я бы пока держался подальше от NgramModel от NLTK. В настоящее время существует ошибка сглаживания, из-за которой модель сильно переоценивает вероятности, когда n>1. Это относится ко всем оценщикам, включая WittenBellProbDist и даже LidstoneProbDist. Я думаю, что эта ошибка существует уже несколько лет, что говорит о том, что эта часть NLTK недостаточно хорошо протестирована.

См.: https://github.com/nltk/nltk/issues/367.

person afourney    schedule 09.04.2013
comment
В этом есть смысл — я заметил, что условные вероятности для данного токена не дают в сумме 1 при суммировании всех возможных токенов. Некоторое время я немного волновался, прежде чем понял, что базовый уровень внезапно убивает мой гораздо более сложный метод, хех. - person DJLamar; 14.04.2013