Python
Twitter
GoogleMapsAPI
機械学習
データサイエンス

感情予測したツイートをGoogle Mapにプロット

Ekmanの6感情を分類する文字ベースCNNモデルを作成しましたが、それを用いてGoogle Mapにプロットする方法を紹介します。

プロットされるもの

見たほうが早いので、以下にプロット後の画像を貼ります。(動画はこちら)

ズームする前
Screenshot_2018-09-08_15-29-43.png

ズームした後
Screenshot_2018-09-08_15-30-16.png

日付バーの日付を変更した後
Screenshot_2018-09-08_15-30-39.png

機能

ざっくりと機能を説明すると以下です。

  • マーカークラスタを使ってズーム位置に合わせた感情データクラスタをプロット。
  • ズームすればリアルタイムにクラスタを更新。
  • 日付バーを動かせばリアルタイムに各日付ごとのデータをプロット。
  • 各地理的位置における各感情のツイート数をプロット。

jupyter notebookで実行

収集済みのツイートデータの読み込みをします。データはTwitterのStandard Search APIを使って、特定の語のツイートを数件ごとに分けて保存したものです。

import json
data = None
datanum = 1453
for i in range(datanum):
    with open("tweets/data_{}.json".format(i)) as f:
        if data is None:
            data = json.load(f)
        else:
            data['statuses'] += json.load(f)['statuses']

こちらに、地名と座標を対応させた辞書があるので、これを読み込み、さらにデータを整形します。

import pickle
with open("pref_dict.pkl", "rb") as f:
    pref_dict = pickle.load(f)

with open("city_dict.pkl", "rb") as f:
    city_dict = pickle.load(f)

import re
import pandas as pd
import math
regex = r"[都道府県\,市町村群 ]"

def geocode(location, regex, city_dict, pref_dict):
    ds = re.split(regex, location)
    for d in ds:
        d = d.lower().strip()
        if d in city_dict:
            t = city_dict[d]
            if math.isnan(float(t[0])) or math.isnan(float(t[1])):
                continue
            else:
                return t

    for d in ds:
        d = d.lower().strip()
        if d in pref_dict:
            t = pref_dict[d]
            if math.isnan(float(t[0])) or math.isnan(float(t[1])):
                continue
            else:
                return t
    return False

def format_data(statuses):
    results = []
    for status in statuses:
        try:
            coordinates = geocode(status['user']['location'], regex, city_dict, pref_dict)
            if coordinates:
                results.append({
                    'user':status['user']['screen_name'], 
                    'text':status['full_text'], 
                    'coordinates': coordinates,
                    'date': status['created_at']
                })
            else:
                continue
        except Exception as e:
            print(e)
            break
    return pd.DataFrame(results)

df = format_data(data['statuses'])

以前、訓練したこちらのモデルを使って、モデルを読み込み、感情予測します。ついでに、日付関連の前処理を行います。

import pandas as pd
import numpy as np
from keras.models import load_model
from keras.preprocessing.sequence import pad_sequences
import pickle

emotions = ["happy", "sad", "disgust", "angry", "fear", "surprise"]
colors = ["orange", "blue", "green", "red", "gray", "purple"]

model = load_model("models/ja_tweets_sentiment/model_2018-08-28-15:00.h5")

with open("models/ja_tweets_sentiment/tokenizer_cnn_ja.pkl", "rb") as f:
    tokenizer = pickle.load(f)

def preprocess(data, tokenizer, maxlen=280):
    return(pad_sequences(tokenizer.texts_to_sequences(data), maxlen=maxlen))

preds = model.predict(preprocess(df['text'].tolist(), tokenizer))
strength = list(map(max, preds))
df['strength'] = strength
preds = np.argmax(preds, axis=1)
df['emotion'] = preds

df = df.dropna()
df.date = pd.to_datetime(df.date)
df["date_day"] = list(map(lambda x: str(x).split()[0], df.date))
df["date_hour"] = list(map(lambda x: str(x).split(":")[0], df.date))
df = df.sort_values(by="date", ascending=True)

とりあえず、ここまでのデータを保存しておきましょう。

df.to_csv("data.csv", index=False)
df.head()

Screenshot_2018-09-08_15-48-46.png

必要なデータを切り出します。

colors = ["orange", "blue", "green", "red", "gray", "purple"]
in_colors = []
in_coords = []
in_dates = []
in_infos = []
for i, d in df.iterrows():
    in_colors.append(colors[int(d['emotion'])])
    in_coords.append(make_tuple(d['coordinates']))
    in_dates.append(d['date_day'])
    in_infos.append(d['text'])

私が作成したこちらのモジュールをインポートして、プロットします。

import mapgen
center = (38, 137)
mapgen.plot_3("test_map_ver6.html", center, in_coords, in_colors, in_dates, in_infos)

htmlの出力は、以下の7z圧縮したファイルにまとめてあります。
https://github.com/sugiyamath/credibility_analysis/blob/master/notebook/sentiment_analysis/htmlfiles.7z