LoginSignup
12
24

More than 5 years have passed since last update.

[Python]TwitterAPIとMeCabを使った形態素解析と可視化

Last updated at Posted at 2019-02-11

はじめに

仕事上フリーコメント分析する機会が沢山あります。一件一件目を通して、アフターコーディングみたいなことをしてもいいのですが、せっかく世の中色んなツールがあるので、便利にできたらなと思っています。

本記事は、いつも使っている分析動作を簡単な形式で記載していきます。成果物としてはこんな感じ。
スクリーンショット 2019-02-11 16.59.25.png
※Python/mecab/wordcloud/twitterAPIの導入の話はありません。

環境

macOS
Python3.7

情報収集

今回は、題材探すのも面倒なので、twtterAPIを利用して、情報収集を行なっていきます。

APIの利用方法は以下を参照にしてください。

Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ
Twitter APIでつぶやきを取得する
PythonでTwitter API を利用していろいろ遊んでみる

適当にデスクトップに以下のファイルを作成します。
内容としてタイムライン取得用のURLにアクセスして、パラメタでtwitterアカウントの名前やリプライ、リツイート等を指定して、OAuthで認証を行ないます。一方でAPI制限についてはターミナル上で表示を行うようにしています。

twpy.py
import requests
import json
from requests_oauthlib import OAuth1Session


access_token = 'hogehogehogehoge'
access_token_secret = 'hogehogehogehoge'
consumer_key = 'hogehogehogehoge'
consumer_key_secret = 'hogehogehogehoge'


url = "https://api.twitter.com/1.1/statuses/user_timeline.json"

params = {'screen_name':'@AbeShinzo',
          'exclude_replies':True,
          'include_rts':False,
          'count':200}

twitter = OAuth1Session(consumer_key, consumer_key_secret, access_token, access_token_secret)

res = twitter.get(url, params = params)

f_out = open('/Users/hoge/Desktop/abe.txt','w')

for j in range(100):
    res = twitter.get(url, params = params)

    if res.status_code == 200:


        limit = res.headers['x-rate-limit-remaining']
        print ("API制限の残り: " + limit)
        if limit == 1:
            sleep(60*15)

        n = 0
        timeline = json.loads(res.text)

        for i in range(len(timeline)):
            if i != len(timeline)-1:
                f_out.write(timeline[i]['text'] + '\n')
            else:
                f_out.write(timeline[i]['text'] + '\n')
                params['max_id'] = timeline[i]['id']-1

f_out.close()

ファイルを保存したら、ターミナル上でファイルを実行。
デスクトップ上にファイルができています。

$ python twitter1.py
API制限の残り: 898
API制限の残り: 897
API制限の残り: 896
API制限の残り: 895
API制限の残り: 894
API制限の残り: 893
API制限の残り: 892
API制限の残り: 891
API制限の残り: 890
API制限の残り: 889
API制限の残り: 888
API制限の残り: 887
API制限の残り: 886
API制限の残り: 885
API制限の残り: 884
API制限の残り: 883
API制限の残り: 882
API制限の残り: 881
API制限の残り: 880
API制限の残り: 879
API制限の残り: 878
API制限の残り: 877
API制限の残り: 876
API制限の残り: 875
・・・

整形

ここからは対話型インタプリタで作業をします。jupyternotebook利用しました。
必要なパッケージをimportします。※本記事では全部使いません。

import re
import MeCab
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib
import seaborn as sns
import wordcloud
from wordcloud import WordCloud,STOPWORDS
import json
import itertools
from collections import Counter
%matplotlib inline
sns.set()

ファイルを読み込みます。
ファイルパスを指定して、UTF-8の読み取りで、分割した形でsptextに代入します。
例えば、手元に分析したいファイルがあれば、ここで指定をしてください。エクセルだとS-JISでエンコーディングを指定するとできます。多分。

filename = "/Users/hoge/Desktop/abe.txt"
with open(filename, "r", encoding="utf-8") as afile:
            string = afile.read()
            sptext = whole_str.splitlines()

中身の確認。何が行われているかわかるように都度中身確認します。

print(sptext)

['本日、#ドイツ の#メルケル首相が来日し、安倍総理と首脳会談を行いました。その様子を動画にまとめましたので、是非ご覧ください。 https://t.co/DutVH8XjRl', '1月は行く。2月は逃げる。と祖母はよく言っていたものでしたが、もう2月。いよいよ予算委員会も始まります。', 'そこで一句。', '', '「鏡餅食べ終わる間に月が明け」 https://t.co/K3d479jttd', '今、海外では、キャッシュレス決済が急速に普及しています。外国人観光客4000万人時代に向けて、大胆な5%ポイント還元で、日本でもキャッシュレスを一気に拡大したいと思いま・・・

今はツイートごとの文字列のリストになっているので、全部くっつけます。

string = '\n'.join(sptext)
print(string)

'本日、#ドイツ の#メルケル首相が来日し、安倍総理と首脳会談を行いました。その様子を動画にまとめましたので、是非ご覧ください。 https://t.co/DutVH8XjRl\n1月は行く。2月は逃げる。と祖母はよく言っていたものでしたが、もう2月。いよいよ予算委員会も始まります。\nそこで一句。\n\n「鏡餅食べ終わる間に月が明け」 https://t.co/K3d479jttd\n今、海外では、キャッシュレス決済が急速に普及しています。外国人観・・・

さらに半角スペースを消しちゃいます。正規表現の置換です。
今回はtwitterのハッシュタグがあるので「#」も削除します。

string = re.sub(' ', '', string)
string = re.sub('#', '', string)
print(string)

'本日、ドイツ のメルケル首相が来日し、安倍総理と首脳会談を行いました。その様子を動画にまとめましたので、是非ご覧ください。 https://t.co/DutVH8XjRl\n1月は行く。2月は逃げる。と祖母はよく言っていたものでしたが、もう2月。いよいよ予算委員会も始まります。\nそこで一句。\n\n「鏡餅食べ終わる間に月が明け」 https://t.co/K3d479jttd\n今、海外では、キャッシュレス決済が急速に普及しています。外国人観光客4000万人時代に向・・・

文章の区切りで分割します。句読点や括弧、改行が出てきたら分割します。正規表現です。
いい感じになってきました。

string = re.split('。(?!」)|\n', string)
print(string)

['本日、ドイツ のメルケル首相が来日し、安倍総理と首脳会談を行いました',
 'その様子を動画にまとめましたので、是非ご覧ください',
 ' https://t.co/DutVH8XjRl',
 '1月は行く',
 '2月は逃げる',
 'と祖母はよく言っていたものでしたが、もう2月',
 'いよいよ予算委員会も始まります',
・・・

Twitter情報のためのURLが混ざっているので、URL要素は削除します。
正規表現で削除しました。他にも特定のワードを削除したければ、こちらこちらを参照に。

newstring = []
for st in string:
    words = re.sub(r'.*http.*', '', st)
    newstring.append(words)

print(newstring)

['本日、ドイツ のメルケル首相が来日し、安倍総理と首脳会談を行いました',
 'その様子を動画にまとめましたので、是非ご覧ください',
 '',
 '1月は行く',
 '2月は逃げる',
 'と祖母はよく言っていたものでしたが、もう2月',
 'いよいよ予算委員会も始まります',
 '',
 'そこで一句',
 '',
 '',
 '',
・・・

上記の通りですが、中身を見てみると、'',←このような空の行が出てきているので、まとめて削除します。

while '' in newstring:
   newstring.remove('') 

print(newstring)

['本日、ドイツ のメルケル首相が来日し、安倍総理と首脳会談を行いました',
 'その様子を動画にまとめましたので、是非ご覧ください',
 '1月は行く',
 '2月は逃げる',
 'と祖母はよく言っていたものでしたが、もう2月',
 'いよいよ予算委員会も始まります',
 'そこで一句',
 '今、海外では、キャッシュレス決済が急速に普及しています',
 '外国人観光客4000万人時代に向けて、大胆な5%ポイント還元で、日本でもキャッシュレスを一気に拡大したいと思います',
 '花屋さんでは、QR決済に挑戦しました',
 '初めてだったのでかなり緊張しましたが、本当に簡単でほっとしました',
 '海外のお客さんも来て使ったそうですが、QRコードの紙を一枚だけでいいので、花屋さんの方も簡単に導入できたとおっしゃってました',
・・・

形態素分解

ここまできたらお馴染みのMeCabを使います。
wakatiでもいいですが、このあと名詞のみを抽出するので、品詞がセットになっているchasenを使います。

m = MeCab.Tagger("-Ochasen")

ここから肝です。
内包表記で複雑になっていますが、chasenで形態素にしたものの中に名詞が含まれているものだけをさらにリストにしています。
ここまでくれば、数えることも簡単になります。

wordlists = [ \
    [v.split()[2] for v in m.parse(sentense).splitlines() \
       if (len(v.split())>=3 and v.split()[3][:2]=='名詞')] \
    for sentense in newstring]

print(wordlists)

[['本日', 'ドイツ', 'メルケル', '首相', '来日', '安倍', '総理', '首脳', '会談'],
 ['様子', '動画', '是非', 'ご覧'],
 ['1月'],
 ['2月'],
 ['祖母', 'もの', '2月'],
 ['予算', '委員', '会'],
 ['一句'],
 ['今', '海外', 'キャッシュ', 'レス', '決済', '急速', '普及'],
 ['外国',

今はリストの入れ子になっているので、これを結合して一つのリストにします。

wordlist = list(itertools.chain.from_iterable(wordlists))
print(wordlist)

['本日', 'ドイツ', 'メルケル', '首相', '来日', '安倍', '総理', '首脳', '会談', '様子', '動画', '是非', 'ご覧', '1月', '2月', '祖母', 'もの', '2月', '予算', '委員', '会', '一句', '今', '海外', 'キャッシュ', 'レス', '決済', '急速', '普及', '外国', '人', '観光', '客', '4000', '万', '人', '時代', '大胆', '5', '%', 

解析(とりあえず数える)

せっかくなのでカウントしておきます。上位100個。
話題がわかるかなと思ったら、そうでもない。。。共起関係とか見ないとダメそう。別で記事投稿します。

cnt = Counter(wordlist)
sorted(cnt.items(), key=lambda x: x[1],reverse=True)[:100]

[('安倍', 281),
 ('日本', 257),
 ('日', 245),
 ('三', 233),
 ('晋', 213),
 (':', 202),
 ('演説', 182),
 ('こと', 167),
 ('総裁', 164),
 ('会', 159),
 ('県', 151),
・・・

可視化の準備

続いて文字の可視化の準備をします。半角スペースで一つの文字列にします。
※このやり方は合ってるか知りませんが、昔可視化を試みた時に、英語は分割されて綺麗に表示されたのに、日本語だとできなかったことから、とりあえず半角スペースで区切ってみてます。

mojiretu = ' '.join(wordlist)
print(mojiretu)

'本日 ドイツ メルケル 首相 来日 安倍 総理 首脳 会談 様子 動画 是非 ご覧 1月 2月 祖母 もの 2月 予算 委員 会 一句 今 海外 キャッシュ レス 決済 急速 普及 外国 人 観光 客 4000 万 人 時代 大胆 5 % ポイント 還元 日本 キャッシュ レス 拡大 花屋 さん QR 決済 挑戦 緊張 簡単 海外 お客 さん そう QR コード 紙 一 枚 花屋 さん 方 簡単 導入 東京 戸越 銀座 商店 街 キャッシュ レス 決済 体験 最初 コンビニ プリペイドカード ん 店頭

可視化(wordcloud)

最後に可視化ですが、全然分析するには不便だけど、なんとなくかっこよく見えるwordcloudを利用します。これのためだけに全部を繋げた文字列にしました。

font指定/可視化させない言葉の指定/色や大きさの指定等をした上で、matplotlibでwordcloudを呼び出します。

#fpath = "/Library/Fonts/ヒラギノ丸ゴ ProN W4.ttc"
#もともと上記のFONTでやっていましたが、突然使えなくなりました
fpath = "./fonts/IPAexfont00301/ipaexg.ttf"
stop_words = [ u'もの',u'こと',u'安倍',u'今日',u'日本',u'昨日',u'私',u'総理',u'本日',u'さん']
wordcloud = WordCloud(background_color="white", width=900, height=500,max_font_size=40,stopwords=set(stop_words),font_path=fpath).generate(mojiretu)

plt.figure(figsize=(15,12))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

スクリーンショット 2019-02-11 16.59.25.png

ちなみに形容詞はこんな感じでした。

最大フォントサイズを少し調整しました。

スクリーンショット 2019-02-11 17.08.42.png

僕が愛読している日経ヴェリタス小栗さんのツイート可視化

無駄に黒背景にしました。

スクリーンショット 2019-02-11 17.29.39.png

終わり

12
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
24