Prophetを使って、30分でコウメ太夫の努力の結果をビジュアライズする。

私はコウメ太夫が比較的好きだ。

彼に遭った最初で最後の機会は、まだ私が小学生の頃。

ショッピングモールで"徒然なるままに書き散らしたコウメ日記"に興じる彼に出会った。

その時のネタは今でも覚えている。

「(チャンチャヵ チャン×2 チャチャンヵ チャン×2)×2

最近目が悪いので。 

コンタクトにしてみたら。 

自分の頭が禿げてる事を知りました。 チクショウ。」

子供ながらに思った。

「消え去る日は近い」と。

私の直感的予測は当たり、2年もしないまま彼は芸能界の表舞台から姿を消した。

そこから時は流れること十数年、Twitterで不死鳥の如く復活を遂げる彼を目撃した。

スクリーンショット 2019-06-22 16.00.36.png

彼は2016年3月、何を思ったかチクショーネタを毎日つぶやく、

"#まいにちチクショー"キャンペーンを始動させた。

最初のtweetのいいね数はわずか160台と、始まりは静かだったが、

時間が経つに連れて下記のようなフォロワーが増えていった。

【事例1:コウメ太夫のネタを評価する者と、その評価を評価する者】

スクリーンショット 2019-06-22 16.05.30.png

【事例2:コウメ太夫のネタをvisualizeする者】

スクリーンショット 2019-06-22 16.17.09.png

【事例3:コウメ太夫のネタを哲学的視点から解釈する者】

スクリーンショット 2019-06-22 16.13.42.png

このようなフォロワーの増加に比して、彼のツイートの人気(=いいね,RT)は上昇しているように感じる。

今では1万RT以上のネタもあるほどだ。

このようにコウメ太夫のネタを媒介として、様々なコンテンツが生まれ、それらが相互作用し合い全体の価値が向上していくネットワークは、プラットフォームの様相を呈していると言えるだろう。

このプラットフォームの全体像を図式化すると下記のようになると考える。

スクリーンショット 2019-06-23 1.59.23.png

(「プラットフォームの教科書」(根来龍之)を参考に作成)

そう。

もうお分かりの通り、2019年6月現在、コウメ太夫はGAFA(Google, Apple, Facebook, Amazon)顔負けのプラットフォームを構築し、"芸人@Twitter"界のプラットフォーマーとして君臨しつつあるのだ。

そして今回その証明を、Facebookが開発した"Prophet"という時系列解析ライブラリを用いて行いたいと思う。


目的とゴール

目的:コウメ太夫の人気が上昇傾向にあるという仮説を立証する。

ゴール:時系列解析ライブラリ"Prophet"を用いて、コウメ太夫のtweetに対するいいね数の時系列変化を出力し、右肩上がりに上昇していることを確認する。

サブミッション:コウメ太夫が次いつバズるかを予測できるか、検証する。


Prophetとは?

Facebookが開発した時系列予測ライブラリ。

特筆すべきは、時系列データのトレンドを把握できるだけでなく、トレンドの変化点の検出も出来ること。

しかも、めちゃくちゃ簡単に。

もちろん回帰タスクも可能。

重回帰やSVR等の線形/非線形回帰モデルとは異なり、基本的には説明変数を必要としない。

どちらかというとARIMA(SARIMA)モデルのように、時系列でみたときのデータの変動からトレンド曲線を導出するアルゴリズム。

Prophetでは予測線をスプライン曲線(与えられた任意の点の各点を滑らかに結ぶ曲線)として表現している。モデル式は下記。

スクリーンショット 2019-06-22 18.05.17.png

g(t)がトレンド成分、 s(t)が季節成分、 h(t)が祝日などのイレギュラーな効果成分、 εが誤差項となる。

(詳細は論文を確認願います。)


やりたいことの流れ

おおまかに

1. コウメ太夫の"#まいにちチクショー"タグを含む全ツイートそれぞれのいいね数およびtweet日付を取得、データフレーム化

2. いいね数の時系列変化をProphetを用いて分析

3. (サブ)学習期間&テスト期間に分割し、時系列予測の予測精度を検証

と言った感じ。


実行環境

Python 3.7(Anaconda3系)

macOS Mojave 10.14.1

Jupyter Notebook


実行


ライブラリのインポート

まず、必要なライブラリをインポートする。


koume_prophet.py

import tweepy

import re
import pandas as pd
import datetime as dt
from fbprophet import Prophet
import seaborn as sns
sns.set_style(style="ticks")

