Пакет NLTK для оценки недоумения (unigram)

Я пытаюсь рассчитать недоумение для данных, которые у меня есть. Код, который я использую:

 import sys
 sys.path.append("/usr/local/anaconda/lib/python2.7/site-packages/nltk")

from nltk.corpus import brown
from nltk.model import NgramModel
from nltk.probability import LidstoneProbDist, WittenBellProbDist
estimator = lambda fdist, bins: LidstoneProbDist(fdist, 0.2)
lm = NgramModel(3, brown.words(categories='news'), True, False, estimator)
print lm

Но я получаю сообщение об ошибке,

File "/usr/local/anaconda/lib/python2.7/site-packages/nltk/model/ngram.py", line 107, in __init__
cfd[context][token] += 1
TypeError: 'int' object has no attribute '__getitem__'

Я уже выполнил скрытое распределение Дирихле для имеющихся у меня данных и сгенерировал униграммы и их соответствующие вероятности (они нормализованы, поскольку сумма общих вероятностей данных равна 1).

Мои униграммы и их вероятность выглядят так:

Negroponte 1.22948976891e-05
Andreas 7.11290670484e-07
Rheinberg 7.08255885794e-07
Joji 4.48481435106e-07
Helguson 1.89936727391e-07
CAPTION_spot 2.37395965468e-06
Mortimer 1.48540253778e-07
yellow 1.26582575863e-05
Sugar 1.49563800878e-06
four 0.000207196011781

Это всего лишь фрагмент файла юниграмм, который у меня есть. Тот же формат используется примерно для 1000 строк. Суммарные вероятности (второй столбец) дают 1.

Я начинающий программист. Этот ngram.py принадлежит пакету nltk, и я не знаю, как это исправить. Пример кода, который у меня есть, взят из документации nltk, и я не знаю, что теперь делать. Пожалуйста, помогите, что я могу сделать. Заранее спасибо!


