Подтвердить что ты не робот

Nltk языковая модель (ngram) вычисляет проблему слова из контекста

Я использую 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

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

4b9b3361

Ответ 1

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

print lm.prob("word", ["This is a context which generates a word"])
# => 0.00493261081006

Ответ 2

Я знаю, что этот вопрос старый, но он появляется каждый раз, когда я google nltk класс NgramModel. Пробная реализация 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" должен not быть строкой или списком с одной многословной строкой. '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 - плохая идея. Все будет разваливаться. Я гарантирую это.)

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

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

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

Ответ 3

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

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

тогда

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

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

Ответ 4

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