6章 クラス分類 II:感情分析
まずはツイートデータを取得します。
しかし、ここでつまずきました...
いろいろ調べてツイートをダウンロードするコードを書きました。
tweepyというモジュールをダウンロードします。
以下のサイトが参考になりました
statsbeginner.hatenablog.com
しかし、API制限という最悪なものがあるため、どうやら180回/15分しかツイートをダウンロードできないようです。
API制限まとめ
解除する方法もちらほらあるようですが、自分にはよくわからないので仕方なく仕様どうりに行きたいと思います。
http://www.sananalytics.com/lab/twitter-sentiment/
このサイトから"sanders-twitter-0.2.zip"をダウンロードして解凍します。
その中にある、"corpus.csv"と同じディレクトリ内で以下のコードを実行します。
import tweepy import csv import time import numpy as np import pandas as pd from time import sleep # csvファイル読み込み d = pd.read_csv('corpus.csv', names=['topic', 'pos/neg', 'id']) f = open("tweet_text.csv", "a") writer = csv.writer(f) data = np.array(d['id']) # 各種キーをセット CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) ACCESS_TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' ACCESS_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET) #APIインスタンスを作成 api = tweepy.API(auth) text = [] error = [] data_size = len(data) for i in range(data_size): if i % 180 or i == 0: try: text.append([api.get_status(data[i]).text]) except: text.append(["Error"]) error.append(i) print(i," : Error") else: print("stop downloading(API) time [{} : {}] ".format(time.gmtime().tm_hour, time.gmtime().tm_min)) print("Error tottal : ", len(error)) sleep(900) continue print("finished") print("error index", error) writer.writerows(text) f.close()
7時間ぐらいかかります笑
終わると、"tweet_text.csv"というファイルが生成されていると思います。
最初はpositiveとnegativeの分類です。
"tweet_text.csvでは、1〜191までが"positive"、192〜568までが"negative"となっています。
なので、"Error"以外を取り除いて読み取っていきます。
f = open("tweet_text.csv", "r") text = [] index = [] for i in range(568): t = f.readline() if t != 'Error\n': text.append(t) if i<=190: index.append(0) elif 191<= i <= 567: index.append(1)
その後、前回つかった"StemmedTfidfVectorizer"を使います。
english_stemmer = nltk.stem.SnowballStemmer('english') class StemmedTfidfVectorizer(TfidfVectorizer): def build_analyzer(self): analyzer = super(TfidfVectorizer, self).build_analyzer() return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc)) vec = StemmedTfidfVectorizer(ngram_range=(1, 3), stop_words='english', decode_error='ignore') X = vec.fit_transform(text) y = np.array(index) X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, random_state=0) clf = MultinomialNB(alpha=0.8) clf.fit(X_train, y_train)
正解率とAUCを見て行きましょう。
正解率 : 0.69105691056 AUC : 0.82078313253
本とは違うやり方をしたせいか、正解率が約70%ととても低いです...
とりあえず、bias-variansグラフを見てみましょう。
!?!? 超ハイバリアンスですね...
ちょっとやる気をなくしたので、感情ありor感情なしの分類の方へ逃げようと思います。
感情なしのツイートは568〜5483になっています。
感情ありと感情なしのデータ比がちょっと....
細かいことは気にせずやっていきましょう。
for i in range(5483): t = f.readline() if t != 'Error\n': text.append(t) if i<=567: index.append(0) else: index.append(1)
正解率とAUCを見て行きましょう。
正解率 : 0.90955882352 AUC : 0.882790780212
正解率90%はなかなかいい数字だと思います。
これも、bias-variansグラフを見てみましょう。
なかなかいい感じじゃなかいか!!
これで満足です。
positiveとnegativeの分類は忘れたとこにしましょう。
一応、全体のコードです。
import numpy as np import nltk.stem import matplotlib.pyplot as plt from sklearn.metrics import roc_auc_score from sklearn.naive_bayes import MultinomialNB from sklearn.cross_validation import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer f = open("tweet_text.csv", "r") text = [] index = [] for i in range(568): t = f.readline() if t != 'Error\n': text.append(t) if i<=190: index.append(0) elif 191<= i <= 567: index.append(1) english_stemmer = nltk.stem.SnowballStemmer('english') class StemmedTfidfVectorizer(TfidfVectorizer): def build_analyzer(self): analyzer = super(TfidfVectorizer, self).build_analyzer() return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc)) vec = StemmedTfidfVectorizer(ngram_range=(1, 3), stop_words='english', decode_error='ignore') X = vec.fit_transform(text) y = np.array(index) X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, random_state=0) clf = MultinomialNB(alpha=0.8) clf.fit(X_train, y_train) y_pred = clf.predict_proba(X_test)[:, 1] print("正解率 : ", clf.score(X_test, y_test)) print("AUC : ", roc_auc_score(y_test, y_pred))