Nltk NaiveBayesClassifier для анализа настроений
Я тренирую NaiveBayesClassifier
в Python, используя предложения, и он дает мне ошибку ниже. Я не понимаю, что может быть ошибкой, и любая помощь будет хорошей.
Я пробовал много других форматов ввода, но ошибка остается. Код, приведенный ниже:
from text.classifiers import NaiveBayesClassifier
from text.blob import TextBlob
train = [('I love this sandwich.', 'pos'),
('This is an amazing place!', 'pos'),
('I feel very good about these beers.', 'pos'),
('This is my best work.', 'pos'),
("What an awesome view", 'pos'),
('I do not like this restaurant', 'neg'),
('I am tired of this stuff.', 'neg'),
("I can't deal with this", 'neg'),
('He is my sworn enemy!', 'neg'),
('My boss is horrible.', 'neg') ]
test = [('The beer was good.', 'pos'),
('I do not enjoy my job', 'neg'),
("I ain't feeling dandy today.", 'neg'),
("I feel amazing!", 'pos'),
('Gary is a friend of mine.', 'pos'),
("I can't believe I'm doing this.", 'neg') ]
classifier = nltk.NaiveBayesClassifier.train(train)
Я включил трассировку ниже.
Traceback (most recent call last):
File "C:\Users\5460\Desktop\train01.py", line 15, in <module>
all_words = set(word.lower() for passage in train for word in word_tokenize(passage[0]))
File "C:\Users\5460\Desktop\train01.py", line 15, in <genexpr>
all_words = set(word.lower() for passage in train for word in word_tokenize(passage[0]))
File "C:\Python27\lib\site-packages\nltk\tokenize\__init__.py", line 87, in word_tokenize
return _word_tokenize(text)
File "C:\Python27\lib\site-packages\nltk\tokenize\treebank.py", line 67, in tokenize
text = re.sub(r'^\"', r'``', text)
File "C:\Python27\lib\re.py", line 151, in sub
return _compile(pattern, flags).sub(repl, string, count)
TypeError: expected string or buffer
Ответы
Ответ 1
Вам нужно изменить структуру данных. Вот ваш список train
в текущем виде:
>>> train = [('I love this sandwich.', 'pos'),
('This is an amazing place!', 'pos'),
('I feel very good about these beers.', 'pos'),
('This is my best work.', 'pos'),
("What an awesome view", 'pos'),
('I do not like this restaurant', 'neg'),
('I am tired of this stuff.', 'neg'),
("I can't deal with this", 'neg'),
('He is my sworn enemy!', 'neg'),
('My boss is horrible.', 'neg')]
Проблема, однако, в том, что первым элементом каждого кортежа должен быть словарь возможностей. Поэтому я изменю ваш список на структуру данных, с которой может работать классификатор:
>>> from nltk.tokenize import word_tokenize # or use some other tokenizer
>>> all_words = set(word.lower() for passage in train for word in word_tokenize(passage[0]))
>>> t = [({word: (word in word_tokenize(x[0])) for word in all_words}, x[1]) for x in train]
Ваши данные теперь должны быть структурированы следующим образом:
>>> t
[({'this': True, 'love': True, 'deal': False, 'tired': False, 'feel': False, 'is': False, 'am': False, 'an': False, 'sandwich': True, 'ca': False, 'best': False, '!': False, 'what': False, '.': True, 'amazing': False, 'horrible': False, 'sworn': False, 'awesome': False, 'do': False, 'good': False, 'very': False, 'boss': False, 'beers': False, 'not': False, 'with': False, 'he': False, 'enemy': False, 'about': False, 'like': False, 'restaurant': False, 'these': False, 'of': False, 'work': False, "n't": False, 'i': False, 'stuff': False, 'place': False, 'my': False, 'view': False}, 'pos'), . . .]
Обратите внимание, что первый элемент каждого кортежа теперь является словарем. Теперь, когда ваши данные на месте и первый элемент каждого кортежа - это словарь, вы можете обучить классификатор следующим образом:
>>> import nltk
>>> classifier = nltk.NaiveBayesClassifier.train(t)
>>> classifier.show_most_informative_features()
Most Informative Features
this = True neg : pos = 2.3 : 1.0
this = False pos : neg = 1.8 : 1.0
an = False neg : pos = 1.6 : 1.0
. = True pos : neg = 1.4 : 1.0
. = False neg : pos = 1.4 : 1.0
awesome = False neg : pos = 1.2 : 1.0
of = False pos : neg = 1.2 : 1.0
feel = False neg : pos = 1.2 : 1.0
place = False neg : pos = 1.2 : 1.0
horrible = False pos : neg = 1.2 : 1.0
Если вы хотите использовать классификатор, вы можете сделать это следующим образом. Сначала вы начинаете с тестового предложения:
>>> test_sentence = "This is the best band I've ever heard!"
Затем вы токенизируете предложение и выясняете, какие слова разделяет предложение с all_words. Они составляют особенности предложения.
>>> test_sent_features = {word: (word in word_tokenize(test_sentence.lower())) for word in all_words}
Ваши функции теперь будут выглядеть так:
>>> test_sent_features
{'love': False, 'deal': False, 'tired': False, 'feel': False, 'is': True, 'am': False, 'an': False, 'sandwich': False, 'ca': False, 'best': True, '!': True, 'what': False, 'i': True, '.': False, 'amazing': False, 'horrible': False, 'sworn': False, 'awesome': False, 'do': False, 'good': False, 'very': False, 'boss': False, 'beers': False, 'not': False, 'with': False, 'he': False, 'enemy': False, 'about': False, 'like': False, 'restaurant': False, 'this': True, 'of': False, 'work': False, "n't": False, 'these': False, 'stuff': False, 'place': False, 'my': False, 'view': False}
Затем вы просто классифицируете эти функции:
>>> classifier.classify(test_sent_features)
'pos' # note 'best' == True in the sentence features above
Это тестовое предложение представляется положительным.
Ответ 2
@275365 учебник по структуре данных для байесовского классификатора NLTK замечателен. С более высокого уровня мы можем смотреть на него как
У нас есть предложения с предложениями с тегами сентимента:
training_data = [('I love this sandwich.', 'pos'),
('This is an amazing place!', 'pos'),
('I feel very good about these beers.', 'pos'),
('This is my best work.', 'pos'),
("What an awesome view", 'pos'),
('I do not like this restaurant', 'neg'),
('I am tired of this stuff.', 'neg'),
("I can't deal with this", 'neg'),
('He is my sworn enemy!', 'neg'),
('My boss is horrible.', 'neg')]
Давайте рассмотрим наши наборы функций как отдельные слова, поэтому мы извлекаем список всех возможных слов из данных обучения (пусть называют его словарем) как таковой:
from nltk.tokenize import word_tokenize
from itertools import chain
vocabulary = set(chain(*[word_tokenize(i[0].lower()) for i in training_data]))
По существу, vocabulary
здесь то же самое @275365 all_word
>>> all_words = set(word.lower() for passage in training_data for word in word_tokenize(passage[0]))
>>> vocabulary = set(chain(*[word_tokenize(i[0].lower()) for i in training_data]))
>>> print vocabulary == all_words
True
Из каждой точки данных (т.е. каждого предложения и тега pos/neg) мы хотим сказать, существует или нет функция (т.е. слово из словаря).
>>> sentence = word_tokenize('I love this sandwich.'.lower())
>>> print {i:True for i in vocabulary if i in sentence}
{'this': True, 'i': True, 'sandwich': True, 'love': True, '.': True}
Но мы также хотим сказать классификатору, что слово не существует в предложении, но в словаре, поэтому для каждой точки данных мы перечисляем все возможные слова в словаре и говорим, существует ли слово или нет:
>>> sentence = word_tokenize('I love this sandwich.'.lower())
>>> x = {i:True for i in vocabulary if i in sentence}
>>> y = {i:False for i in vocabulary if i not in sentence}
>>> x.update(y)
>>> print x
{'love': True, 'deal': False, 'tired': False, 'feel': False, 'is': False, 'am': False, 'an': False, 'good': False, 'best': False, '!': False, 'these': False, 'what': False, '.': True, 'amazing': False, 'horrible': False, 'sworn': False, 'ca': False, 'do': False, 'sandwich': True, 'very': False, 'boss': False, 'beers': False, 'not': False, 'with': False, 'he': False, 'enemy': False, 'about': False, 'like': False, 'restaurant': False, 'this': True, 'of': False, 'work': False, "n't": False, 'i': True, 'stuff': False, 'place': False, 'my': False, 'awesome': False, 'view': False}
Но так как это повторяется через словарь в два раза, это более эффективно для этого:
>>> sentence = word_tokenize('I love this sandwich.'.lower())
>>> x = {i:(i in sentence) for i in vocabulary}
{'love': True, 'deal': False, 'tired': False, 'feel': False, 'is': False, 'am': False, 'an': False, 'good': False, 'best': False, '!': False, 'these': False, 'what': False, '.': True, 'amazing': False, 'horrible': False, 'sworn': False, 'ca': False, 'do': False, 'sandwich': True, 'very': False, 'boss': False, 'beers': False, 'not': False, 'with': False, 'he': False, 'enemy': False, 'about': False, 'like': False, 'restaurant': False, 'this': True, 'of': False, 'work': False, "n't": False, 'i': True, 'stuff': False, 'place': False, 'my': False, 'awesome': False, 'view': False}
Итак, для каждого предложения мы хотим сказать классификатору для каждого предложения, какое слово существует, а какое слово - нет, а также дать ему знак pos/neg. Мы можем назвать это feature_set
, это кортеж, состоящий из x
(как показано выше) и его тега.
>>> feature_set = [({i:(i in word_tokenize(sentence.lower())) for i in vocabulary},tag) for sentence, tag in training_data]
[({'this': True, 'love': True, 'deal': False, 'tired': False, 'feel': False, 'is': False, 'am': False, 'an': False, 'sandwich': True, 'ca': False, 'best': False, '!': False, 'what': False, '.': True, 'amazing': False, 'horrible': False, 'sworn': False, 'awesome': False, 'do': False, 'good': False, 'very': False, 'boss': False, 'beers': False, 'not': False, 'with': False, 'he': False, 'enemy': False, 'about': False, 'like': False, 'restaurant': False, 'these': False, 'of': False, 'work': False, "n't": False, 'i': False, 'stuff': False, 'place': False, 'my': False, 'view': False}, 'pos'), ...]
Затем мы передаем эти функции и теги в feature_set в классификатор для его обучения:
from nltk import NaiveBayesClassifier as nbc
classifier = nbc.train(feature_set)
Теперь у вас есть обученный классификатор, и когда вы хотите пометить новое предложение, вам нужно "подкрепить" новое предложение, чтобы увидеть, какое из слов в новом предложении находится в словаре, в котором обучен классификатор:
>>> test_sentence = "This is the best band I've ever heard! foobar"
>>> featurized_test_sentence = {i:(i in word_tokenize(test_sentence.lower())) for i in vocabulary}
ПРИМЕЧАНИЕ.. Как видно из вышеприведенного шага, классификатор наивных байков не может обрабатывать словарные слова, поскольку токен foobar
исчезает после того, как вы его украли.
Затем вы подаете экспериментальное предложение featurized в классификатор и попросите его классифицировать:
>>> classifier.classify(featurized_test_sentence)
'pos'
Надеюсь, это даст более четкое представление о том, как подавать данные в классификатор наивных байков NLTK для сентиментального анализа. Здесь полный код без комментариев и пошаговое руководство:
from nltk import NaiveBayesClassifier as nbc
from nltk.tokenize import word_tokenize
from itertools import chain
training_data = [('I love this sandwich.', 'pos'),
('This is an amazing place!', 'pos'),
('I feel very good about these beers.', 'pos'),
('This is my best work.', 'pos'),
("What an awesome view", 'pos'),
('I do not like this restaurant', 'neg'),
('I am tired of this stuff.', 'neg'),
("I can't deal with this", 'neg'),
('He is my sworn enemy!', 'neg'),
('My boss is horrible.', 'neg')]
vocabulary = set(chain(*[word_tokenize(i[0].lower()) for i in training_data]))
feature_set = [({i:(i in word_tokenize(sentence.lower())) for i in vocabulary},tag) for sentence, tag in training_data]
classifier = nbc.train(feature_set)
test_sentence = "This is the best band I've ever heard!"
featurized_test_sentence = {i:(i in word_tokenize(test_sentence.lower())) for i in vocabulary}
print "test_sent:",test_sentence
print "tag:",classifier.classify(featurized_test_sentence)
Ответ 3
Похоже, что вы пытаетесь использовать TextBlob, но обучаете NLTK NaiveBayesClassifier, который, как указано в других ответах, должен быть передан словарь функций.
TextBlob имеет средство выделения по умолчанию, которое указывает, какие слова в обучающем наборе включены в документ (как показано в других ответах). Поэтому TextBlob позволяет передавать ваши данные как есть.
from textblob.classifiers import NaiveBayesClassifier
train = [('This is an amazing place!', 'pos'),
('I feel very good about these beers.', 'pos'),
('This is my best work.', 'pos'),
("What an awesome view", 'pos'),
('I do not like this restaurant', 'neg'),
('I am tired of this stuff.', 'neg'),
("I can't deal with this", 'neg'),
('He is my sworn enemy!', 'neg'),
('My boss is horrible.', 'neg') ]
test = [
('The beer was good.', 'pos'),
('I do not enjoy my job', 'neg'),
("I ain't feeling dandy today.", 'neg'),
("I feel amazing!", 'pos'),
('Gary is a friend of mine.', 'pos'),
("I can't believe I'm doing this.", 'neg') ]
classifier = NaiveBayesClassifier(train) # Pass in data as is
# When classifying text, features are extracted automatically
classifier.classify("This is an amazing library!") # => 'pos'
Конечно, простой экстрактор по умолчанию не подходит для всех проблем. Если вы хотите, чтобы функции были извлечены, вы просто пишете функцию, которая берет строку текста в качестве входных данных и выводит словарь функций и передает его в классификатор.
classifier = NaiveBayesClassifier(train, feature_extractor=my_extractor_func)
Я рекомендую вам ознакомиться с небольшим учебником по классификатору TextBlob: http://textblob.readthedocs.org/en/latest/classifiers.html