「停電」に関するツイートをpythonで収集して、WordCloudで可視化してみた

Twitterデータを使って、何か面白いことができないか調べていきたいと思います。
今回は、Twitterデータの収集・分析方法について情報をまとめ、
先日の関西地方での台風による「停電」、北海道での地震による「停電」に関するツイートを簡単に収集・分析してみました。

※この記事は2018/09/15に執筆しました。関西地方に大型台風が上陸したのは9/4、北海道の胆振地方で震度7の地震が発生したのは9/6です。

# Twitterデータって、どうやったら収集できるの？

時代により変わりそうですが、2018年9月時点現在では、参考[1]～[5]のサイトの情報が役に立ちます。
以下の流れで収集することができます。

1. 開発者用のTwitterアカウントを登録する（参考[1]）
 - 通常のTwitterアカウントを利用することができる
 - 登録に際しては、英語で簡単な説明を記入する必要あり（特別な用意は不要）  
2. Twitter APIに利用者登録する（参考[2]）
 - かなりザルなので、適当に記入でOK
3. API利用のためのアクセスキー・トークンを取得（参考[2]）
 - 指示に従えば簡単にできる
4. Twitter REST APIsで、データを収集する（参考[3]～[5]）
 - Twitter REST APIsは、Twitter上でのツイートの検索が可能なAPI
     - 日本語で書かれている仕様は、参考[3] 
 - タダで利用できるが制限がある。基本的にお試し用
     - 一部のツイートのみが検索対象
     - 直近1週間程度のツイートのみ検索可能
     - リクエスト回数に制限がある（450回/15分。しかも1回に100ツイートまでしか取得できない！）
 - pythonからTwitter REST APIsを呼ぶ場合は、requests-oauthlibライブラリが便利
     - 参考[4]～[5] の実装例が参考となる

以降で早速Twitterデータを収集してみたいと思います。

# 「停電」に関するツイートを収集する

2018年9月15日現在、旬なワードで、ツイートを収集したいと思います。
2018年9月は、関西地方への大型の台風の上陸、北海道胆振地方での震度7の地震、と大きな天災に見舞われた月でした。また、それらの天災により2つの地方で大規模な「停電」が発生しました。
そこで、今回は「停電」というキーワードに絞って、ツイートを収集してみることにしました。

まずは、ライブラリの読み込みなど、ツイート収集の準備です。
Twitter REST APIsの出力は、json形式であるため、jsonライブラリを使います。
また、pythonからREST APIsを簡単に呼び出せるように、requests_oauthlibライブラリを使います。

```python
# Twitterデータ収集用のログインキーの情報
KEYS = { # 自分のアカウントで入手したキーを記載
        'consumer_key':'*********************',
        'consumer_secret':'*********************',
        'access_token':'*********************',
        'access_secret':'*********************',
       }

# Twitterデータの収集（収集準備）
import json
from requests_oauthlib import OAuth1Session
twitter = OAuth1Session(KEYS['consumer_key'],KEYS['consumer_secret'],KEYS['access_token'],KEYS['access_secret'])
```

ツイート収集用の関数は、以下のように書きました。
keyword（検索したい語）、latitude（ツイート場所の緯度）、longitude（ツイート場所の経度）、radius（latitude、longitudeを中心とした検索対象範囲）を引数としています。
1回あたり最大100ツイートしか検索できないため、for文で複数回リクエストしてます。

```python

# Twitterデータ取得関数
def getTwitterData(key_word, latitude, longitude, radius, repeat=10):
    
    url = "https://api.twitter.com/1.1/search/tweets.json"
    params ={'q': key_word, 'count':'100', 'geocode':'%s,%s,%skm' % (latitude, longitude, radius), 'result_type':'recent'} #取得パラメータ
    tweets = []

    mid = -1

    for i in range(repeat):
        params['max_id'] = mid # midよりも古いIDのツイートのみを取得する
        res = twitter.get(url, params = params)
        if res.status_code == 200: #正常通信出来た場合

            sub_tweets = json.loads(res.text)['statuses'] #レスポンスからツイート情報を取得

            user_ids = []
            for tweet in sub_tweets:
                user_ids.append(int(tweet['id']))
                tweets.append(tweet)
            
            # ループで取得したmidよりも古いツイートを取るための工夫（※もっと良い書き方ありそう）
            if len(user_ids) > 0:
                min_user_id = min(user_ids)
                mid = min_user_id - 1
            else:
                mid = -1
            print(mid) # 時系列で見た時に最も古いツイートID
            
        else: #正常通信出来なかった場合(2018/9/24に修正しました)
            print("Failed: %d" % res.status_code)
    
    print("ツイート取得数：%s" % len(tweets))
    return tweets
```

