Edited at

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

More than 1 year has passed since last update.

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