LIFULL Creators Blog

「株式会社LIFULL(ライフル)」の社員によるブログです。

Python版CausalImpactを用いたTVCMの効果検証

こんにちは。LIFULLでデータアナリストをしている宮野です。

普段はサービス周りのデータ分析を行っているのですが、TVCMの効果検証を行う機会があり、その際CausalImpactという時系列因果推論フレームワークを使用したのでご紹介いたします。


【目次】

はじめに

  • CausalImpactとは?

 →Googleがリリースした時系列因果推論の"R"パッケージです。
そう。Rのパッケージです。当然Rを使って効果検証を行うのが通常だと思います。

なのですが、私自身Pythonを使用することが多く、どうせならPythonで分析できないかと調べたところ、有志が作成した"Pythonでも使えるCausalImpact"のライブラリを発見しました。
せっかくなのでこちらを使用してみたのですが、実装していく中で、非公式?故か日本語での参考記事があまり見当たりませんでした。そこで少しでもPython版を使用する方の参考になればと思い、こちらを執筆しました。

今回使用したPythonのライブラリはこちら。
dafiti/causalinpact:https://github.com/dafiti/causalimpact

参考として、記事後半でRのCausalImpactにおける検証結果との比較も行っています。

なお、この記事は「とりあえず手を動かして実行できる」ことを目的にしているため、難しい用語の使用はできるだけ避けました。同じ理由で、前提となる統計学や因果推論の知識も割愛しています。
※実務で使用する場合は必ず有識者に相談やレビューをしてもらったうえで効果検証をしてください

Pythonを用いたCausalImpact

データの準備

今回、CausalImpactを使用して「ある地域では、TVCMを放映したことによってサイト流入数は増加したか?」という検証を行うものとします。

検証を行うためには目的変数となる"TVCM放映エリア"のサイト流入数と、共変量(≒説明変数)となる"非TVCM放映エリア"のサイト流入数のデータが必要になります。

これらを踏まえて、用意したデータの概要は以下の通りです。

  • データ取得期間:2019年10月1日〜2020年2月29日
  • TVCM放映期間:2020年1月8日〜
  • TVCM放映エリア(Aエリア):サイト流入数(目的変数)
  • TVCM非放映エリア(B,C,Dエリア):サイト流入数(共変量≒説明変数)

※実際のデータを使用することはできないため、サンプルデータを用意しました


Python版CausalImpactのインストール

pip install pycausalimpact
#必要なライブラリをインポートする
import pandas as pd
import numpy as np
from statsmodels.tsa.arima_process import ArmaProcess
from matplotlib import pyplot as plt
from causalimpact import CausalImpact ##CausalImpactのライブラリ

%matplotlib inline
#データの読み込み(今回はexcel)
df = pd.read_excel('sample.xlsx')
 
#データの確認
df.head()

f:id:LIFULL-miyanoy:20200409130900p:plain
データの読み込みが完了しました。

後述しますが、CausalImpactを実行する際にどの時点で介入があったのかindexで指定する必要があります。
今回はわかりやすいようにdateをindexに指定します。

#CausalImpactを実行する際、わかりやすいように日付データをindexに指定する
df = df.set_index('date')
df.head()

f:id:LIFULL-miyanoy:20200409130903p:plain

これでCausalImpactを実行する準備ができました。

効果検証

実際に効果検証を行っていきます。

#TVCM放送前と後を指定する
pre_period = ['2019-10-01', '2020-01-07'] #TVCM放映開始前
post_period = ['2020-01-08', '2020-02-29'] #TVCM放映開始後

#CausalImpactの実行
ci = CausalImpact(df, pre_period, post_period)
ci.plot(figsize=(22, 20))

f:id:LIFULL-miyanoy:20200409130851p:plain
縦に引かれた黒の破線は、TVCM放映開始後である2020-01-08となります。
上段に図示された黒の実線は実績値、青の点線はTVCMを放映しなかった場合の予測値となります。
中段に図示されたものがTVCM放映の効果になりますが、2020年1月8日にTVCMを放映してからサイト流入数が増加したと言えそうです。
下段に図示されたものは増加したサイト流入数の累計値です。

結果のサマリーを確認するには以下を実行します。

#サマリーの確認
print(ci.summary())
Posterior Inference {Causal Impact}
                          Average            Cumulative
Actual                    285.22             15116.91
Prediction (s.d.)         206.92 (10.57)     10966.99 (559.96)
95% CI                    [186.82, 228.24]   [9901.52, 12096.52]

Absolute effect (s.d.)    78.3 (10.57)       4149.92 (559.96)
95% CI                    [56.99, 98.4]      [3020.39, 5215.39]

Relative effect (s.d.)    37.84% (5.11%)     37.84% (5.11%)
95% CI                    [27.54%, 47.56%]   [27.54%, 47.56%]

Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%

For more details run the command: print(impact.summary('report'))

