はじめに
Twitterのつぶやきを統計的に分析してみる その3。
前々回、前回と、Twitterのつぶやきの統計的処理とその可視化を行ってきました。
今回は、それを一歩進めて、機械学習によるつぶやき内容の評価を行ってみます。
今回、目指すのは、麺活er(麺を食すことが人生の大きなウェイトを占める方々)を
自負している、yutokiku氏のアカウントを分析対象にして、
麺活erからラーメンを引くと、何が残るのか?
を明らかにすることです、
前提
Twitterのつぶやきを感情分析してみるシリーズ
第1弾と第2弾での処理が完了し、
以下の前処理が完了した分析用のデータが手元にあること。
- クレンジング(正規化)
- 形態素解析
- 品詞フィルタリング
- ストップワード除去
繰り返しになりますが、公開されている(鍵付きではない)アカウント
とはいえど、
自分のつぶやきだけじゃないので、データそのものの公開は控えることにします。
統計処理と可視化の内容(予定)
今回は、以下のような分析と可視化を行ってみることにします。
- よく使用される単語ヒストグラム(前々回)
- word cloud(前回)
- 単語間の類似度 <- 今回
- 例えば、
ラーメンと近い意味で使用されている単語
は何か?を計算することができます。 - 例えば、@yutokiku氏のつぶやきから、
ラーメンを引くと何が残るか
計算することができます。
- 例えば、
- アカウント間のつぶやき内容の類似度(次回?)
可視化してみる
分析対象は、筆者が興味のある、個人的に知ってるアカウント
となります。
ので、一部の人たちは面白いかもしれないが、そうでない人は、かなりつまらないと思う
。
1. よく使用される単語ヒストグラム
前々回の記事を参照してください。
2. wordcloud
前回の記事を参照してください。
3. 単語間の類似度
単語と単語の類似度を、どうやって評価するかは、世の中にはいろいろと方法があります。
そういう細かい話は飛ばして、ここではデファクトスタンダードな方法である、Doc2Vecを使います。
3.1 単語(言語)の定量的表現
Doc2Vecを使うことで、文章内で似たような文脈で使用されている単語を判断することができます。
その過程で、単語をベクトル表現しているため、ベクトル演算することができます。
その結果、
王様 - 男性 + 女性 = ??
というような計算ができるようになります。
もちろん、この計算の結果は、女王
になります。
機械学習で、単語のニュアンスまで学習させたうえで、その演算もできてしまうのはすごいですね。
3.2 単語(言語)の学習
以下に、pythonでgensimパッケージを使い、doc2vecで学習させる部分のコードを示します。
from gensim import models
sentences = []
for key, doc in data.iterrows():
if not isinstance(doc["tweet"],str) or len(doc["tweet"])<1:
continue
words= doc["tweet"]
twt = words.split(" ")
line = models.doc2vec.LabeledSentence(twt, tags=[doc["user"]])
sentences.append(line)
num_epochs = 20
num_ittr = 200
vecsize = 400
alpha = 0.050
min_alpha = 0.005
# doc2vec の学習条件設定
# alpha: 学習率 高いほど収束が速いが、高すぎると発散する。低いほど精度が高いが、収束が遅くなる。
# min_count: X回未満しか出てこない単語は無視
# size: ベクトルの次元数 / iter: 反復回数 / workers: 並列実行数
model = models.Doc2Vec(min_count=3, workers=16, window=4, iter=num_ittr, size=vecsize)
# doc2vec の学習前準備(単語リスト構築)
model.build_vocab(sentences)
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
# doc2vec学習実行
#model.train(sentences, start_alpha=alpha, end_alpha=min_alpha, total_examples=len(data), epochs=num_epochs)
alpha_delta = (alpha - min_alpha) / num_epochs
from random import shuffle
for epoch in range(num_epochs):
shuffle(sentences)
model.alpha = alpha
model.min_alpha = alpha
model.train(sentences, total_examples=len(data), epochs=num_epochs)
model.save("{}".format(args.output))
alpha -= alpha_delta
print("epoch {}/{} is finished".format(epoch+1,num_epochs))
これで、Twitterのつぶやきの文書コーパスから、隠れ層が1層、計3層のNeural Networkを使った
Deep Learningで、文章のベクトル化ができます。
なお、この学習にはベクトルをランダムに初期化するようで(仕組みはよくわかっていない)、
同じ学習パラメタと教師データを使ったとしても、学習させるたびに結果が異なる
ことに留意してください。
3.3 単語(言語)間の類似度の計算
それでは、計算した学習モデルを使い、演算をさせてみたいと思います。
3.3.1 よくつぶやく単語の振り返り
yutokiku氏のつぶやきの、これまで可視化した結果を、改めて振り返ってみましょう。
Account | 開始日時(JST) | 終了日時(JST) | 件数 | 補足 |
---|---|---|---|---|
@yutokiku | 2015-10-14 13:50:20 | 2017-08-10 22:53:20 | 3,213件 | – |
ちなみに、一番古いつぶやきは
新しいOSをのせるには、ハードスペックも上げないといけないわけで、がんばれ30代!(笑)
でした。
つぶやきヒストグラム | つぶやきword cloud |
---|---|
ラーメン、目立ちますね。。。。
なお、word cloudの可視化の結果を見やすくするために、
あまり意味を持たなそうな単語については、フィルタリングして除外しています。
そのために、histogram とword cloudの内容をヨーク見比べると、あれ?と思うことがあるかもしれません。
でも、お気になさらずに!
この2つの可視化の結果から、yutokiku氏が、いかににラーメンという単語をつぶやいているか
、が
直感的にも定量的にも示すことができていますね。
この分析から、注目すべき単語は以下であることがわかります。
- 東京都
- ラーメン
- 神奈川県
- 行く
いい- 食べる
- 見る
- 麺
- 麺活
- 今日
よいいう- 渋谷区
この中でも よい とか いう という、その単語のままではちょっと内容を想像しずらいものを除外し、
分析して価値がありそうな単語を残して、次の分析に進みましょう。
3.3.2 単語間の類似度
いよいよ、類似度を見てみましょう。
yutokiku.model
というファイル名で学習モデルを保存していれば、
以下のようにして学習モデルを読み込めます。
name="yutokiku"
model = models.Doc2Vec.load("{}.doc2vec".format(name))
3.3.2.1 ラーメン と 麺活 の類似度
まず、yutokiku氏のつぶやき学習モデルで、ラーメン と 麺活 の類似度を計算してみます。
ymodel.similarity("ラーメン","麺活")
# 0.78987607725675235
うーん、特別、密接ではないようですね。
らぁ麺だったり拉麺だったりそばだったり、微妙な表記ゆれがあったりして、
必ずしも、麺活と一緒に使われる単語というわけではなさそうです。
ちなみに、boomin614の場合、類似度は 0.87978855218224716 でした。yutokiku氏より若干高いですね。
言われてみれば、そんな気もするような。
3.3.2.2 yutokiku氏の、単語間の関連度
それでは、yutokiku氏のつぶやきで、ラーメンがどういう単語と関連が強いのか見てみましょう。
- ラーメン
ymodel.most_similar(positive=['ラーメン'], topn=10)
単語 | 類似度 |
---|---|
ラーメン屋 | 0.9772789478302002 |
鍋 | 0.9741593599319458 |
合う | 0.9679932594299316 |
汁 | 0.9672616720199585 |
フクロウ | 0.9634534120559692 |
食べる | 0.9552503824234009 |
理想 | 0.9543302059173584 |
野菜 | 0.9528324007987976 |
贅沢 | 0.9499553442001343 |
味 | 0.9437661170959473 |
- 麺活
ymodel.most_similar(positive=['麺活'], topn=10)
単語 | 類似度 |
---|---|
本日 | 0.985655665397644 |
昼 | 0.979606568813324 |
東急東横線 | 0.9713839888572693 |
京急久里浜線 | 0.9685754776000977 |
中央線 | 0.9638262987136841 |
煮干し | 0.9596883058547974 |
鯵 | 0.9571654796600342 |
東海道線 | 0.9565385580062866 |
ビール | 0.956403374671936 |
北久里浜 | 0.9531933069229126) |
なるほどなるほど、確かにこれはフォロワーだったらyuyokiku氏のつぶやきを特徴づける
結果となっていることがよくわかりますね!
ちなみに、boomin614の場合は、以下の通りでした。
- ラーメン
bmodel.most_similar(positive=['ラーメン'], topn=10)
単語 | 類似度 |
---|---|
麺 | 0.9981880187988281 |
安定 | 0.9981077909469604 |
昼休み | 0.9978439807891846 |
熱い | 0.9972622394561768 |
うどん | 0.997221052646637 |
稼働 | 0.9967553019523621 |
周辺 | 0.9967378377914429 |
BY | 0.9961580038070679 |
通常 | 0.9958750009536743 |
キーワード | 0.9953306317329407 |
- 麺活
bmodel.most_similar(positive=['麺活'], topn=10)
単語 | 類似度 |
---|---|
監視 | 0.997142493724823 |
システム | 0.9968782663345337 |
あちこち | 0.9928720593452454 |
リアルタイム | 0.9834117889404297 |
いいね! | 0.9787250757217407 |
チェックイン | 0.9654333591461182 |
麵活 | 0.9524260759353638 |
ER | 0.9482050538063049 |
Hashtag | 0.9464929103851318 |
つぶやき | 0.94593745470047 |
ラーメンと麺活、どちらの場合も、全世界リアルタイム麺活監視システムで分析結果を呟いている内容が、
関連の高い単語として学習されているようです。
また 麺活er という言葉をよく使うのですが、辞書登録されていないので、er部分が切り離されたようですね。
3.3.3 いよいよ、麺活erからラーメンを引いてみる
3.3.3.1 yutokiku氏からラーメンを引いてみた
単語 | 類似度 |
---|---|
福井県 | 0.763325572013855 |
新潟県 | 0.7488822340965271 |
20人 | 0.7419391870498657 |
お気 | 0.7234288454055786 |
福島県 | 0.6961318254470825 |
納 | 0.6638048887252808 |
亀岡文殊 | 0.6636269092559814 |
アピール | 0.6521700620651245 |
秋田市 | 0.6138999462127686 |
監視 | 0.6055328845977783 |
ここでの類似度は、引いた結果として類似しているということです。
要は、対極にある言葉なので、より似ていない、と解釈してください。
- 福井県、新潟県、福島県
旅行で行ったのでしょうか。
旅行先で、「ラーメン」は呟いていないようですね。 20人
お店の待ち行列の長さを呟いたようです。
3.3.3.2 yutokiku氏から麺活を引いてみた
単語 | 類似度 |
---|---|
お気 | 0.8138871192932129 |
監視 | 0.8095569610595703 |
福井県 | 0.7570892572402954 |
20人 | 0.739549994468689 |
納 | 0.7112507820129395 |
未来館 | 0.7097063064575195 |
でかい | 0.6974242925643921 |
アピール | 0.6721981763839722 |
誕生日 | 0.6529790163040161 |
福島県 | 0.5813616514205933 |
ここでの類似度は、引いた結果として類似しているということです。
要は、対極にある言葉なので、より似ていない、と解釈してください。
お気 は、分かち書き&基本形への変形などの過程で、気を付ける が分解された結果のようです。
この単語は麺活から遠くても仕方がないとして、監視
が遠い位置にあるとは。。。。
yutokiku氏、全世界リアルタイム麺活監視システムのアクセス権がありながら、
分析をだいぶサボっておられる
ということかもしれません。こらっ!笑
3.3.3.3 yutokiku氏のラーメンから麺活を引いてみた
単語 | 類似度 |
---|---|
由来 | 0.7321574687957764 |
調子 | 0.5533725023269653 |
広島 | 0.5327156782150269 |
当日 | 0.519767165184021 |
フクロウ | 0.4968743324279785 |
美味しい | 0.4750869870185852 |
つけまつげ | 0.474945992231369 |
餃子 | 0.45154258608818054 |
湯気 | 0.44765740633010864 |
られる | 0.41427338123321533 |
コメントしづらい。。。。ご本人からの意見を待つことにしましょう。。。。
3.3.3.4 yutokiku氏の麺活からラーメンを引いてみた
単語 | 類似度 |
---|---|
新潟県 | 0.5728588104248047 |
満月 | 0.5422463417053223 |
日和 | 0.5412570238113403 |
フェリーターミナル | 0.5083515644073486 |
静岡県 | 0.46679234504699707 |
秩父市 | 0.4598701596260071 |
足下 | 0.44213247299194336 |
皇居 | 0.43109312653541565 |
きれいな | 0.41275203227996826 |
跡 | 0.401312917470932 |
コメントしづらい。。。。ご本人からの意見を待つことにしましょう。。。。
3.3.3.5 yutokiku氏の神奈川での麺活の様子
単語 | 類似度 |
---|---|
京急久里浜線 | 0.9863211512565613 |
東急東横線 | 0.9824132323265076 |
東海道線 | 0.9822019338607788 |
はまる | 0.981946587562561 |
北久里浜 | 0.9811553955078125 |
横須賀線 | 0.9807214736938477 |
中央線 | 0.9803013801574707 |
讃岐 | 0.9784263372421265 |
予想外 | 0.9779013395309448 |
本日 | 0.9760028123855591 |
出没エリアが一目瞭然
ですね・・・・・笑
まとめ
こうして、単語間の類似度を見てみると、単にword cloudで可視化するより、
その人を特徴づける言葉
を、浮かび上がらせることが出来るようになりました。
今回はyutokiku氏のつぶやき内容を中心に分析しましたが、
例えば新聞記事を分析したり、国会答弁を分析したりすると、
密接に使用される単語などが計算できるようになって、面白い発見があるかもしれません。
次回は、この類似度をさらにネットワーク図を使って可視化する
ことに取り組んでみたいと思います。
それでは。