Help us understand the problem. What is going on with this article?

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すると良いかもしれない。
(2019-10-02 追記:縦軸の意味はこの方が丁寧に説明してくださっているので、参考にしてください。https://github.com/facebook/prophet/issues/392)

おまけ

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

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 コウメ。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした