Реализация классификатора Bag-of-Words Naive-Bayes в NLTK

В основном у меня есть тот же вопрос как этот парень.. пример в книге NLTK для наивного байесовского классификатора рассматривает только то, встречается ли слово в документе как характеристику. слов»).

Один из ответов предполагает, что это невозможно сделать с помощью встроенных классификаторов NLTK. Так ли это? Как я могу выполнить классификацию NB по частоте / набору слов с помощью NLTK?


person bgcode    schedule 11.04.2012    source источник


Ответы (3)


scikit-learn имеет реализация полиномиального наивного байесовского метода, который является правильным вариантом наивного байесовского метода в данной ситуации. Однако машина опорных векторов (SVM), вероятно, будет работать лучше.

Как указал Кен в комментариях, у NLTK есть хорошая оболочка для scikit. -учить классификаторы. Модифицированный из документов, вот несколько сложный, который взвешивает TF-IDF, выбирает 1000 лучших функций на основе статистики chi2, а затем передает это в полиномиальный наивный байесовский классификатор. (Бьюсь об заклад, это несколько неуклюже, так как я не очень хорошо знаком ни с NLTK, ни с scikit-learn.)

import numpy as np
from nltk.probability import FreqDist
from nltk.classify import SklearnClassifier
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline

pipeline = Pipeline([('tfidf', TfidfTransformer()),
                     ('chi2', SelectKBest(chi2, k=1000)),
                     ('nb', MultinomialNB())])
classif = SklearnClassifier(pipeline)

from nltk.corpus import movie_reviews
pos = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('pos')]
neg = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('neg')]
add_label = lambda lst, lab: [(x, lab) for x in lst]
classif.train(add_label(pos[:100], 'pos') + add_label(neg[:100], 'neg'))

l_pos = np.array(classif.classify_many(pos[100:]))
l_neg = np.array(classif.classify_many(neg[100:]))
print "Confusion matrix:\n%d\t%d\n%d\t%d" % (
          (l_pos == 'pos').sum(), (l_pos == 'neg').sum(),
          (l_neg == 'pos').sum(), (l_neg == 'neg').sum())

Это напечатано для меня:

Confusion matrix:
524     376
202     698

Не идеально, но прилично, учитывая, что это не супер простая задача, и она обучена только на 100/100.

person Danica    schedule 11.04.2012
comment
На самом деле, он, вероятно, хочет получить модели машины опорных векторов, полученные методом scikit-learn. У NLTK есть хорошая оболочка nltk.classify.scikitlearn.SklearnClassifier, благодаря которой эти классификаторы хорошо вписываются в его API. - person Ken Bloom; 11.04.2012
comment
@KenBloom Да, SVM, вероятно, были бы лучше, но он специально спрашивал о наивном Байесе. :) Эта оболочка хороша, и я только что понял, что в scikit-learn есть также полиномиальный наивный байесовский метод, поэтому я изменю свой ответ, чтобы использовать его. - person Danica; 11.04.2012
comment
это выглядит гениально просто. Жаль, что я не выучил Python, когда работал над докторской диссертацией. в этом. Я проделал большую работу по обертыванию классификаторов в Ruby, что было бы совершенно ненужным. - person Ken Bloom; 11.04.2012
comment
+1, но обратите внимание, что эта оболочка scikit-learn еще не появилась в выпуске NLTK, поэтому вам нужна новейшая версия с GitHub. - person Fred Foo; 12.04.2012
comment
@larsmans Правда? Я только что сделал pip install nltk на днях на этом компьютере, и это сработало... хотя nltk.__version__ - это 2.0.1rc4, так что я думаю, что это не официальный выпуск. - person Danica; 12.04.2012
comment
@Dougal: это релиз-кандидат. Я не знал, что они размещают их на PyPI. - person Fred Foo; 12.04.2012
comment
Я знаю, что вы спрашивали о наивных байесовских классификаторах, но я обнаружил, что PassiveAggressiveClassifier(n_iter=100) работает лучше всего. Также установите TfidfTransformer(sublinear_tf=True). - person Tim Ludwinski; 04.02.2014
comment
Исправлено batch_classify на classify_many по предложению @Rosem3ri. - person Danica; 27.12.2014

Функции в байесовском классификаторе NLTK являются «номинальными», а не числовыми. Это означает, что они могут принимать конечное число дискретных значений (меток), но их нельзя рассматривать как частоты.

Таким образом, с помощью байесовского классификатора вы не можете напрямую использовать частоту слов в качестве характеристики — вы можете сделать что-то вроде использования 50 более часто встречающихся слов из каждого текста в качестве набора характеристик, но это совсем другое дело.

Но, возможно, в NLTK есть другие классификаторы, зависящие от частоты. Я бы не знал, но вы смотрели? Я бы сказал, что это стоит проверить.

person alexis    schedule 11.04.2012

  • поместите строку, на которую вы смотрите, в список, разбитый на слова
  • для каждого элемента в списке спросите: является ли этот элемент функцией, которая есть у меня в списке функций.
  • Если это так, добавьте пробу журнала как обычно, если нет, игнорируйте ее.

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

Для большей точности считайте все биграммы, триграммы и т. д. как отдельные функции.

Это помогает вручную написать свои собственные классификаторы, чтобы вы точно понимали, что происходит и что вам нужно сделать для повышения точности. Если вы используете предварительно упакованное решение, и оно работает недостаточно хорошо, вы мало что можете с этим поделать.

person Matt    schedule 10.03.2014