Ответ 1
Быстрое исправление:
print lm.prob("word", ["This is a context which generates a word"])
# => 0.00493261081006
Я использую 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
Может ли кто-нибудь помочь мне? Спасибо!
Быстрое исправление:
print lm.prob("word", ["This is a context which generates a word"])
# => 0.00493261081006
Я знаю, что этот вопрос старый, но он появляется каждый раз, когда я 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())
... но здесь так много недоразумений, что я не могу сказать, что он на самом деле пытался сделать.
Что касается вашего второго вопроса: это происходит потому, что "b"
не встречается в категории Brown corpus news
, как вы можете проверить с помощью:
>>> 'b' in brown.words(categories='news')
False
тогда
>>> 'word' in brown.words(categories='news')
True
Я допускаю, что сообщение об ошибке очень загадочно, поэтому вы можете записать отчет об ошибках авторам NLTK.
Я бы держался подальше от NLTK NgramModel. В настоящее время наблюдается сглаживающая ошибка, которая заставляет модель сильно переоценивать вероятности при n > 1. Если вы в конечном итоге используете NgramModel, вам обязательно нужно применить исправление, упомянутое в git, здесь: https://github.com/nltk/nltk/issues/367