web-dev-qa-db-fra.com

Formation nltk NaiveBayesClassifier pour l'analyse des sentiments

J'entraîne le NaiveBayesClassifier en Python en utilisant des phrases, et cela me donne l'erreur ci-dessous. Je ne comprends pas ce que l'erreur pourrait être, et toute aide serait bonne.

J'ai essayé de nombreux autres formats d'entrée, mais l'erreur persiste. Le code donné ci-dessous:

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)

J'inclus le retraçage ci-dessous.

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

Vous devez modifier votre structure de données. Voici votre liste train telle qu'elle est actuellement:

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

Le problème est cependant que le premier élément de chaque Tuple doit être un dictionnaire de fonctionnalités. Je vais donc changer votre liste en une structure de données avec laquelle le classificateur peut travailler:

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

Vos données doivent maintenant être structurées comme ceci:

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

Notez que le premier élément de chaque Tuple est maintenant un dictionnaire. Maintenant que vos données sont en place et que le premier élément de chaque Tuple est un dictionnaire, vous pouvez entraîner le classificateur comme suit:

>>> 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 vous souhaitez utiliser le classificateur, vous pouvez le faire comme ceci. Tout d'abord, vous commencez par une phrase test:

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

Ensuite, vous symbolisez la phrase et déterminez quels mots la phrase partage avec all_words. Ceux-ci constituent les caractéristiques de la phrase.

>>> test_sent_features = {Word: (Word in Word_tokenize(test_sentence.lower())) for Word in all_words}

Vos fonctionnalités ressembleront maintenant à ceci:

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

Ensuite, vous classez simplement ces fonctionnalités:

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

Cette phrase test semble positive.

39

Le tutoriel de @ 275365 sur la structure des données du classificateur bayésien de NLTK est excellent. D'un niveau plus élevé, nous pouvons le considérer comme,

Nous avons des phrases d'entrée avec des tags de sentiment:

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

Considérons nos ensembles de fonctionnalités comme des mots individuels, nous extrayons donc une liste de tous les mots possibles des données d'apprentissage (appelons-le vocabulaire) en tant que telle:

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

Essentiellement, vocabulary voici la même chose que @ 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

À partir de chaque point de données (c'est-à-dire chaque phrase et la balise pos/neg), nous voulons dire si une caractéristique (c'est-à-dire un mot du vocabulaire) existe ou non.

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

Mais nous voulons aussi dire au classificateur quel mot n'existe pas dans la phrase mais dans le vocabulaire, donc pour chaque point de données, nous listons tous les mots possibles dans le vocabulaire et disons si un mot existe ou non:

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

Mais comme cela parcourt le vocabulaire deux fois, il est plus efficace de le faire:

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

Donc, pour chaque phrase, nous voulons dire au classificateur pour chaque phrase quel mot existe et quel mot n'existe pas et lui donner également la balise pos/neg. Nous pouvons appeler cela un feature_set, c'est un Tuple composé d'un x (comme illustré ci-dessus) et de sa balise.

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

Ensuite, nous introduisons ces fonctionnalités et ces balises dans le Feature_set dans le classificateur pour le former:

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

Maintenant, vous avez un classificateur formé et lorsque vous souhaitez baliser une nouvelle phrase, vous devez "personnaliser" la nouvelle phrase pour voir quels mots de la nouvelle phrase font partie du vocabulaire sur lequel le classificateur a été formé:

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

REMARQUE: Comme vous pouvez le voir à partir de l'étape ci-dessus, le classificateur bayésien naïf ne peut pas gérer les mots de vocabulaire puisque le jeton foobar disparaît après l'avoir développé.

Ensuite, vous introduisez la phrase de test dans le classificateur et lui demandez de classer:

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

Espérons que cela donne une image plus claire de la façon d'introduire des données dans le classificateur bayésien naïf de NLTK pour l'analyse sentimentale. Voici le code complet sans les commentaires et la procédure pas à pas:

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
alvas

Il semble que vous essayez d'utiliser TextBlob mais que vous formez le NLTK NaiveBayesClassifier, qui, comme indiqué dans d'autres réponses, doit recevoir un dictionnaire de fonctionnalités.

TextBlob possède un extracteur de fonctionnalités par défaut qui indique quels mots de l'ensemble de formation sont inclus dans le document (comme démontré dans les autres réponses). Par conséquent, TextBlob vous permet de transmettre vos données telles quelles.

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'

Bien sûr, l'extracteur par défaut simple n'est pas approprié pour tous les problèmes. Si vous souhaitez extraire des entités, il vous suffit d'écrire une fonction qui prend une chaîne de texte en entrée, de sortir le dictionnaire des entités et de la transmettre au classificateur.

classifier = NaiveBayesClassifier(train, feature_extractor=my_extractor_func)

Je vous encourage à consulter le court didacticiel du classificateur TextBlob ici: http://textblob.readthedocs.org/en/latest/classifiers.html

5
Steve L