nltk NaiveBayesClassifier training for sentiment analysis

Trenuję NaiveBayesClassifier w Pythonie używając zdań, i to daje mi błąd poniżej. Nie rozumiem, jaki może być błąd, a każda pomoc byłaby dobra.

Próbowałem wielu innych formatów wejściowych, ale błąd pozostaje. Kod podany poniżej:

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)

Włączam śledzenie poniżej.

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
Author: iCodez, 2013-12-29

3 answers

Musisz zmienić strukturę danych. Oto twoja train lista w obecnej formie:

>>> 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')]
Problem polega jednak na tym, że pierwszym elementem każdej krotki powinien być słownik cech. Więc zmienię Twoją listę w strukturę danych, z którą klasyfikator może pracować:
>>> 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]

Twoje dane powinny być teraz uporządkowane w następujący sposób:

>>> 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'), . . .]

Zauważ, że pierwszy element każdej krotki jest teraz słownikiem. Teraz, gdy Twoje dane są na miejscu i pierwszym elementem każda krotka jest słownikiem, można trenować klasyfikator tak:

>>> 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

Jeśli chcesz użyć klasyfikatora, możesz to zrobić w ten sposób. Po pierwsze, zaczynasz od zdania testowego:

>>> test_sentence = "This is the best band I've ever heard!"

Następnie tokenizujesz zdanie i ustalasz, które słowa zdanie dzieli z all_words. Stanowią one cechy zdania.

>>> test_sent_features = {word.lower(): (word in word_tokenize(test_sentence.lower())) for word in all_words}

Twoje funkcje będą teraz wyglądać tak:

>>> 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}

Wtedy po prostu klasyfikujesz te cechy:

>>> classifier.classify(test_sent_features)
'pos' # note 'best' == True in the sentence features above

To zdanie testowe wydaje się być pozytywny.

 33
Author: πόδας ὠκύς,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-18 12:01:16

@275365 's tutorial on the data structure for nltk' s bayesian classifier is great. Z bardziej wysokiego poziomu możemy spojrzeć na to jako,

Mamy zdania wejściowe z tagami sentencji:

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')]

Rozważmy nasze zestawy funkcji jako indywidualne słowa, Więc wyodrębnimy listę wszystkich możliwych słów z danych treningowych (nazwijmy to słownictwem) jako takie:

from nltk.tokenize import word_tokenize
from itertools import chain
vocabulary = set(chain(*[word_tokenize(i[0].lower()) for i in training_data]))

Zasadniczo, vocabulary tutaj jest to samo @275365 ' s 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

Z każdego punktu danych, (tj. każde zdanie i znacznik pos / neg), chcemy powiedzieć, czy dana cecha (tj. słowo ze słownika) istnieje, czy nie.

>>> 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}

Ale chcemy również powiedzieć klasyfikatorowi, które słowo nie istnieje w zdaniu, ale w słowniku, więc dla każdego punktu danych wymieniamy wszystkie możliwe słowa w Słowniku i mówimy, czy słowo istnieje, czy nie: {]}

>>> 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}

Ale ponieważ to przenika przez słownictwo dwa razy, jest to bardziej efektywne, aby to zrobić:

>>> 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}

Więc dla każdego zdania, my chcesz powiedzieć klasyfikatorowi dla każdego zdania, które słowo istnieje, a które nie, a także nadać mu znacznik pos / neg. Możemy to nazwać feature_set, jest to krotka złożona z x (Jak pokazano powyżej) i jej znacznika.

>>> 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'), ...]

Następnie przekazujemy te funkcje i tagi w feature_set do klasyfikatora, aby je trenować:

from nltk import NaiveBayesClassifier as nbc
classifier = nbc.train(feature_set)

Teraz masz wyszkolony klasyfikator i gdy chcesz oznaczyć nowe zdanie, musisz "featuryzować" nowe zdanie, aby zobaczyć, które ze słów w nowym zdania są w słowniku, na którym klasyfikator był szkolony:

>>> 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}

Uwaga: Jak widać z powyższego kroku, naiwny klasyfikator Bayesa nie może poradzić sobie ze słownikami, ponieważ token foobar znika po tym, jak go featuryzujesz.

Następnie karmisz featuryzowane zdanie testowe do klasyfikatora i prosisz go o klasyfikację:

>>> classifier.classify(featurized_test_sentence)
'pos'

Miejmy nadzieję, że to daje jaśniejszy obraz tego, jak podawać dane naiwnemu klasyfikatorowi Bayesa nltk dla sentymentalnych analiza. Oto Pełny kod bez komentarzy i walkthrough:

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)
 20
Author: alvas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-30 04:31:37

Wygląda na to, że próbujesz użyć TextBlob, ale trenujesz nltk NaiveBayesClassifier, który, jak wskazano w innych odpowiedziach, musi zostać przekazany słownik funkcji.

TextBlob ma domyślną funkcję extractor, która wskazuje, które słowa w zestawie treningowym są zawarte w dokumencie (jak pokazano w innych odpowiedziach). Dlatego TextBlob pozwala na przekazywanie danych tak, jak jest.

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'

Oczywiście, prosty domyślny ekstraktor nie jest odpowiedni dla wszystkich problemy. Jeśli chcesz, jak funkcje są wyodrębniane, po prostu napisz funkcję, która pobiera ciąg tekstu jako wejście i wyprowadza słownik funkcji i przekazuje go klasyfikatorowi.

classifier = NaiveBayesClassifier(train, feature_extractor=my_extractor_func)

Zachęcam do zapoznania się z krótkim tutorialem TextBlob classifier tutaj: http://textblob.readthedocs.org/en/latest/classifiers.html

 5
Author: Steve L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-29 20:52:28