単語の処理の仕方もかなりわかりましたので、今度こそ福岡聖菜のtweetを判定したいと思います。 前回のダメな例がこちらです。
dailytextmining.hatenablog.com
前処理
6月10日から8月10日までの全tweetを取得します。列はid, name, tweetの3列、行数は3264行です。2ヶ月も続けていますと結構集まりますね。今日で50日目です。飽きずによくやっているなと思います。
とりあえず、pandasを使ってデータフレームとして読み込みます。
import pandas as pd import numpy as np %matplotlib inline import matplotlib.pyplot as plt train = pd.read_csv('all_20180812.csv', header = 0, delimiter = ",")
チュートリアルだとquoting=3という引数がありましたが、これをつけるとエラーが起こりましたので外しました。
tweet内容が読み込めたところで、nameを福岡聖菜の場合は1を、福岡聖菜ではない場合は0を代入にして正解ラベルを作ります。
train["name"].loc[train["name"] != "seina_fuku48"] = 0 train["name"].loc[train["name"] == "seina_fuku48"] = 1
それで、前回は気づかなかったのですが、ただ単に0と1を代入しただけでは、この0と1は文字列なんですよね。
print(train.dtypes)
id int64 name object tweet object dtype: object
正解データとして扱うにはintにする必要がありますので、name内の数値をコピーして、新しくintの列を作ります。
train['name_int'] = train['name'].astype(np.int64) train
実行結果はこんな感じです。
id name tweet name_int 0 1 0 #アイドル修業中♡公演\n来てくれて、見てくれて、\nありがとうございました???!\n\n... 0 1 2 0 今日は #山根涼羽 ずんちゃんと、\nカフェに行ったりお買い物しました☕??\n大切な同期と... 0 2 3 0 投票した\nマイスイートピアノちゃん\n17位だ???!!!!!\nピアノちゃんすき?!!!... 0
次に、tweet内容を詳しく見てみます。
train['tweet'][0]
'#アイドル修業中♡公演\n来てくれて、見てくれて、\nありがとうございました???!\n\nドラフト3期生の\n#齋藤陽菜 ちゃん(はーたん)(1枚目)と\n#石綿星南 ちゃん(せなたん)(2枚目)が劇場フル出演デビューでした~!✨\n出てくれ… https://t.co/PuFkSwSEnZ'
HTMLタグはないですね。なので、MeCabだけを関数としてまとめます。tweet内のリンク(http以降)を消すか消さないかで迷いましたが、リンクのあるなしも重要な要素だと思いますので、残しておきました。
import MeCab import re tagger = MeCab.Tagger ("-Owakati") def tweet_to_words(raw_tweet): # letters_only = re.sub("(https?)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)", " ", tweet_text) mecab = tagger.parse(raw_tweet) return(mecab)
結果はこんな感じです。
tweet_to_words(train["tweet"][0])
'# アイドル修業中 ♡ 公演 来 て くれ て 、 見 て くれ て 、 ありがとう ござい まし た ???! ドラフト 3 期生 の # 齋藤 陽 菜 ちゃん ( は ー たん )( 1 枚 目 ) と # 石綿 星 南 ちゃん ( せ な たん )( 2 枚 目 ) が 劇場 フル 出演 デビュー でし た ~!✨ 出 て くれ … https :// t . co / PuFkSwSEnZ \n'
ややばらけ過ぎている気がしますが、そのまま続けてみます。
この関数をtweetの数だけfor文で回していきます。
num_tweets = train["tweet"].size clean_train_reviews = [] for i in range(0, num_tweets): clean_train_tweets.append( tweet_to_words( train["tweet"][i] ) ) print(clean_train_reviews)
TypeError: object of type 'float' has no len()
コードは間違っていないはずですが、エラーが起きました。 こういう場合はデータが悪いはずなので、tweet内容にNaNがないか見てみます。
train.isnull().any(axis=0)
id False name False tweet True name_int False dtype: bool
まぁ、NaNが当然ありますね。 いつも通り、train[train.isnull().any(1)]で検索していってNaNを消していきます。
NaNを全部消してみたところで、再実行。BeautifulSoupの警告が出てきましたが、実行できました。
from sklearn.feature_extraction.text import CountVectorizer vectorizer = CountVectorizer(analyzer = "word", tokenizer = None, preprocessor = None, stop_words = None, max_features = 4000) train_data_features = vectorizer.fit_transform(clean_train_tweets) train_data_features = train_data_features.toarray() print(train_data_features.shape)
(2000, 4000)
2000行で最大に設定した4000個の特徴量ができました。 これをランダムフォレストに学習させます。正解ラベルはtrain["name_int”]です。
from sklearn.ensemble import RandomForestClassifier forest = RandomForestClassifier(n_estimators = 100) forest = forest.fit(train_data_features, train["name_int"])
何も起こらないので学習できたようです。 学習ができたところで、8月10日から12日の2日分の最新tweetを投げてみましょう(185件)。中身はidとtweetだけで、nameは外しています。
test = pd.read_csv("all_20180810_12.csv", header=0, delimiter=",") test
id tweet 0 9876 握手会ありがとうございました??\n\nじゃんけん大会本戦出場です✨✌?️\nLovelyS... 1 9877 本線いっくよぉ〜✨✨\n\nSugarが勝ってくれたのぉ!???\n\nLovelyとSug...
あとは同じように、特徴量を出して、forest.predict(test_data_features)とpredictするだけです。
num_reviews = len(test["tweet"]) clean_test_reviews = [] for i in range(0,num_reviews): clean_review = tweet_to_words( test["tweet"][i] ) clean_test_reviews.append( clean_review ) test_data_features = vectorizer.transform(clean_test_reviews) test_data_features = test_data_features.toarray() result = forest.predict(test_data_features) output = pd.DataFrame( data={"id":test["id"], "name":result} ) output.to_csv( "fukuoka.csv", index=False)
このようなcsvができました。
id,name 9876,0 9877,0 9878,0 9879,0 9882,0 9883,0 9884,0 9888,0 9889,0 9890,0 9891,0 9892,0 9894,0 9900,0 9901,0 (以下、略)
これをずっと見ていくと、1つだけ1(正解)があります。その中身を見てみます。
握手会ありがとうございました。 、、、、、元気です? #きょうのせいちゃん https://t.co/Z68vsoSjxs
きた、福岡聖菜のtweeetです。きょうのせいちゃん というのがありますので、わかりやすかったのかもしれませんね。下記の2つは0(福岡聖菜ではない)と判別されていました。
きぃちゃんお誕生日おめでとう✨ AKB最年少と言ってたのが 遥か彼方の18歳にお互いなったね笑 長女らしい優しさとまだまだ子供な部分 1つ1つが愛おしいです。 ステージのキラキラアイドル、 バラエティの天然のおもしろさ きぃちゃん… https://t.co/Y3dp0vfFHZ "まけたぁぁぁぁ??? #AKBじゃんけん https://t.co/pnzYUkU0vP"
2番目のはどうやっても判定できなさそうですが、色々パラメータをいじったらもしかしたら正解できるかもしれません。ちょっと楽しみです。
今日の結果
今日のAKBメンバーによる呟きは95件でした。 3日間続いた握手会は今日で最後だったようです。
'嬉しい': 11, '楽しい': 8, '可愛い': 8, '珍しい': 5, '正しい': 4, 'っぽい': 4, 'よろしい': 3, '弱い': 3, 'いい': 3, 'ない': 2, '無い': 2, '早い': 2, '五月蝿い': 2, 'よい': 2, '良い': 1, '遠い': 1, '辛い': 1, '眩しい': 1, '切ない': 1, '美しい': 1, 'うれしい': 1, '悔しい': 1, '優しい': 1, 'おしい': 1, 'おもしろい': 1, 'つらい': 1, 'もどかしい': 1}) 'アクシュカイ': 57, '部': 40, '今日': 36, '会': 25, '浴衣': 24, '写真': 24, '大会': 23, '日': 19, '明日': 16, '本戦': 15, 'ちゃん': 15, 'レーン': 15, 'ん': 14, '応援': 13, '皆さん': 12, '嬉しい': 11, 'さん': 11, '当日': 11, '券': 11, '目': 11, '人': 11, 'お願い': 10, '笑': 10, '動画': 10, 'ステージ': 10, 'こと': 9, 'アクシュカイ': 57, 'する': 51, '部': 40, 'ける': 40, '今日': 36, '会': 25, '浴衣': 24, '写真': 24, '大会': 23, '日': 19, '来る': 17, '明日': 16, 'くださる': 16, '本戦': 15, 'ちゃん': 15, 'レーン': 15, 'ん': 14,