この関数を用いて、北海道胆振地震の震源地となった厚真町近辺での「停電」という語を含むツイートを収集してみます。

```python
# 参考[6]で作成されていた関数を拝借しました
import time, calendar
def YmdHMS(created_at):
    time_utc = time.strptime(created_at, '%a %b %d %H:%M:%S +0000 %Y')
    unix_time = calendar.timegm(time_utc)
    time_local = time.localtime(unix_time)  # 2018/9/24に修正しました
    return time.strftime("%Y/%m/%d %H:%M:%S", time_local)


# Twitterデータの収集（「停電」を含む、厚真町付近半径20km、2018/9/7～2018/9/15）
# 厚真町付近の停電に関連するツイートを取得
tweets_atsuma = getTwitterData("停電", 42.7304715, 141.8155423, 20, repeat=10)
for tweet in tweets_atsuma:
    print(YmdHMS(tweet["created_at"]))
    print(tweet["text"] + "\n")
```
出力：
1038073748983709696
1037945395739910145
1037869698870726655
1037774249295900671
1037707169267765248
1037694413487525887
1037682907790233599
1037673160626163711
1037667915925876735
-1
Failed: 200
ツイート取得数：126

2018/09/15 03:18:49
けっぱれった北海道！
油断できないし、これからも節電は大事だけど、ひとまず計画停電回避できたようですYO！
\#ケッパレ北海道 https://（リンク）

2018/09/15 02:05:16
北海道電力の経営コンセプトは、2011年以降一貫して電力を核エネルギーである泊発電所の稼働することに傾注している。泊を稼働させずに収益をあげる経営方針をわたしは、北海道電力の札幌説明会で、尋ねたが北海道電力は、丁寧な説明を拒んだ。そして今回の大規模停電事故が発生。

2018/09/13 23:56:38
北海道内、主要病院の自家発電切替記録タイムスタンプから道内の地域別停電開始時刻が判明。道内全域のブラックアウトを招いた停電。2段階で実施。泊発電所の隣の岩内の病院の時刻から不良債権である泊の使用済核燃料を守る姿勢が鮮明。岩内協会病… https://（リンク）

:
(中略)
:

2018/09/07 06:22:37
停電なおらない 部屋真っ暗
星が綺麗だなァ〜
曇ってるけど。

2018/09/07 06:05:35
そして私は暗黒の世界に帰るぜ！要は停電してる家に帰るだけ

2018/09/07 05:44:44
@(ユーザ名) 実家は停電が続いており携帯も使えません。ほんとに真っ暗で怖いしコンビニも何も売ってません。とりあえず職場の病院で携帯使ってます…アレさんの家族はご無事ですか？

***

とりあえず収集できましたが、countパラメータに100を指定しても100件取得できないなど、仕様に一部謎な箇所が残りました。時間のある時に理由を調べていきたいと思います。

# 北海道、大阪、東京の「停電」ツイートを比較してみるよ

北海道（厚真町周辺）、大阪（大阪南部）、東京の3つの地域の「停電」に関するツイートを比較してみたいと思います。
先程説明した方法で、大阪南部（関西国際空港を中心に半径20km）、東京（皇居を中心に半径20km）の「停電」を含むツイートを収集しました。収集期間は、全て9/7～9/15の9日間です。
収集したツイートは形態素解析にかけ、頻出する単語をWordCloudで可視化することで比較したいと思います。
ちなみに、形態素解析ではjanomeを利用します。Mecab, Chasenなどの有名な形態素解析器と比較して、「pip install janome」で手軽にインストールできる点がメリットです。（コンパイル面倒くさいよ）

以下のような関数を定義して、janomeで形態素解析して、単語の出現頻度をカウントしました。

```python
# 文章を形態素解析して、Bag of Wordsに変換する
from janome.tokenizer import Tokenizer
import collections

# ツイートに含まれる単語をカウントして辞書化
def CountWord(tweets):
    tweet_list = [tweet["text"] for tweet in tweets]
    all_tweet = "\n".join(tweet_list)

    t = Tokenizer()
    c = collections.Counter(token.base_form for token in t.tokenize(all_tweet) 
                            if token.part_of_speech.startswith('名詞') and len(token.base_form) > 1) # 原形に変形、名詞のみ、1文字を除去

    freq_dict = {}
    mc = c.most_common()
    for elem in mc:
        print("%s\t\t %s" % (elem[0],elem[1]))
        freq_dict[elem[0]] = elem[1]
        
    return freq_dict
```
また、以下のような関数を定義して、WordCloudで可視化できるようにしました。

