7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ProphetとTwitterで人生を振り返る

Last updated at Posted at 2022-08-17

全Tweetで振り返る

Tweet数で時系列分析

自分の何かを反映している気がしたので、Tweet数の変化について時系列分析してみます

  • 時系列データの可視化
  • (全体/年次/月次/日次)トレンドの可視化
  • 変化点検知ロジックによる変化点の検出

を、Prophetに投げつけて分析します。

参考文献: こちらのブログ

データの準備 - Twitterからのデータ取得

Twitter公式からツイートを取得しようとしたら時間がかかったので、
Twilogから取得してみます。
csvで取得するとツイート内の改行の扱いが手間だったので、xmlで取得してみました。

ライブラリの準備 - XMLの処理用

xmlの処理に必要なライブラリをインポートします。

import pandas as pd
! pip install xmljson
import xmljson
from lxml import etree

データのインポート

Colaboratoryで実行していますので、GoogleDriveにxmlファイルを置いて、マウントして読み込みます。

xml_tree = etree.parse('/content/drive/MyDrive/works/gg_hatano220206.xml')

# すべてのタグの取得
xml_root = xml_tree.getroot()
# xmlデータをdict型に変換
xml_dict = xmljson.yahoo.data(xml_root)

データの整形

xml > tweets > tweet > time に投稿時刻が入っていたので、取得します。
先頭に"20"をつけるとYYYYmmddになるっぽいので、この時点で整形しておきます。

from datetime import datetime as dt
tweet_time_list = []

for d in xml_dict['tweets']['tweet']:
  tmp = '20' + d['time']

  tmp = dt.strptime(tmp, '%Y%m%d %H%M%S')
  tweet_time_list.append(tmp)

時間順に並べて番号を付与することで、Tweet数の変化を見ます。

dat = pd.DataFrame({'time' : tweet_time_list})
dat = dat.sort_values('time', ascending=True).reset_index(drop = True)
dat = dat.assign(tweet_num=range(len(dat)))
dat['tweet_num'] = dat['tweet_num'] + 1
dat.head(5)
time tweet_num
0 2011-11-12 21:35:08 1
1 2011-11-12 21:43:03 2
2 2011-11-13 10:04:13 3
3 2011-11-13 11:09:01 4
4 2011-11-13 11:33:26 5

39393 rows × 2 columns

できました。

投稿数推移の可視化

投稿数の伸びを、とりあえず可視化しておきます。

import pandas as pd
import matplotlib.pyplot as plt

x = dat["time"]
y = dat["tweet_num"]

plt.plot(x,y)

e8f41dff8748ca2474474af301bf8d165329b15e.png

何回か傾きが変わっていそうです。

この辺りで人生の変化が起きていそうです。

ライブラリの準備 - Prophetによる時系列データ分析

トレンド分析や変化点検知をするために、Prophetを使ってみます。

! pip install fbprophet
from fbprophet import Prophet

学習

Prophetのモデル式は、トレンド$g_t$、季節$s_t$、イベント$h_t$、誤差$\epsilon_t $として、

$$
y_t =g_t + s_t + h_t + \epsilon_t
$$

という形のようです。参考

とりあえず学習させてみましょう。このmodel.fitには時間がかかります。(Colabで5分くらいかかった)
change_point_rangeは、学習に使うデータの割合(古いものからXX%を学習に使う)みたいです。
今回は予測する必要はないので、100%で学習します。n_changepointsは想定される変化点の個数?です。適当に10にしました。

dat = dat.rename(columns={'time':'ds', 'tweet_num':'y'})
model = Prophet(n_changepoints = 10, changepoint_range=1.0, growth='linear')
model.add_seasonality(name='monthly', period=30.5, fourier_order=5)
model.fit(dat)

トレンドの可視化

変化の様子を可視化してみます。周期性を出してくれるみたいです。便利ですね。

future = model.make_future_dataframe(periods=90)
forecast = model.predict(future)
model.plot_components(forecast)
plt.show()

15eae9e7380bfcb80495c7b95ceef856b47d1309.png

