NaturalLanguageToolkit(NLTK)を使用してPython3で感情分析を実行する方法
著者は、 Open Internet / Free Speech 基金を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
今日生成される大量のデータは非構造化であり、洞察を生成するための処理が必要です。 非構造化データの例としては、ニュース記事、ソーシャルメディアへの投稿、検索履歴などがあります。 自然言語を分析してそれを理解するプロセスは、自然言語処理(NLP)の分野に分類されます。 感情分析は一般的なNLPタスクであり、テキストまたはテキストの一部を事前定義された感情に分類する必要があります。 Natural Language Toolkit(NLTK)は、Pythonで一般的に使用されるNLPライブラリであり、テキストデータを分析します。
このチュートリアルでは、さまざまなデータクリーニング方法を使用して、NLP用のNLTKパッケージからサンプルツイートのデータセットを準備します。 データセットを処理する準備ができたら、事前に分類されたツイートでモデルをトレーニングし、そのモデルを使用してサンプルのツイートを否定的な感情と肯定的な感情に分類します。
この記事は、 Python ( Python 3シリーズのコーディング方法を参照)の基本、主にデータ構造、クラス、およびメソッドの使用に精通していることを前提としています。 このチュートリアルでは、NLPとnltk
の知識がないことを前提としていますが、それに関する知識が追加されています。
前提条件
- このチュートリアルは、Pythonバージョン3.6.5に基づいています。 Python 3をインストールしていない場合は、Python3のローカルプログラミング環境をインストールしてセットアップするためのガイドを以下に示します。
- 言語データの操作に精通していることをお勧めします。 NLTKを初めて使用する場合は、 Natural Language Toolkit(NLTK)ガイドを使用してPython3で言語データを操作する方法を確認してください。
ステップ1—NLTKのインストールとデータのダウンロード
このチュートリアルでは、すべてのNLPタスクにPythonのNLTKパッケージを使用します。 このステップでは、NLTKをインストールし、モデルのトレーニングとテストに使用するサンプルツイートをダウンロードします。
まず、NLTKパッケージをpip
パッケージマネージャーでインストールします。
pip install nltk==3.3
このチュートリアルでは、NLTKパッケージの一部であるサンプルツイートを使用します。 まず、次のコマンドを実行してPythonインタラクティブセッションを開始します。
python3
次に、Pythonインタープリターにnltk
モジュールをインポートします。
import nltk
NLTKパッケージからサンプルツイートをダウンロードします。
nltk.download('twitter_samples')
Pythonインタープリターからこのコマンドを実行すると、ツイートがダウンロードされてローカルに保存されます。 サンプルがダウンロードされると、使用できるようになります。
チュートリアルの後半で、ネガティブツイートとポジティブツイートを使用して、感情分析に関するモデルをトレーニングします。 感情のないツイートは、モデルのテストに使用されます。
独自のデータセットを使用する場合は、 Twitter API を使用して、特定の期間、ユーザー、またはハッシュタグからツイートを収集できます。
NLTKをインポートし、サンプルツイートをダウンロードしたので、exit()
と入力してインタラクティブセッションを終了します。 これで、ツイートをインポートしてデータの処理を開始する準備が整いました。
ステップ2—データのトークン化
元の形式の言語は機械で正確に処理できないため、機械が理解しやすいように言語を処理する必要があります。 データを理解するための最初の部分は、トークン化と呼ばれるプロセス、またはトークンと呼ばれる小さな部分に文字列を分割することです。
トークンは、ユニットとして機能するテキスト内の文字のシーケンスです。 トークンの作成方法に基づいて、トークンは単語、絵文字、ハッシュタグ、リンク、または個々の文字で構成されている場合があります。 言語をトークンに分割する基本的な方法は、空白と句読点に基づいてテキストを分割することです。
開始するには、スクリプトを保持する新しい.py
ファイルを作成します。 このチュートリアルでは、nlp_test.py
を使用します。
nano nlp_test.py
このファイルでは、最初にtwitter_samples
をインポートして、そのデータを操作できるようにします。
nlp_test.py
from nltk.corpus import twitter_samples
これにより、モデルをトレーニングおよびテストするためのさまざまなツイートを含む3つのデータセットがNLTKからインポートされます。
negative_tweets.json
:否定的な感情を持つ5000件のツイートpositive_tweets.json
:肯定的な感情を持つ5000件のツイートtweets.20150430-223406.json
:感情のない20000ツイート
次に、positive_tweets
、negative_tweets
、およびtext
の変数を作成します。
nlp_test.py
from nltk.corpus import twitter_samples positive_tweets = twitter_samples.strings('positive_tweets.json') negative_tweets = twitter_samples.strings('negative_tweets.json') text = twitter_samples.strings('tweets.20150430-223406.json')
twitter_samples
のstrings()
メソッドは、データセット内のすべてのツイートを文字列として出力します。 さまざまなツイートコレクションを変数として設定すると、処理とテストが簡単になります。
NLTKでトークナイザーを使用する前に、追加のリソースpunkt
をダウンロードする必要があります。 punkt
モジュールは、単語や文をトークン化するのに役立つ事前トレーニング済みのモデルです。 たとえば、このモデルは、名前にピリオドが含まれている可能性があることを認識しています(「S. Daityari」)と文のこの期間の存在は必ずしもそれを終わらせるわけではありません。 まず、Pythonインタラクティブセッションを開始します。
python3
セッションで次のコマンドを実行して、punkt
リソースをダウンロードします。
import nltk nltk.download('punkt')
ダウンロードが完了すると、NLTKのトークナイザーを使用できるようになります。 NLTKは、.tokenized()
メソッドを使用したツイートのデフォルトのトークナイザーを提供します。 positive_tweets.json
データセットをトークン化するオブジェクトを作成する行を追加します。
nlp_test.py
from nltk.corpus import twitter_samples positive_tweets = twitter_samples.strings('positive_tweets.json') negative_tweets = twitter_samples.strings('negative_tweets.json') text = twitter_samples.strings('tweets.20150430-223406.json') tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
スクリプトをテストして.tokenized
メソッドの動作を確認する場合は、強調表示されたコンテンツをnlp_test.py
スクリプトに追加します。 これにより、positive_tweets.json
データセットからの単一のツイートがトークン化されます。
nlp_test.py
from nltk.corpus import twitter_samples positive_tweets = twitter_samples.strings('positive_tweets.json') negative_tweets = twitter_samples.strings('negative_tweets.json') text = twitter_samples.strings('tweets.20150430-223406.json') tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0] print(tweet_tokens[0])
ファイルを保存して閉じ、スクリプトを実行します。
python3 nlp_test.py
トークン化のプロセスは、空白での単純な分割ではないため、時間がかかります。 しばらく処理すると、次のように表示されます。
Output['#FollowFriday', '@France_Inte', '@PKuchly57', '@Milipol_Paris', 'for', 'being', 'top', 'engaged', 'members', 'in', 'my', 'community', 'this', 'week', ':)']
ここで、.tokenized()
メソッドは、@
や_
などの特殊文字を返します。 これらの文字は、このチュートリアルの後半で正規表現によって削除されます。
.tokenized()
メソッドがどのように機能するかを確認したので、コメントアウトするか、最後の行を削除して、行の先頭に#
を追加して、トークン化されたツイートをスクリプトから印刷してください。 :
nlp_test.py
from nltk.corpus import twitter_samples positive_tweets = twitter_samples.strings('positive_tweets.json') negative_tweets = twitter_samples.strings('negative_tweets.json') text = twitter_samples.strings('tweets.20150430-223406.json') tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0] #print(tweet_tokens[0])
これで、データをトークン化するようにスクリプトが構成されました。 次のステップでは、スクリプトを更新してデータを正規化します。
ステップ3—データの正規化
単語にはさまざまな形式があります。たとえば、「ran」、「runs」、「running」は、同じ動詞「run」のさまざまな形式です。 分析の要件によっては、これらすべてのバージョンを同じ形式の「実行」に変換する必要がある場合があります。 NLPの正規化は、単語を標準形に変換するプロセスです。
正規化は、同じ意味で異なる形式の単語をグループ化するのに役立ちます。 正規化しないと、「run」、「runs」、および「running」は、同じ単語として扱われるようにしたい場合でも、異なる単語として扱われます。 このセクションでは、正規化の2つの一般的な手法であるステミングとレンマ化について説明します。
ステミングは、単語から接辞を削除するプロセスです。 単純な動詞形式のみを処理するステミングは、単語の終わりを削除するヒューリスティックなプロセスです。
このチュートリアルでは、語彙のコンテキストとテキスト内の単語の形態素解析で単語を正規化するレンマ化のプロセスを使用します。 レンマ化アルゴリズムは、単語の構造とそのコンテキストを分析して、正規化された形式に変換します。 したがって、速度が犠牲になります。 ステミングとレンマ化の比較は、最終的には速度と精度の間のトレードオフになります。
lemmatizationの使用に進む前に、Pythonインタラクティブセッションに次のように入力して、必要なリソースをダウンロードしてください。
python3
セッションで次のコマンドを実行して、リソースをダウンロードします。
import nltk nltk.download('wordnet') nltk.download('averaged_perceptron_tagger')
wordnet は、スクリプトがベースワードを決定するのに役立つ英語の字句データベースです。 文中の単語の文脈を判断するには、averaged_perceptron_tagger
リソースが必要です。
ダウンロードすると、レンマタイザーを使用する準備がほぼ整います。 レンマタイザーを実行する前に、テキスト内の各単語のコンテキストを決定する必要があります。 これは、文中の単語の相対的な位置を評価するタグ付けアルゴリズムによって実現されます。 Pythonセッションで、pos_tag
関数をインポートし、タグを取得するための引数としてトークンのリストを提供します。 Pythonでこれを試してみましょう:
from nltk.tag import pos_tag from nltk.corpus import twitter_samples tweet_tokens = twitter_samples.tokenized('positive_tweets.json') print(pos_tag(tweet_tokens[0]))
pos_tag
関数の出力は次のとおりです。
Output[('#FollowFriday', 'JJ'), ('@France_Inte', 'NNP'), ('@PKuchly57', 'NNP'), ('@Milipol_Paris', 'NNP'), ('for', 'IN'), ('being', 'VBG'), ('top', 'JJ'), ('engaged', 'VBN'), ('members', 'NNS'), ('in', 'IN'), ('my', 'PRP$'), ('community', 'NN'), ('this', 'DT'), ('week', 'NN'), (':)', 'NN')]
タグのリストから、最も一般的なアイテムとその意味のリストを次に示します。
NNP
:名詞、適切、単数NN
:名詞、一般、単数、または質量IN
:前置詞または接続詞、従属VBG
:動詞、動名詞、または現在分詞VBN
:動詞、過去分詞
これがデータセットの完全なリストです。
一般に、タグがNN
で始まる場合、その単語は名詞であり、VB
で始まる場合、その単語は動詞です。 タグを確認したら、exit()
と入力してPythonセッションを終了します。
これを文を正規化する関数に組み込むには、最初にテキスト内の各トークンのタグを生成してから、タグを使用して各単語を語彙化する必要があります。
nlp_test.py
ファイルを、文をレンマ化する次の関数で更新します。
nlp_test.py
... from nltk.tag import pos_tag from nltk.stem.wordnet import WordNetLemmatizer def lemmatize_sentence(tokens): lemmatizer = WordNetLemmatizer() lemmatized_sentence = [] for word, tag in pos_tag(tokens): if tag.startswith('NN'): pos = 'n' elif tag.startswith('VB'): pos = 'v' else: pos = 'a' lemmatized_sentence.append(lemmatizer.lemmatize(word, pos)) return lemmatized_sentence print(lemmatize_sentence(tweet_tokens[0]))
このコードは、WordNetLemmatizer
クラスをインポートし、それを変数lemmatizer
に初期化します。
関数lemmatize_sentence
は、最初にツイートの各トークンの位置タグを取得します。 if
ステートメント内で、タグがNN
で始まる場合、トークンは名詞として割り当てられます。 同様に、タグがVB
で始まる場合、トークンは動詞として割り当てられます。
ファイルを保存して閉じ、スクリプトを実行します。
python3 nlp_test.py
出力は次のとおりです。
Output['#FollowFriday', '@France_Inte', '@PKuchly57', '@Milipol_Paris', 'for', 'be', 'top', 'engage', 'member', 'in', 'my', 'community', 'this', 'week', ':)']
動詞being
がそのルート形式be
に変わり、名詞members
がmember
に変わることに気付くでしょう。 先に進む前に、スクリプトからのサンプルツイートを出力する最後の行をコメントアウトしてください。
単語を正規化する関数を正常に作成したので、ノイズを除去する準備が整いました。
ステップ4—データからノイズを取り除く
このステップでは、データセットからノイズを除去します。 Noise は、データに意味や情報を追加しないテキストの一部です。
ノイズはプロジェクトごとに固有であるため、あるプロジェクトでノイズを構成するものが別のプロジェクトにない場合があります。 たとえば、ある言語で最も一般的な単語は、ストップワードと呼ばれます。 ストップワードの例としては、「is」、「the」、「a」などがあります。 特定のユースケースでそれらを含めることが保証されない限り、言語を処理する際には一般的に無関係です。
このチュートリアルでは、 Python の正規表現を使用して、次のアイテムを検索および削除します。
- ハイパーリンク-Twitterのすべてのハイパーリンクは、URL短縮サービスt.coに変換されます。 したがって、それらをテキスト処理に保持しても、分析に価値はありません。
- 返信でのTwitterの処理-これらのTwitterユーザー名の前には、意味を伝えない
@
記号が付いています。 - 句読点と特殊文字-これらはテキストデータにコンテキストを提供することがよくありますが、このコンテキストは処理が難しいことがよくあります。 簡単にするために、ツイートからすべての句読点と特殊文字を削除します。
ハイパーリンクを削除するには、最初にhttp://
またはhttps://
で始まり、その後に文字、数字、または特殊文字が続くURLに一致する部分文字列を検索する必要があります。 パターンが一致すると、.sub()
メソッドはパターンを空の文字列に置き換えます。
remove_noise()
関数内の単語形式を正規化するため、スクリプトからlemmatize_sentence()
関数をコメントアウトできます。
次のコードをnlp_test.py
ファイルに追加して、データセットからノイズを削除します。
nlp_test.py
... import re, string def remove_noise(tweet_tokens, stop_words = ()): cleaned_tokens = [] for token, tag in pos_tag(tweet_tokens): token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\ '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token) token = re.sub("(@[A-Za-z0-9_]+)","", token) if tag.startswith("NN"): pos = 'n' elif tag.startswith('VB'): pos = 'v' else: pos = 'a' lemmatizer = WordNetLemmatizer() token = lemmatizer.lemmatize(token, pos) if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words: cleaned_tokens.append(token.lower()) return cleaned_tokens
このコードは、ノイズを除去し、前のセクションで説明した正規化とレンマ化を組み込んだremove_noise()
関数を作成します。 このコードは、ツイートトークンとストップワードのタプルの2つの引数を取ります。
次に、コードはループを使用してデータセットからノイズを除去します。 ハイパーリンクを削除するには、コードは最初にhttp://
またはhttps://
で始まり、その後に文字、数字、または特殊文字が続くURLに一致する部分文字列を検索します。 パターンが一致すると、.sub()
メソッドは、パターンを空の文字列、つまりに置き換えます。
同様に、@
の言及を削除するために、コードは正規表現を使用してテキストの関連部分を置き換えます。 このコードは、re
ライブラリを使用して、@
記号に続いて数字、文字、または_
を検索し、それらを空の文字列に置き換えます。
最後に、ライブラリstring
を使用して句読点を削除できます。
これに加えて、NLTKに組み込まれているストップワードのセットを使用してストップワードを削除することもできます。これは、別途ダウンロードする必要があります。
Pythonインタラクティブセッションから次のコマンドを実行して、このリソースをダウンロードします。
nltk.download('stopwords')
リソースがダウンロードされたら、インタラクティブセッションを終了します。
.words()
メソッドを使用して、英語のストップワードのリストを取得できます。 関数をテストするために、サンプルツイートで実行してみましょう。 nlp_test.py
ファイルの最後に次の行を追加します。
nlp_test.py
... from nltk.corpus import stopwords stop_words = stopwords.words('english') print(remove_noise(tweet_tokens[0], stop_words))
ファイルを保存して閉じた後、スクリプトを再度実行して、次のような出力を受け取ります。
Output['#followfriday', 'top', 'engage', 'member', 'community', 'week', ':)']
この関数は、@
のすべての言及を削除し、単語を停止し、単語を小文字に変換することに注意してください。
次のステップのモデリング演習に進む前に、remove_noise()
関数を使用して、ポジティブツイートとネガティブツイートをクリーンアップします。 remove_noise()
の出力をサンプルツイートに出力する行をコメントアウトし、nlp_test.py
スクリプトに以下を追加します。
nlp_test.py
... from nltk.corpus import stopwords stop_words = stopwords.words('english') #print(remove_noise(tweet_tokens[0], stop_words)) positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json') negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json') positive_cleaned_tokens_list = [] negative_cleaned_tokens_list = [] for tokens in positive_tweet_tokens: positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words)) for tokens in negative_tweet_tokens: negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words))
サンプルツイートをクリーンアップするコードを追加したので、元のトークンをサンプルツイートのクリーンアップされたトークンと比較することをお勧めします。 これをテストする場合は、次のコードをファイルに追加して、リスト内の500番目のツイートの両方のバージョンを比較します。
nlp_test.py
... print(positive_tweet_tokens[500]) print(positive_cleaned_tokens_list[500])
ファイルを保存して閉じ、スクリプトを実行します。 出力から、句読点とリンクが削除され、単語が小文字に変換されていることがわかります。
Output['Dang', 'that', 'is', 'some', 'rad', '@AbzuGame', '#fanart', '!', ':D', 'https://t.co/bI8k8tb9ht'] ['dang', 'rad', '#fanart', ':d']
テキストの前処理中に発生する可能性のある特定の問題があります。 たとえば、スペースのない単語(“ iLoveYou”)は1つとして扱われ、そのような単語を区切るのは難しい場合があります。 さらに、「Hi」、「Hii」、および「Hiiiii」は、問題に取り組むために特定の何かを記述しない限り、スクリプトによって異なる方法で処理されます。 特定のデータのノイズ除去プロセスを微調整するのが一般的です。
remove_noise()
関数の動作を確認したので、スクリプトにコメントアウトするか、スクリプトから最後の2行を削除して、さらに追加できるようにしてください。
nlp_test.py
... #print(positive_tweet_tokens[500]) #print(positive_cleaned_tokens_list[500])
このステップでは、分析をより効果的にするために、データからノイズを除去しました。 次のステップでは、データを分析して、サンプルデータセットで最も一般的な単語を見つけます。
ステップ5—単語密度の決定
テキストデータの分析の最も基本的な形式は、単語の頻度を取り出すことです。 単一のツイートは、単語の分布を見つけるにはエンティティとしては小さすぎるため、単語の頻度の分析は、すべての肯定的なツイートに対して行われます。
次のスニペットは、ジェネレーター関数を定義します。この関数は、get_all_words
という名前で、ツイートのリストを引数として取り、結合されたすべてのツイートトークンの単語のリストを提供します。 nlp_test.py
ファイルに次のコードを追加します。
nlp_test.py
... def get_all_words(cleaned_tokens_list): for tokens in cleaned_tokens_list: for token in tokens: yield token all_pos_words = get_all_words(positive_cleaned_tokens_list)
ツイートのサンプルにあるすべての単語をまとめたので、NLTKのFreqDistクラスを使用して最も一般的な単語を見つけることができます。 nlp_test.py
ファイルに次のコードを追加します。
nlp_test.py
from nltk import FreqDist freq_dist_pos = FreqDist(all_pos_words) print(freq_dist_pos.most_common(10))
.most_common()
メソッドは、データで最も頻繁に出現する単語を一覧表示します。 これらの変更を行った後、ファイルを保存して閉じます。
ここでファイルを実行すると、データに最も一般的な用語が含まれています。
Output[(':)', 3691), (':-)', 701), (':d', 658), ('thanks', 388), ('follow', 357), ('love', 333), ('...', 290), ('good', 283), ('get', 263), ('thank', 253)]
このデータから、絵文字エンティティがポジティブツイートの最も一般的な部分のいくつかを形成していることがわかります。 次のステップに進む前に、上位10個のトークンを出力するスクリプトの最後の行を必ずコメントアウトしてください。
要約すると、nltk
からツイートを抽出し、トークン化、正規化、およびモデルで使用するためのツイートのクリーンアップを行いました。 最後に、データ内のトークンの頻度も調べ、上位10個のトークンの頻度を確認しました。
次のステップでは、感情分析用のデータを準備します。
ステップ6—モデルのデータを準備する
感情分析は、書かれているトピックに対する著者の態度を特定するプロセスです。 モデルをトレーニングするためのトレーニングデータセットを作成します。 これは教師あり学習機械学習プロセスであり、各データセットをトレーニングの「感情」に関連付ける必要があります。 このチュートリアルでは、モデルは「ポジティブ」および「ネガティブ」な感情を使用します。
感情分析を使用して、テキストをさまざまな感情に分類できます。 トレーニングデータセットを簡素化して利用できるようにするために、このチュートリアルでは、ポジティブとネガティブの2つのカテゴリのみでモデルをトレーニングするのに役立ちます。
モデルは、ルールと方程式を使用したシステムの記述です。 身長を考えると、人の体重を予測する方程式のように単純な場合があります。 構築する感情分析モデルは、ツイートをポジティブまたはネガティブな感情に関連付けます。 データセットを2つの部分に分割する必要があります。 最初の部分の目的はモデルを構築することですが、次の部分はモデルのパフォーマンスをテストします。
データ準備ステップでは、トークンを辞書形式に変換して感情分析用のデータを準備し、トレーニングとテストの目的でデータを分割します。
トークンを辞書に変換する
まず、モデルに入力するデータを準備します。 NLTKの単純ベイズ分類器を使用して、モデリングの演習を行います。 モデルには、ツイート内の単語のリストだけでなく、単語をキーとして、True
を値として持つPython辞書が必要であることに注意してください。 次の関数は、クリーンアップされたデータの形式を変更するジェネレーター関数を作成します。
次のコードを追加して、ツイートをクリーンアップされたトークンのリストから、キーをトークンとしてTrue
を値として持つ辞書に変換します。 対応する辞書はpositive_tokens_for_model
とnegative_tokens_for_model
に保存されます。
nlp_test.py
... def get_tweets_for_model(cleaned_tokens_list): for tweet_tokens in cleaned_tokens_list: yield dict([token, True] for token in tweet_tokens) positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list) negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list)
モデルのトレーニングとテストのためのデータセットの分割
次に、NaiveBayesClassifier
クラスをトレーニングするためのデータを準備する必要があります。 次のコードをファイルに追加して、データを準備します。
nlp_test.py
... import random positive_dataset = [(tweet_dict, "Positive") for tweet_dict in positive_tokens_for_model] negative_dataset = [(tweet_dict, "Negative") for tweet_dict in negative_tokens_for_model] dataset = positive_dataset + negative_dataset random.shuffle(dataset) train_data = dataset[:7000] test_data = dataset[7000:]
このコードは、各ツイートにPositive
またはNegative
のラベルを付けます。 次に、ポジティブツイートとネガティブツイートを結合してdataset
を作成します。
デフォルトでは、データにはすべての肯定的なツイートとそれに続くすべての否定的なツイートが順番に含まれます。 モデルをトレーニングするときは、バイアスを含まないデータのサンプルを提供する必要があります。 偏りを避けるために、random
の.shuffle()
メソッドを使用してデータをランダムに配置するコードを追加しました。
最後に、コードはシャッフルされたデータをトレーニングとテストのためにそれぞれ70:30の比率に分割します。 ツイートの数は10000であるため、シャッフルされたデータセットの最初の7000ツイートをモデルのトレーニングに使用し、最後の3000ツイートをモデルのテストに使用できます。
このステップでは、クリーンアップされたトークンを辞書形式に変換し、データセットをランダムにシャッフルして、トレーニングデータとテストデータに分割しました。
ステップ7—モデルの構築とテスト
最後に、NaiveBayesClassifier
クラスを使用してモデルを構築できます。 .train()
メソッドを使用してモデルをトレーニングし、.accuracy()
メソッドを使用してテストデータでモデルをテストします。
nlp_test.py
... from nltk import classify from nltk import NaiveBayesClassifier classifier = NaiveBayesClassifier.train(train_data) print("Accuracy is:", classify.accuracy(classifier, test_data)) print(classifier.show_most_informative_features(10))
コードを追加したら、ファイルを保存して閉じ、実行します。 コードの出力は次のようになります。
OutputAccuracy is: 0.9956666666666667 Most Informative Features :( = True Negati : Positi = 2085.6 : 1.0 :) = True Positi : Negati = 986.0 : 1.0 welcome = True Positi : Negati = 37.2 : 1.0 arrive = True Positi : Negati = 31.3 : 1.0 sad = True Negati : Positi = 25.9 : 1.0 follower = True Positi : Negati = 21.1 : 1.0 bam = True Positi : Negati = 20.7 : 1.0 glad = True Positi : Negati = 18.1 : 1.0 x15 = True Negati : Positi = 15.9 : 1.0 community = True Positi : Negati = 14.1 : 1.0
精度は、モデルが感情を正しく予測できたテストデータセット内のツイートの割合として定義されます。 テストセットの99.5%の精度はかなり良いです。
最も有益な機能を示す表では、出力のすべての行に、トレーニングデータセットのポジティブタグとネガティブタグのツイートでのトークンの発生率が示されています。 データの最初の行は、トークン:(
を含むすべてのツイートで、否定的なツイートと肯定的なツイートの比率が2085.6
対1
であることを示しています。 興味深いことに、ポジティブデータセットには:(
のトークンが1つあったようです。 テキストの上位2つの識別項目が絵文字であることがわかります。 さらに、sad
などの単語は否定的な感情につながりますが、welcome
やglad
は肯定的な感情に関連付けられています。
次に、Twitterからのランダムなツイートでモデルがどのように機能するかを確認できます。 次のコードをファイルに追加します。
nlp_test.py
... from nltk.tokenize import word_tokenize custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again." custom_tokens = remove_noise(word_tokenize(custom_tweet)) print(classifier.classify(dict([token, True] for token in custom_tokens)))
このコードを使用すると、custom_tweet
変数に関連付けられた文字列を更新して、カスタムツイートをテストできます。 これらの変更を行った後、ファイルを保存して閉じます。
スクリプトを実行して、カスタムテキストを分析します。 例のカスタムテキストの出力は次のとおりです。
Output'Negative'
また、肯定的なツイートを正しく特徴付けているかどうかを確認することもできます。
nlp_test.py
... custom_tweet = 'Congrats #SportStar on your 7th best goal from last season winning goal of the year :) #Baller #Topbin #oneofmanyworldies'
出力は次のとおりです。
Output'Positive'
ポジティブな感情とネガティブな感情の両方をテストしたので、変数を更新して、皮肉のようなより複雑な感情をテストします。
nlp_test.py
... custom_tweet = 'Thank you for sending my baggage to CityX and flying me to CityY at the same time. Brilliant service. #thanksGenericAirline'
出力は次のとおりです。
Output'Positive'
モデルは、この例をポジティブとして分類しました。 これは、トレーニングデータが、皮肉なツイートをネガティブとして分類するのに十分なほど包括的ではなかったためです。 モデルで皮肉を予測する場合は、それに応じてモデルをトレーニングするために十分な量のトレーニングデータを提供する必要があります。
このステップでは、モデルを作成してテストしました。 また、特定の例で皮肉を検出しないなど、その制限のいくつかについても調査しました。 完成したコードには、チュートリアルに従うことでアーティファクトが残っているため、次のステップでは、コードをPythonのベストプラクティスに合わせる方法を説明します。
ステップ8—コードのクリーンアップ(オプション)
チュートリアルは完了していますが、nlp_test.py
ファイルのコードを再編成して、プログラミングのベストプラクティスに従うことをお勧めします。 ベストプラクティスに従って、コードは次の基準を満たす必要があります。
- すべてのインポートはファイルの先頭にある必要があります。 同じライブラリからのインポートは、1つのステートメントにグループ化する必要があります。
- すべての関数は、インポート後に定義する必要があります。
- ファイル内のすべてのステートメントは、
if __name__ == "__main__":
条件で格納する必要があります。 これにより、ファイルの機能を別のファイルにインポートする場合にステートメントが実行されなくなります。
また、新しいremove_noise
関数によってレンマ化が完了するため、lemmatize_sentence
関数とともに、チュートリアルに従ってコメントアウトされたコードを削除します。
nlp_test.py
のクリーンバージョンは次のとおりです。
from nltk.stem.wordnet import WordNetLemmatizer from nltk.corpus import twitter_samples, stopwords from nltk.tag import pos_tag from nltk.tokenize import word_tokenize from nltk import FreqDist, classify, NaiveBayesClassifier import re, string, random def remove_noise(tweet_tokens, stop_words = ()): cleaned_tokens = [] for token, tag in pos_tag(tweet_tokens): token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\ '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token) token = re.sub("(@[A-Za-z0-9_]+)","", token) if tag.startswith("NN"): pos = 'n' elif tag.startswith('VB'): pos = 'v' else: pos = 'a' lemmatizer = WordNetLemmatizer() token = lemmatizer.lemmatize(token, pos) if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words: cleaned_tokens.append(token.lower()) return cleaned_tokens def get_all_words(cleaned_tokens_list): for tokens in cleaned_tokens_list: for token in tokens: yield token def get_tweets_for_model(cleaned_tokens_list): for tweet_tokens in cleaned_tokens_list: yield dict([token, True] for token in tweet_tokens) if __name__ == "__main__": positive_tweets = twitter_samples.strings('positive_tweets.json') negative_tweets = twitter_samples.strings('negative_tweets.json') text = twitter_samples.strings('tweets.20150430-223406.json') tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0] stop_words = stopwords.words('english') positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json') negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json') positive_cleaned_tokens_list = [] negative_cleaned_tokens_list = [] for tokens in positive_tweet_tokens: positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words)) for tokens in negative_tweet_tokens: negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words)) all_pos_words = get_all_words(positive_cleaned_tokens_list) freq_dist_pos = FreqDist(all_pos_words) print(freq_dist_pos.most_common(10)) positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list) negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list) positive_dataset = [(tweet_dict, "Positive") for tweet_dict in positive_tokens_for_model] negative_dataset = [(tweet_dict, "Negative") for tweet_dict in negative_tokens_for_model] dataset = positive_dataset + negative_dataset random.shuffle(dataset) train_data = dataset[:7000] test_data = dataset[7000:] classifier = NaiveBayesClassifier.train(train_data) print("Accuracy is:", classify.accuracy(classifier, test_data)) print(classifier.show_most_informative_features(10)) custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again." custom_tokens = remove_noise(word_tokenize(custom_tweet)) print(custom_tweet, classifier.classify(dict([token, True] for token in custom_tokens)))
結論
このチュートリアルでは、Python3のnltk
ライブラリを使用した基本的な感情分析モデルを紹介しました。 まず、ツイートをトークン化し、単語を正規化し、ノイズを除去することにより、ツイートの前処理を実行しました。 次に、データ内で頻繁に発生するアイテムを視覚化しました。 最後に、ツイートを特定の感情に関連付けるモデルを作成しました。
教師あり学習モデルは、そのトレーニングデータと同じくらい優れています。 モデルをさらに強化するために、興奮や怒りなどのカテゴリをさらに追加することを検討できます。 このチュートリアルでは、基本的なモデルを作成することによって表面を引っかいただけです。 ここに感情分析を実行する際に注意しなければならないさまざまな考慮事項の詳細なガイドがあります。