python - machine - Nltk NaiveBayesClassifier training para el análisis de sentimientos
python naive bayes text classification (3)
El tutorial de @ 275365 sobre la estructura de datos para el clasificador bayesiano de NLTK es excelente. Desde un nivel más alto, podemos verlo como,
Tenemos oraciones de entrada con etiquetas de sentimiento:
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'')]
Consideremos que nuestros conjuntos de características son palabras individuales, por lo que extraemos una lista de todas las palabras posibles de los datos de entrenamiento (llamémoslo vocabulario) como tal:
from nltk.tokenize import word_tokenize
from itertools import chain
vocabulary = set(chain(*[word_tokenize(i[0].lower()) for i in training_data]))
Esencialmente, el vocabulary
aquí es el mismo @_ de 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
Desde cada punto de datos (es decir, cada oración y la etiqueta pos / neg), queremos decir si existe una característica (es decir, una palabra del vocabulario) o no.
>>> 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}
Pero también queremos decirle al clasificador qué palabra no existe en la oración pero en el vocabulario, así que para cada punto de datos, enumeramos todas las palabras posibles en el vocabulario y decimos si existe una palabra o no:
>>> 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}
Pero como esto recorre el vocabulario dos veces, es más eficiente hacer esto:
>>> 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}
Entonces, para cada oración, queremos decirle al clasificador de cada oración qué palabra existe y qué palabra no, y también asignarle la etiqueta pos / neg. Podemos llamarlo un feature_set
, es una tupla compuesta de una x
(como se muestra arriba) y su etiqueta.
>>> 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''), ...]
Luego introducimos estas características y etiquetas en el feature_set en el clasificador para entrenarlo:
from nltk import NaiveBayesClassifier as nbc
classifier = nbc.train(feature_set)
Ahora tiene un clasificador capacitado y cuando quiere etiquetar una nueva oración, tiene que "caracterizar" la nueva oración para ver cuál de las palabras de la nueva oración están en el vocabulario en el que se entrenó al clasificador:
>>> 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}
NOTA: Como puede ver en el paso anterior, el clasificador ingenuo de bayes no puede manejar palabras de vocabulario ya que el token de foobar
desaparece después de caracterizarlo.
Luego introduce la oración de prueba caracterizada en el clasificador y le pide que clasifique:
>>> classifier.classify(featurized_test_sentence)
''pos''
Esperemos que esto proporcione una imagen más clara de cómo introducir datos en el clasificador de bayes ingenuo de NLTK para el análisis sentimental. Aquí está el código completo sin los comentarios y el tutorial:
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)
Estoy entrenando el NaiveBayesClassifier
en Python usando oraciones, y me da el error a continuación. No entiendo cuál podría ser el error, y cualquier ayuda sería buena.
He intentado muchos otros formatos de entrada, pero el error permanece. El código que figura a continuación:
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)
Incluyo el rastreo a continuación.
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
Necesitas cambiar tu estructura de datos. Aquí está su lista de train
como está actualmente:
>>> 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'')]
Sin embargo, el problema es que el primer elemento de cada tupla debe ser un diccionario de características. Así que cambiaré su lista a una estructura de datos con la que el clasificador pueda trabajar:
>>> 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]
Tus datos ahora deberían estar estructurados así:
>>> 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''), . . .]
Tenga en cuenta que el primer elemento de cada tupla ahora es un diccionario. Ahora que sus datos están en su lugar y que el primer elemento de cada tupla es un diccionario, puede entrenar al clasificador de la siguiente manera:
>>> 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
Si quieres usar el clasificador, puedes hacerlo así. Primero, comienzas con una oración de prueba:
>>> test_sentence = "This is the best band I''ve ever heard!"
Luego, tokeniza la oración y averigua qué palabras comparte la oración con all_words. Estas constituyen las características de la oración.
>>> test_sent_features = {word.lower(): (word in word_tokenize(test_sentence.lower())) for word in all_words}
Sus características ahora se verán así:
>>> 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}
Entonces simplemente clasifica esas características:
>>> classifier.classify(test_sent_features)
''pos'' # note ''best'' == True in the sentence features above
Esta oración de prueba parece ser positiva.
Parece que está intentando usar TextBlob pero está entrenando el NLTK NaiveBayesClassifier, que, como se señaló en otras respuestas, debe pasar un diccionario de características.
TextBlob tiene un extractor de características predeterminado que indica qué palabras del conjunto de capacitación se incluyen en el documento (como se muestra en las otras respuestas). Por lo tanto, TextBlob le permite pasar sus datos como están.
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''
Por supuesto, el simple extractor predeterminado no es apropiado para todos los problemas. Si desea conocer cómo se extraen las funciones, simplemente escriba una función que tome una cadena de texto como entrada y produzca el diccionario de características y se lo pase al clasificador.
classifier = NaiveBayesClassifier(train, feature_extractor=my_extractor_func)
Le animo a consultar el breve tutorial de clasificador de TextBlob aquí: http://textblob.readthedocs.org/en/latest/classifiers.html