それぞれ眺めてみると...

  • trend
    • 2013年04月くらいの鈍化は、修士の研究室配属。
    • 2015年10月くらいの鈍化は、新入社員研修後の配属かな。
    • 2018年の立ち上がりは...フラれた時期かなあ...
  • weekly
    • 月曜夜に投稿数が少ないのは、多分野球の試合がないから、だと思います
  • yearly
    • 3月、5月、8月に静か(休み?)
    • 11月に元気(CSと日本シリーズ?)
  • daily
    • 25時くらいにピークがありそう
      • オールナイトニッポンかな
  • monthly
    • 20日くらいに黙るのは...給料日?

学生時代(-2015/03)と、社会人時代(2015/04-)とは分けた方がいいかもですね。
休みの取り方が違うので。

変化点検知

とりあえず現状のままやってみます。

import seaborn as sns

df_input = dat
# add change rates to changepoints
df_changepoints = df_input.loc[model.changepoints.index]
df_changepoints['delta'] = model.params['delta'].ravel()

# get changepoints
df_changepoints['ds'] = df_changepoints['ds'].astype(str)
df_changepoints['delta'] = df_changepoints['delta'].round(2)
df_selection = df_changepoints[df_changepoints['delta'] != 0]
date_changepoints = df_selection['ds'].astype('datetime64[ns]').reset_index(drop=True)

# plot
sns.set(style='whitegrid')
ax = sns.factorplot(x='ds', y='delta', data=df_changepoints, kind='bar', color='royalblue', size=4, aspect=2)
ax.set_xticklabels(rotation=90)

33f824251284402eb3106f7d53fa5298abde99e1.png

うーん...?変化が大きな日付をピックアップして、その日に何があったかを調べてみます。

  • 2012-06-17 : (増加) 院試の勉強中ですかね
  • 2013-05-15 : (減少) M1のGW明けに何があったのだろう -> ぼっち飯していました 悲しい
  • 2015-09-18 : (減少) 新人研修がまだ終わっていません 何の日だろう 

トレンドを眺めていた時の方が、直感と合った知見が得られた気がします。

社会人になってからのTweetで振り返る

昔のことを覚えていないので、社会の闇に揉まれている期間のデータに絞ってみます。2015年4月からです。

dat_work = dat[dat['ds'] > dt.strptime("20150401 000000", '%Y%m%d %H%M%S')]
dat_work = dat_work.reset_index(drop=True)
dat_work.head()
ds y
0 2015-04-01 12:14:37 25999
1 2015-04-01 12:17:12 26000
2 2015-04-01 12:22:15 26001
3 2015-04-01 14:12:59 26002
4 2015-04-01 17:12:07 26003

学習

時間かかる

model_work = Prophet(changepoint_range=1.0, growth='linear')
model_work.add_seasonality(name='monthly', period=30.5, fourier_order=5)
model_work.fit(dat_work)

はい

トレンドの可視化

見ましょう

future_work = model_work.make_future_dataframe(periods=90)
forecast_work = model_work.predict(future_work)
model_work.plot_components(forecast_work)
plt.show()

fd348a06e72a3356453b03b761cf3dcb841c50e4.png

さっきと雰囲気が違いますね。

  • trend
    • 2016年6月くらいの鈍化...あの案件ですね
    • 2017年3月くらいの鈍化...あの案件ですね
    • 2018年6月くらいの立ち上がり...はい
    • 2019年4月くらいの鈍化...あの案件
    • 2020年5月くらいの鈍化...あの案件
  • weekly
    • 月曜夜に投稿が増えています。
      • 巨人をあまり見なくなって、野球の影響が減っていそうです。
  • yearly
    • 5,6月に底をついて、11月がピーク
    • 毎年10月末の学会の時は、投稿伸びますね 出張中だからかな 楽しいのでしょうね
  • daily
    • 25時くらいにピークがありそう オールナイトニッポンかな
  • monthly
    • 20日くらいに黙るのは...給料日?なぜだろ

まとめ

  • 1人でうどんを食べた日からツイート頻度が減った
  • 案件が始まるとツイート頻度が減る
  • 給料日付近で黙る
  • 明示的なライフイベントを変化点として入力する案もある
7
3
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
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?