Prophet用のライブラリが未インストールの場合は、

ターミナルからpipでインストールする。

$ pip install fbprophet

Anacondaでインストールの場合は下記を実行。(こちらのほうがトラブルが少ない様子)

$ conda install -c conda-forge fbprophet

tweepy(Tweet情報取得用)のインストールは下記

$ pip install tweepy


tweet取得の準備

TwitterAPI経由でtweetデータを取得するためには、予めAPIキー、アクセストークンを取得する必要がある。


koume_prophet.py

# キーの設定

consumer_key = "XXXXXXXXXXXXXXXXXXXXXXXX"
consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXX"
access_token = "XXXXXXXXXXXXXXXXXXXXXXXX"
access_secret = "XXXXXXXXXXXXXXXXXXXXXXXX"

取得方法は下記のサイトを参考にすると良いかも。

https://qiita.com/yokoh9/items/760e432ebd39040d5a0f

次に、取得対象のユーザーを設定する。対象はもちろんコウメ。ついでに取得するtweet数もここで設定。


koume_prophet.py

## 取得対象の設定

# user_idの設定(”@〜”のユーザーIDをサイト(https://idtwi.com/)で数字に変換した後、こちらに代入)
USERid = "391900115"
# 取得したいツイート数の設定
numberOfTweets = 5000

APIキーを用いて、tweetデータを取得する準備をする。


koume_prophet.py

#ユーザーのtweetを取得

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)
api = tweepy.API(auth, wait_on_rate_limit = True)

wait_on_rate_limit = TrueはAPI制限回避のためのおまじない。(今回何度もAPIを叩くわけではないので、必要ないかも)


tweetデータの取得

カーソルオブジェクトを取得。tweepyのcursorを使うと、api.user_timeline メソッドなど 1 ページずつ結果を戻してくるメソッドのページネーションを考慮しなくても良くなるそう。


koume_prophet.py

aTimeLine = tweepy.Cursor(api.user_timeline,id=USERid).items(numberOfTweets)


numberOfTweetsは冒頭で設定した取得ツイート数。

続いて取得したオブジェクトから必要なデータを抽出&整形する。

取得するデータ対象は"#まいにちチクショー"タグが含まれる、コウメ太夫のtweet全て。


koume_prophet.py

t_txt = [] # Tweetのテキスト情報を格納(今回は不要)

t_num = [] # Tweetの日付、いいね数、RT数などを格納
cnt = 1
for tweet in aTimeLine:
## 数値・日付情報取得
fav = tweet.favorite_count
rt = tweet.retweet_count
date = str(tweet.created_at)[:10]
## テキスト情報取得・クレンジング
T = tweet.text.replace('\n','')
if "#まいにちチクショー" in T and "RT @" not in T:
T = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", T)
T = T.replace('コウメ太夫のチクポーレディオ#', '')
T = T.strip()
T = T.replace('#まいにちチクショー', '')
T = T.replace('\u3000', '')
T = T.replace('チクショー!!', '')
t_txt.append([cnt, T])
t_num.append([cnt, date, fav, rt])
cnt += 1


tweetデータの集計

日付データの欠損を考慮しつつ、取得したデータからデータフレームを作成する。


koume_prophet.py

### データ作成

## 取得データを集計
data = pd.DataFrame(t_num, columns = ["index", "date", "fav", "rt"])
data = data.set_index("index")
data = data.groupby("date")
data_agg = data[["fav","rt"]].sum()
## 今日までの日付リスト生成
date = dt.date(2016, 3, 1)
today = dt.date.today()
duration = (today-date).days
date_list = []
for i in range(duration):
date_list.append(date)
date += dt.timedelta(days=1)
date_list = [str(n) for n in date_list]
date_list_df = pd.DataFrame(date_list, columns = ["date"])
## 結合
dataset = pd.merge(date_list_df, data_agg, on = "date", how = "left")
dataset =dataset.fillna(0)
dataset = dataset.set_index("date")

予測精度を評価するために、学習データとテストデータを作成する。

各データセットの期間は下記。

[学習期間]

・2016-03-01~2019-02-28

→まいにちチクショーが開始した日から丸々3年間。年別のトレンドを掴むためにも、年単位での設定が良いと思われる。

[テスト期間]

・2019-03-01~2019-06-17とする。

→学習期間end~この記事を執筆した日から5日前までにした。感覚的にいいねの伸びは5日程度で落ち着くと考えたので。


koume_prophet.py

# データ準備