```python
# Word Cloudで可視化、WordCloud可視化関数
from wordcloud import WordCloud
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
from matplotlib.font_manager import FontProperties
fp = FontProperties(fname=r'C:\WINDOWS\Fonts\meiryo.ttc', size=50) #日本語対応

def DrawWordCloud(word_freq_dict, fig_title):

    wordcloud = WordCloud(background_color='white', min_font_size=15, font_path='C:\WINDOWS\Fonts\meiryo.ttc',
                          max_font_size=200, width=1000, height=500)    
    wordcloud.generate_from_frequencies(word_freq_dict)
    plt.figure(figsize=[20,20])
    plt.title(fig_title, fontproperties=fp)
    plt.imshow(wordcloud,interpolation='bilinear')
    plt.axis("off")
```

# 実際に、比較してみた

### 北海道

まずは、北海道（厚真町周辺）から。
ちなみにWordCloudでは、頻出の単語ほど、文字が大きく表示されます。

```python
atsuma_freq_dict = CountWord(tweets_atsuma)
DrawWordCloud(atsuma_freq_dict, "北海道の「停電」関連ツイート")
```
出力：
![北海道.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/caeef218-71c6-6aa0-7ec0-3bc6ca705f7f.png)
***

【結果解釈】

 - やはり北海道、苫小牧、胆振、厚真などの地震で被害の大きかった地名が目立ちます
 - 発電、節電、電気、電力、解消などの単語が多く、一刻も早く復旧してほしいという思いが感じられます
 - コンビニ、断水、充電、余震などの単語が多く、身の回りに大変な生活をしている人が多かったと想像されます

### 大阪

次いで、大阪（大阪南部）。

```python
osaka_freq_dict = CountWord(tweets_osaka)
DrawWordCloud(osaka_freq_dict, "大阪の「停電」関連ツイート")
```
出力：
![大阪.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/c902fab4-ccdf-f7c1-5a7f-5ed4a63118c3.png)
***

 - 北海道とは異なり、大阪、岸和田、和泉、貝塚などの台風で被害の大きかった地名が目立ちます
 - 関電という固有の会社名が目立ちます。関電にどうにか頑張って復旧してほしいという思いが感じられます
 - qoheyという単語は、岸和田市長の永野耕平さん（@qohey4251）のツイートが影響しています。今回の大阪での停電で尽力されたことが窺えます

### 東京

最後に東京です。

```python
tokyo_freq_dict = CountWord(tweets_tokyo)
DrawWordCloud(tokyo_freq_dict, "東京の「停電」関連ツイート")
```
出力：
![東京.PNG](https://qiita-image-store.s3.amazonaws.com/0/254780/f9628061-2b22-00ed-a6f7-23d5e5aeb52a.png)

***

 - 北海道地震関連の地名が多く、台風での停電被害と比較すると、地震での停電被害に関心が強いことが窺えます
 - 原発、稼働、火力、電源、発電などの単語が多く、直近の停電復旧よりも、日本のエネルギー問題そのものを考えるようなツイートが多いことが推測されます
 - デマ、マスコミ、政府、記者などの報道関連の単語も多く、震災発生時の情報伝達の在り方を気にするツイートも多いことが推測されます

# まとめと今後

簡単な分析でしたが、「停電」に関する、地域ごとの問題意識の違いが表れているのではないかと思います。
高度な分析に取り組もうとすると、REST APIs で収集できる範囲では不足かもしれませんが、
旬なワードに関する地域毎での意識の違いを見るのには結構使えそうな感触でした。

Twitterデータの他の活用方法についても探っていこうと思います。

次回：
「「クッパ姫」に関するツイートをpythonで収集して、バースト検出してみた」
https://qiita.com/pocket_kyoto/items/de4b512b8212e53bbba3



# 参考

[1]
【第1回】Twitter APIを使うためにdeveloper accountの申請をしよう！
https://masatoshihanai.com/php-twitter-bot-01/#twitter-api
[2]
【2018年】TwitterのAPIに登録し、アクセスキー・トークンを取得する具体的な方法
https://momokogumi.com/twitter-api
[3]
Twitter 開発者 ドキュメント日本語訳
http://westplain.sakuraweb.com/translate/twitter/Documentation/REST-APIs/Public-API/GET-search-tweets.cgi
[4]
スタバのTwitterデータをpythonで大量に取得し、データ分析を試みる その１
https://qiita.com/kenmatsu4/items/23768cbe32fe381d54a2
[5]
PythonでTwitter API を利用していろいろ遊んでみる
https://qiita.com/bakira/items/00743d10ec42993f85eb
[6]
Streaming APIで取得したつぶやきの処理方法
http://blog.unfindable.net/archives/4302