person Ana_Sam    schedule 21.10.2015    source источник
comment
Сначала вы сказали, что хотите рассчитать сложность модели униграмм в текстовом корпусе. Но теперь вы отредактировали слово unigram.   -  person Omid    schedule 21.10.2015
comment
Пример кода из nltk сам по себе не работает :( Здесь в примере кода это триграмма и я бы поменял его на униграмму, если он работает. Как обойти эту ошибку?   -  person Ana_Sam    schedule 21.10.2015
comment
Обязательно ли использовать NLTK?   -  person Omid    schedule 21.10.2015
comment
Не говоря уже о NLTK. Я просто чувствовал, что его проще использовать, поскольку я новичок в программировании. Есть ли какой-либо другой способ или пакет, который я могу использовать для оценки недоумения для данных (которые не являются коричневым корпусом), которые у меня есть?   -  person Ana_Sam    schedule 21.10.2015
comment
Есть конечно. Я собираюсь предположить, что у вас есть простой текстовый файл, из которого вы хотите построить языковую модель униграммы, а затем вычислить недоумение для этой модели. Верно?   -  person Omid    schedule 22.10.2015
comment
Нет, я уже выполнил LDA для данных, которые у меня были, и у меня есть сгенерированные униграммы. Это сделано. Для этих униграмм мне нужно рассчитать недоумение. Формат моих данных: Negroponte 1.22948976891e-05 Andreas 7.11290670484e-07 Rheinberg 7.08255885794e-07 Joji 4.48481435106e-07; То есть у меня есть униграммы и их соответствующие нормализованные распределения.   -  person Ana_Sam    schedule 22.10.2015


Ответы (2)


Недоумение — это обратная вероятность тестового набора, нормированная по количеству слов. В случае униграмм:

введите описание изображения здесь

Теперь вы говорите, что уже построили модель униграммы, то есть для каждого слова у вас есть соответствующая вероятность. Затем вам нужно только применить формулу. Я предполагаю, что у вас есть большой словарь unigram[word], который обеспечит вероятность каждого слова в корпусе. Также необходимо иметь тестовый набор. Если ваша модель униграммы не имеет форму словаря, сообщите мне, какую структуру данных вы использовали, чтобы я мог соответствующим образом адаптировать ее к своему решению.

perplexity = 1
N = 0

for word in testset:
    if word in unigram:
        N += 1
        perplexity = perplexity * (1/unigram[word])
perplexity = pow(perplexity, 1/float(N))

ОБНОВИТЬ:

Поскольку вы просили полный рабочий пример, вот очень простой.

Предположим, это наш корпус:

corpus ="""
Monty Python (sometimes known as The Pythons) were a British surreal comedy group who created the sketch comedy show Monty Python's Flying Circus,
that first aired on the BBC on October 5, 1969. Forty-five episodes were made over four series. The Python phenomenon developed from the television series
into something larger in scope and impact, spawning touring stage shows, films, numerous albums, several books, and a stage musical.
The group's influence on comedy has been compared to The Beatles' influence on music."""

Вот как мы сначала строим модель униграммы:

import collections, nltk
# we first tokenize the text corpus
tokens = nltk.word_tokenize(corpus)

#here you construct the unigram language model 
def unigram(tokens):    
    model = collections.defaultdict(lambda: 0.01)
    for f in tokens:
        try:
            model[f] += 1
        except KeyError:
            model [f] = 1
            continue
    N = float(sum(model.values()))
    for word in model:
        model[word] = model[word]/N
    return model

Наша модель здесь сглажена. Для слов, выходящих за рамки его знаний, он присваивает низкую вероятность 0.01. Я уже говорил вам, как вычислить недоумение:

#computes perplexity of the unigram model on a testset  
def perplexity(testset, model):
    testset = testset.split()
    perplexity = 1
    N = 0
    for word in testset:
        N += 1
        perplexity = perplexity * (1/model[word])
    perplexity = pow(perplexity, 1/float(N)) 
    return perplexity

Теперь мы можем проверить это на двух разных наборах тестов:

testset1 = "Monty"
testset2 = "abracadabra gobbledygook rubbish"

model = unigram(tokens)
print perplexity(testset1, model)
print perplexity(testset2, model)

для которого вы получите следующий результат:

>>> 
49.09452736318415
99.99999999999997

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

person Omid    schedule 21.10.2015
comment
Не могли бы вы дать пример ввода для приведенного выше кода, а также его вывод? Соответственно мне будет легче сформулировать свои данные. Я отредактировал вопрос, добавив униграммы и их вероятности, которые у меня есть в моем входном файле, для которых следует рассчитать недоумение. - person Ana_Sam; 22.10.2015
comment
Привет! Но я также должен включить логарифмическую вероятность, например, недоумение (набор тестов) = exp{- (логарифмическая вероятность/количество токенов)}? qpleple.com/perplexity-to-evaluate-topic-models - person Ana_Sam; 22.10.2015
comment
Большое спасибо за время и код. Я это попробую. Мне нужно вычислить недоумение для униграмм, созданных моделью LDA. Я думаю, что для данных, которые у меня есть, я могу использовать этот код и проверить его. Благодаря тонну! - person Ana_Sam; 22.10.2015
comment
Нет ли ошибки в построении модели в строке model[word] = model[word]/float(len(model)) - разве не должно быть model[word] = model[word]/float(sum(model.values()))? - person mknaf; 06.01.2017
comment
в этой строке model[word]/float(sum(model.values())) он вычисляет сумму (model.values()) каждый раз после обновления нормализованных значений модели. Благодаря этому сумма нормированных значений составляет не 1, а 3,4. сумма должна быть рассчитана один раз и использована внутри цикла for. @heiner был действительно прав, я не вижу, где на него ответили. - person chmodsss; 25.04.2019

Спасибо за фрагмент кода! Не следует:

for word in model:
        model[word] = model[word]/float(sum(model.values()))

быть скорее:

v = float(sum(model.values()))
for word in model:
        model[word] = model[word]/v

О... вижу уже ответили...

person Heiner    schedule 17.01.2018
comment
Привет, Хайнер, добро пожаловать в SO, поскольку вы уже заметили, что на этот вопрос есть хорошо полученный ответ несколько лет назад, нет проблем с добавлением дополнительных ответов на уже отвеченные вопросы, но вы можете убедиться, что они добавляют достаточно значение, чтобы гарантировать их, в этом случае вы можете вместо этого сосредоточиться на ответах на эти новые вопросы! - person colsw; 17.01.2018