共変量の確認と選定 / 周期性(シーズナリティ)の付与

ここからは少し踏み込んだ話をします。

①共変量

今回のデータでは、共変量(≒説明変数)としてB,C,DのTVCM非放映エリアのデータがあります。
この共変量は予測モデルに必要となる大事な要素となります。

共変量がモデル作成にどれだけ使われている(モデルに影響している)のかを確認するために以下を実行します。

ci.trained_model.summary()

f:id:LIFULL-miyanoy:20200414091333p:plain
P>|z|coefに注目します。今回の結果だとエリアB,C,Dを使用して予測モデルを作成していそうです。

例えばcoefが"0"になるような共変量があった場合、その共変量は予測モデル作成には使用されないようになっています。
そのため、使用された共変量を確認し、"使用されなかった共変量を削除→新たな共変量を追加"という作業を繰り返すことで、モデル精度を高めることができそうです。

②周期性(シーズナリティ)

次に周期性(シーズナリティ)について説明します。
時系列データには、天候や季節、曜日などによって数値が変わるような季節変動が含まれる場合があります。季節変動が含まれるデータの場合、より良い予測モデルにするためには季節変動を考慮する必要があります。

ここでは例として「平日より土日のほうが検索数が多いため1週間(7日間)ごとの周期性がありそう」と仮定します。
この周期性を考慮してCausalImpactを実行するには"nseasons"を追記することで実現できます。(デフォルトは1)

#CausalImpactの実行
ci = CausalImpact(df, pre_period, post_period, nseasons=[{'period': 7}]) #7日間の周期性を考慮する
ci.plot(figsize=(22, 20))


これでPython版CausalImpactを用いた効果検証が一通りできました。

RのCausalImpactとの結果比較

同じデータを使用して、RでもCausalImpactを実装していきます。
※Pythonのように日付データをindexに指定しませんがデータの中身は同じものです

最初に断っておきますが、あくまでPythonとの結果比較をするだけで「なぜ結果が違うのか」「どちらがいいのか」などについては触れないものとします。(むしろ詳しい人がいたら教えてください)

RでのCausalImpact実装

#excelファイルを読み込むためのパッケージをインストール
install.packages("openxlsx")
#CausalImpactをインストール
install.packages("CausalImpact")

#ライブラリの読み込み
library(openxlsx)
library(CausalImpact)
 
#データの読み込み(excel)
df <- read.xlsx("sample_R.xlsx")
 
#TVCM放送前と後を指定する(index番号)
pre.period <- c(1, 99) #TVCM放映開始前
post.period <- c(100, 152) #TVCM放映開始後
 
#CausalImpactの実行とサマリーの表示
ci <- CausalImpact(df, pre.period, post.period)
plot(ci)
summary(ci)

f:id:LIFULL-miyanoy:20200409153519p:plain

Posterior inference {CausalImpact}

                         Average      Cumulative   
Actual                   285          15117        
Prediction (s.d.)        207 (13)     10987 (673)  
95% CI                   [182, 233]   [9634, 12325]
                                                   
Absolute effect (s.d.)   78 (13)      4130 (673)   
95% CI                   [53, 103]    [2792, 5483] 
                                                   
Relative effect (s.d.)   38% (6.1%)   38% (6.1%)   
95% CI                   [25%, 50%]   [25%, 50%]   

Posterior tail-area probability p:   0.001
Posterior prob. of a causal effect:  99.9%

For more details, type: summary(impact, "report")

共変量の確認

plot(ci$model$bsts.model, "coefficients")

周期性(シーズナリティ)

ci <- CausalImpact(df, pre.period, post.period, model.args=list(nseasons=7)) #7日間の周期性を考慮する

PythonとRの検証結果比較

PythonとRの検証結果(サマリーの内容)を比較してみます。
f:id:LIFULL-miyanoy:20200416172224p:plain
今回用意したサンプルデータではPythonとRの結果には差がなさそうです。
※尚、今回のサンプルデータでのみ検証結果の比較を行っております。ご注意ください

おわりに

いかがでしたでしょうか?
Python,Rどちらも簡単にCausalImpactを用いた効果検証が行えそうです。

今回のように、TVCM放映エリアと非放映エリアがある場合は共変量として非放映エリアを使用するのが良いと思います。
しかし、全国でTVCMを放映していた場合はどうでしょうか。

例えば、Google Trendsなどを利用して「1LDK」や「引越し」など、同じ業態の中でも検索トレンドがサイト流入数と似ているものを探し、共変量として使用してみるといいかもしれません。
地域にこだわらなくても、同質性が担保できれば問題ないと思います。

今回の検証では、TVCM非放映エリアがあったので簡単に共変量を見つけることができましたが、今後は上記のようなケースでも正しく効果検証ができるように自身のスキルを磨いていきたいと思います。


本記事の内容に齟齬などあればご教示いただけますと幸いです。