train_data = dataset[dataset.index.get_loc("2016-03-01"):dataset.index.get_loc("2019-02-28")]
test_data = dataset[dataset.index.get_loc("2019-03-01"):dataset.index.get_loc("2019-06-17")]
test_data = test_data.reset_index(drop = True)
train_data = train_data.reset_index()

Prophetでモデル構築するための最後の準備。

Prophetの予測では、日付データの変数名を"ds"、トレンドを確認したい対象の変数名を"y"とする必要があるそう。

今回は"いいね数(fav)"を対象とする。(RT数を対象とする場合は"rt"を"y"に変更する。)


koume_prophet.py

train_data = train_data.rename(columns = {"date":"ds", "fav":"y"})



Prophetの実行

早速Prophetモデルを学習させる。


koume_prophet.py

m = Prophet(yearly_seasonality = True, weekly_seasonality = True)

m.fit(train_data)

たった二行でモデルの学習が完了してしまう。すごい。

yearly_seasonality は対象の変数に年間の周期性があると思われる場合にTrueにする。

weekly_seasonality も同様。

そして、最後に予測期間を120日として予測を実施し、結果をplotする。


koume_prophet.py

future = m.make_future_dataframe(periods = 120)

forecast = m.predict(future)
m.plot(forecast)


結果を確認する

まずいいね数の、3年間の推移を確認する。

コウメ太夫の長年の努力の結果が写実される、世紀の一瞬...!圧倒的緊張感...!

どうだ...!

trend.png

このグラフを見る限り、なんとなく右肩上がりに見えるのではないだろうか...!?

ちなみにこのグラフの中で外れ値とも言える、2018年年末に25,000近くのいいねを獲得したtweetは下記であった。

スクリーンショット 2019-06-23 1.25.49.png

どうした、めちゃくちゃ面白いではないか (失礼)

更に細かく見てみよう。

Prophetにはplot_componentsというメソッドが存在する。


koume_prophet.py

m.plot_components(forecast)


これを実行すると、簡単に下記のトレンドを確認することが出来る。

まず学習期間(+予測期間)全体でのトレンドを確認する。

スクリーンショット 2019-06-23 1.13.31.png

これは紛うことなく右肩上がりのトレンド。

コウメ太夫が年々人気になっている証といえるだろう。よかった、本当によかったコウメ太夫。

あなたが日々積み重ねてきた努力は着実に実を結んでいる、自信を持って今の道を進んでいってほしい。

この時点で私の仮説は立証され、目的は達成された。

一方で、このplot_componentsメソッドには上記のほか、

下記のグラフも出力されるので、ついでに見てみる。

1.1週間の曜日別のトレンド

スクリーンショット 2019-06-23 1.13.43.png

この図を見る限り、月、水、金にいいねの山が来る様子。

もしとっておきのネタが思いついたら、ぜひ月、水、金のいずれかの曜日にtweetすると良いかもしれない。

2.1年の月別のトレンド

スクリーンショット 2019-06-23 1.30.03.png

図を見る限り、年末年始にいいね数の山が来ている。また、7~8月あたりにも小さな山が乱立していることから、長期休暇にあわせていいねが増える傾向にあることがわかる。

もしとっておきのネタが思いついたら、ぜひ年末年始、夏休みにtweetすると良いかもしれない。


おまけ

過去のトレンドから、未来のいいね数を予測できないかを検証してみる。

prophetから出力したデータから、テスト期間のデータ(=予測結果データ)を抽出し、

同期間の実績データと照らし合わせ、どれくらいあたっているかを確認する。

精度評価指標はMAPE(平均絶対パーセント誤差)を選択。


koume_prophet.py

forecast = forecast.set_index("ds")

result = forecast[forecast.index.get_loc("2019-03-01"):forecast.index.get_loc("2019-06-17")+1]
result = result.iloc[:, -1]
result = result.reset_index(drop = True)
test = test_data.join(result)
test = test[test['fav'] != 0]
test["MAPE"] = abs((test["fav"]-test["yhat"])/test["fav"])*100
test["MAPE"].mean()

結果は...

88.9%

約90%の誤差。。。つまり、いいね数の実績値が100とした時、

予測値が190位になってしまっているということ。

やっぱりバズり予測は簡単ではなさそうね。


さいごに

彼にこのTipsが届くように祈っている。

また、Pythonを触り始めてからまだ日が浅いので、稚拙なコードが散見されると思います。

質問・指摘等ありましたら、ぜひ気軽コメントください。

LOVE コウメ。