web-dev-qa-db-ja.com

感情分析のための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
22
student001

データ構造を変更する必要があります。現在の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')]

ただし、問題は、各Tupleの最初の要素が機能の辞書であることです。したがって、リストを分類子が使用できるデータ構造に変更します。

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

各Tupleの最初の要素が辞書になっていることに注意してください。データが配置され、各Tupleの最初の要素が辞書になったので、次のように分類子をトレーニングできます。

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

このテスト文は陽性のようです。

39

NLTKのベイジアン分類器のデータ構造に関する@ 275365のチュートリアルは素晴らしいです。より高いレベルから見ると、

感情タグ付きの入力文があります:

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}

しかし、どの単語が文ではなくボキャブラリに存在するかを分類子に伝えたいので、各データポイントについて、ボキャブラリ内のすべての可能な単語をリストし、Wordが存在するかどうかを言います。

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

しかし、これは語彙を2回ループするため、これを行う方が効率的です。

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

そのため、各文について、どのWordが存在し、どのWordが存在しないかを各文の分類子に伝え、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トークンが特徴化されると消えるため、語彙の単語を処理できません。

次に、特徴のあるテスト文を分類器に送り、分類するように依頼します。

>>> 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)
20
alvas

TextBlobを使用しようとしているが、NLTK NaiveBayesClassifierをトレーニングしているようです。NLTKNaiveBayesClassifierは、他の回答で指摘されているように、機能の辞書を渡す必要があります。

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

5
Steve L