Модель языка nltk (ngram) вычисляет вероятность слова из контекста - PullRequest
15 голосов
/ 24 июня 2011

Я использую Python и NLTK для построения языковой модели следующим образом:

from nltk.corpus import brown
from nltk.probability import LidstoneProbDist, WittenBellProbDist
estimator = lambda fdist, bins: LidstoneProbDist(fdist, 0.2)
lm = NgramModel(3, brown.words(categories='news'), estimator)
# Thanks to miku, I fixed this problem
print lm.prob("word", ["This is a context which generates a word"])
>> 0.00493261081006
# But I got another program like this one...
print lm.prob("b", ["This is a context which generates a word"]) 

Но, похоже, это не работает.Результат выглядит следующим образом:

>>> print lm.prob("word", "This is a context which generates a word")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.6/dist-packages/nltk/model/ngram.py", line 79, in prob
    return self._alpha(context) * self._backoff.prob(word, context[1:])
  File "/usr/local/lib/python2.6/dist-packages/nltk/model/ngram.py", line 79, in prob
    return self._alpha(context) * self._backoff.prob(word, context[1:])
  File "/usr/local/lib/python2.6/dist-packages/nltk/model/ngram.py", line 82, in prob
    "context %s" % (word, ' '.join(context)))
TypeError: not all arguments converted during string formatting

Кто-нибудь может мне помочь?Спасибо!

Ответы [ 4 ]

12 голосов
/ 20 февраля 2013

Я знаю, что этот вопрос старый, но он появляется каждый раз, когда я использую класс ngramModel от Google nltk.Пробная реализация NgramModel немного неинтуитивна.Аскер в замешательстве.Насколько я могу судить, ответы не велики.Поскольку я не часто использую NgramModel, это означает, что я запутался.Не более.

Здесь находится исходный код: https://github.com/nltk/nltk/blob/master/nltk/model/ngram.py. Вот определение метода проб NgramModel:

def prob(self, word, context):
    """
    Evaluate the probability of this word in this context using Katz Backoff.

    :param word: the word to get the probability of
    :type word: str
    :param context: the context the word is in
    :type context: list(str)
    """

    context = tuple(context)
    if (context + (word,) in self._ngrams) or (self._n == 1):
        return self[context].prob(word)
    else:
        return self._alpha(context) * self._backoff.prob(word, context[1:])

( note : 'self[context] .prob (word) эквивалентно 'self._model [context] .prob (word)')

Хорошо.Теперь, по крайней мере, мы знаем, что искать.Каким должен быть контекст?Давайте посмотрим на выдержку из конструктора:

for sent in train:
    for ngram in ingrams(chain(self._lpad, sent, self._rpad), n):
        self._ngrams.add(ngram)
        context = tuple(ngram[:-1])
        token = ngram[-1]
        cfd[context].inc(token)

if not estimator_args and not estimator_kwargs:
    self._model = ConditionalProbDist(cfd, estimator, len(cfd))
else:
    self._model = ConditionalProbDist(cfd, estimator, *estimator_args, **estimator_kwargs)

Хорошо.Конструктор создает условное распределение вероятностей (self._model) из условного частотного распределения, «контекст» которого - кортежи униграмм.Это говорит нам, что «контекст» должен , а не быть строкой или списком с одной строкой из нескольких слов.'context' ДОЛЖЕН быть чем-то повторяемым, содержащим символы.На самом деле, требование немного более строгое.Эти кортежи или списки должны иметь размер n-1.Думайте об этом так.Вы сказали, что это модель триграмм.Вам лучше дать ему соответствующий контекст для триграмм.

Давайте посмотрим на это в действии на более простом примере:

>>> import nltk
>>> obs = 'the rain in spain falls mainly in the plains'.split()
>>> lm = nltk.NgramModel(2, obs, estimator=nltk.MLEProbDist)
>>> lm.prob('rain', 'the') #wrong
0.0
>>> lm.prob('rain', ['the']) #right
0.5
>>> lm.prob('spain', 'rain in') #wrong
0.0
>>> lm.prob('spain', ['rain in']) #wrong
'''long exception'''
>>> lm.prob('spain', ['rain', 'in']) #right
1.0

(В качестве примечания, на самом деле пытаемся сделать что-нибудь с MLE в качестве вашегооценка в NgramModel - плохая идея. Все развалится. Я гарантирую это.)

Что касается исходного вопроса, я полагаю, что мое лучшее предположение о том, чего хочет ОП, таково:

print lm.prob("word", "generates a".split())
print lm.prob("b", "generates a".split())

... но здесь так много недоразумений, что я не могу сказать, что он на самом деле пытался сделать.

7 голосов
/ 24 июня 2011

Что касается вашего второго вопроса: это происходит потому, что "b" не встречается в категории «Коричневый корпус» news, как вы можете проверить с помощью:

>>> 'b' in brown.words(categories='news')
False

, тогда как

>>> 'word' in brown.words(categories='news')
True

Я признаю, что сообщение об ошибке очень загадочное, поэтому вы можете подать отчет об ошибке авторам NLTK.

7 голосов
/ 24 июня 2011

Быстрое исправление:

print lm.prob("word", ["This is a context which generates a word"])
# => 0.00493261081006
4 голосов
/ 10 апреля 2013

Я бы пока держался подальше от NgramModel от NLTK. В настоящее время существует ошибка сглаживания, которая приводит к тому, что модель сильно переоценивает вероятности, когда n> 1. Если вы в конечном итоге используете NgramModel, вам определенно следует применить исправление, упомянутое в трекере проблем git здесь: https://github.com/nltk/nltk/issues/367

...