素人でも1ヶ月 Causal Impact で遊んだら、統計的有意差が見えるようになった話

今回のJADEブログでは、データ分析の初心者が「Causal Impact」というパッケージを使って、施策の効果を統計的かつ定量的に説明する方法を紹介しています。実際の実験結果や、ツールの特徴、限界などが具体的に解説されており、プログラミングスキルがなくてもLLMやGoogle検索を活用して分析できることがわかります。ぜひ皆さんもパッケージに触れてみてください。

こんにちは。2024年5月にJADEに入社した江越です。

前職でデータ加工を生業としていた関係で、現在はデータ分析に関わるサポートをメインに取り組んでいます。……とはいえ、法学部出身ということもあり、統計やデータ分析に関しては「素人に毛が生えた程度」の知識しかありません。

今回は、そんな統計素人の私が Causal Impact という分析パッケージに1ヶ月間触れてみた結果、施策の効果を統計的かつ定量的に説明できる手段が得られた経験をシェアしたいと思います。

【もくじ】

Causal Impactとの出会い

統計素人の私が Causal Impact と出会ったきっかけは、端的に言えば弊社が開催したウェビナーでした。

※弊社では継続的に学び合うための勉強会があり、その中で自社が登壇したセミナーを振り返るカリキュラムがあります。素敵ですよね。

そのウェビナーで「Causal Impact」という聞き慣れないワードを耳にした当時の私。「どうやら簡単なプログラミング実装で統計的に施策の効果検証ができる代物らしいけれど、それ以上のことは分からんな〜」とモヤモヤしていました。曖昧な理解を放っておけない性分の私は、気になるあの子のことを想うように、Causal Impact のことを考えて眠れない夜が続きました。

……という冗談はさておき、やはり気になるものは気になるものです。加えて、個人的に効果検証の手法について行き詰まりを感じていた部分もあり、試しに Causal Impact を使ってみることにしました。

(実はウェビナーのアーカイブ公開しております……!よろしければどうぞ!)

ja.dev

効果検証について持っていた課題感

Causal Impact を知る前の効果検証手段

Causal Impact を学ぶ前、私が抱えていた課題は「統計的有意差を定量的に示す」手段を効果検証に用いていなかったことでした。

※統計的有意差がある:「偶然生じうる誤差の範囲を超えて差がある」状態を指します。

では、当時の私が効果検証を求められたら、どのような説明をしていたのでしょうか。大まかには以下のようなものでした。

「施策後の数値から施策前の数値を引いたところ、これだけの差分が生じました。経験則から言えば、この程度の差分があれば施策に効果があったと判断できると思います。」

上記の説明の何が問題なのか?

「え、上記の説明で十分じゃないの?」と思われる方もいらっしゃるでしょう。確かに、意思決定がスムーズに進み、施策が順調に展開され効果を発揮できるなら、結果的には問題ないかもしれません。

しかし、大規模な予算や工数を投じる施策の場合、以下のような観点からの説明も求められることがあるのではないでしょうか?

  • 施策の前後に生じた差分が、単なる偶然の誤差ではないことを確認したい
  • 誤差の可能性を考慮した上で、実際のインパクトがどの程度あったのかを知りたい
  • 可能であれば、季節変動による差分を除外し、施策の純粋な効果を定量的に把握したい

せっかく予算を投じて施策を実行したのに、「あの時の効果は単なる偶然でした。申し訳ありません」では、あまりにもったいないですよね。

さらに、各施策がもたらす影響をより正確に把握し、それぞれにどれだけのリソースを割り当てるべきか判断したいケースも少なくありません。

これらの要求に応えるには、単純な差分を示すだけでは不十分で「統計的な有意差を定量的に示す」必要があります。かといって統計学やプログラミングをしっかり学んだ経験がなかった自分は、最適な手段を持ち合わせているわけもありませんでした。

こんな状況で出会ったのが Causal Impact であり、もしかすると自分の課題感を解決する鍵になるかも?と思い立った私は、この未知のパッケージとの戯れに身を投じてみることにしました。

google.github.io

実際に遊んでみる

Causal Impactとは一体何者だ!

さて、遊んでみよう!といっても Causal Impact が何者かもよく知らない私。とりあえずGoogle検索を活用して以下の情報を得ました。

  • Causal Impact はGoogleが作ったRパッケージ。Pythonでも利用できるらしい
  • 施策を行う前のデータを学習して、施策が行われなかった場合のデータがどうなるかを予測してくれる。予測値と実測値を比べれば施策に効果があったかを調べられる
  • 予測に必要な種データは「時系列」と「実測値」、必要に応じて「共変量」の最大3種類

何をすれば良いか整理してみる

これで Causal Impact の概念の大枠は掴めましたが、具体的な手順はまだ把握できていません。

差し当たり「PythonかRを使う必要があるんだな」ということは分かったので、プログラミングの基本である「input/through/output」の枠組みで流れを整理してみました。

  • input:時系列データ、実測値、および必要に応じて、共変量を含むデータセットの準備をする
  • through:Pythonでinputデータを Causal Impact に渡し、予測を実行する
  • output:予測値と実測値の差分を算出し、結果を表示する

inputとthroughを用意して実行してみる

大まかに必要な情報が整理できたので、実験の準備です。

前提情報として以下のような状況を想定して、データとコードを準備してみました。

 

前提情報

  • テスト概要
    • テスト対象:月曜火曜にトレンドのある動きを見せるクエリ×URL群
    • 改善施策:2020年2月1日にタイトル改善をリリースした
  • データ概要
    • 期間:(前)2020-01-01 - 2020-01-31、(後)2020-02-01 - 2020-02-28
    • metric(実測値):Click数
    • covariate(共変量):Impression数

 

Inputデータ(Googleスプレッドシート)

date Click Impression
2020-01-01 7352 48804
2020-01-02 7323 41160
2020-01-03 4136 19420
2020-01-04 4170 20433
2020-01-05 4423 21604
2020-01-06 4031 24975
2020-01-07 4096 20966
2020-01-08 7308 43164
2020-01-09 7193 43956
2020-01-10 4130 20643
2020-01-11 4090 19420
2020-01-12 4164 19800
2020-01-13 4124 21582
2020-01-14 4310 20895
2020-01-15 7464 39160
2020-01-16 7423 39984
2020-01-17 4245 20958
2020-01-18 4098 19280
2020-01-19 4011 21230
2020-01-20 4064 23088
2020-01-21 4283 19820
2020-01-22 7404 40344
2020-01-23 7480 41706
2020-01-24 4211 21956
2020-01-25 4291 23568
2020-01-26 4494 23000
2020-01-27 4489 19740
2020-01-28 4054 19280
2020-01-29 7431 47760
2020-01-30 7380 46201
2020-01-31 4360 24575
2020-02-01 5887 20307
2020-02-02 5628 20958
2020-02-03 5296 21626
2020-02-04 5124 20286
2020-02-05 7943 38320
2020-02-06 7635 42828
2020-02-07 6692 22770
2020-02-08 6733 24525
2020-02-09 6551 23280
2020-02-10 6932 21850
2020-02-11 6532 20181
2020-02-12 9838 39160
2020-02-13 9756 40098
2020-02-14 6231 22471
2020-02-15 6451 20118
2020-02-16 6488 20265
2020-02-17 6908 23280
2020-02-18 6573 21340
2020-02-19 9572 46320
2020-02-20 9395 45073
2020-02-21 6387 22954
2020-02-22 6023 22824
2020-02-23 6589 22333
2020-02-24 6213 20988
2020-02-25 6220 19940
2020-02-26 9214 47383

 

コード(Google Colab)

#######0-事前準備

# 必要なライブラリ、パッケージを用意

!pip install gspread pandas
!pip install tfcausalimpact

import gspread
import pandas as pd

from causalimpact import CausalImpact
from google.colab import auth
from google.auth import default


# 認証などを行います

auth.authenticate_user()
creds, _ = default()
gc = gspread.authorize(creds)



#######1-input

# スプレッドシートにアクセスします

ss_url = "https://docs.google.com/spreadsheets/hogehoge" #対象のスプレッドシートのURLを突っ込む
spreadsheet = gc.open_by_url(ss_url)

# 最初のシートを取得します

sheets = spreadsheet.sheet1

# シートごとのデータを格納するリストを作成します

all_data = []

# 最初のシートのデータを取得し、データフレームに追加します

data = sheets.get_all_values()
input_df = pd.DataFrame(data[1:], columns=data[0])

# 結果変数と共変量のカラムを数値型に変換(ここは小数型に)

input_df['Click']=input_df['Click'].astype(float)
input_df['Impression']=input_df['Impression'].astype(float)

# 時系列カラムをindexに指定

input_df.set_index('date',inplace=True)

#データ型が変換できているか確認

print(input_df.dtypes)



#######2-through

# 期間設定

pre_period = ['2020-01-01', '2020-01-31']
post_period = ['2020-02-01', '2020-02-26']

# 実行

impact = CausalImpact(input_df, pre_period, post_period)




#######3-output

# 結果の確認

print(impact.summary())
print(impact.summary(output='report'))
impact.plot()

統計的有意差が見える……見えるぞっ!

Causal Impact を実行した結果

上記で準備したコードを実行してみると、以下のようなレポートとグラフが得られました。

 

レポート

> Posterior Inference {Causal Impact}
> Average            Cumulative
> Actual                    7031.19            182811.0
> Prediction (s.d.)         5088.55 (171.67)   132302.41 (4463.33)
> 95% CI                    [4762.14, 5435.06] [123815.75, 141311.68]


> Absolute effect (s.d.)    1942.64 (171.67)   50508.59 (4463.33)
> 95% CI                    [1596.13, 2269.05] [41499.32, 58995.25]

> Relative effect (s.d.)    38.18% (3.37%)     38.18% (3.37%)
> 95% CI                    [31.37%, 44.59%]   [31.37%, 44.59%]

> 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'))
> Analysis report {CausalImpact}

> During the post-intervention period, the response variable had
> an average value of approx. 7031.19. By contrast, in the absence of an
> intervention, we would have expected an average response of 5088.55.
> The 95% interval of this counterfactual prediction is [4762.14, 5435.06].
> Subtracting this prediction from the observed response yields
> an estimate of the causal effect the intervention had on the
> response variable. This effect is 1942.64 with a 95% interval of
> [1596.13, 2269.05]. For a discussion of the significance of this effect,
> see below.

> Summing up the individual data points during the post-intervention
> period (which can only sometimes be meaningfully interpreted), the
> response variable had an overall value of 182811.0.
> By contrast, had the intervention not taken place, we would have expected
> a sum of 132302.41. The 95% interval of this prediction is [123815.75, 141311.68].

> The above results are given in terms of absolute numbers. In relative
> terms, the response variable showed an increase of +38.18%. The 95%
> interval of this percentage is [31.37%, 44.59%].

> This means that the positive effect observed during the intervention
> period is statistically significant and unlikely to be due to random
> fluctuations. It should be noted, however, that the question of whether
> this increase also bears substantive significance can only be answered
> by comparing the absolute effect (1942.64) to the original goal
> of the underlying intervention.

> The probability of obtaining this effect by chance is very small
> (Bayesian one-sided tail-area probability p = 0.0).
> This means the causal effect can be considered statistically
> significant.

 

グラフ

得られた結果を解釈してみる

英文が多くて「うっ……」となる方もいらっしゃるかもしれませんが、レポートの内容は意外とシンプルです。上記で得られた結果を簡潔に解釈してみましょう。

レポートの解釈

施策の効果を端的に知りたいなら、最後のパラグラフに注目するとよいでしょう。今回の実験では、以下のような記述があります。

The probability of obtaining this effect by chance is very small
(Bayesian one-sided tail-area probability p = 0.0).
This means the causal effect can be considered statistically
significant.

上記の記述は「偶然に差分が生まれた可能性はとても低く、統計的に有意差があると考えられる」ということを示しています。

 

また、差分が具体的にどの程度あったのかについては、レポート上部にある以下の数表を見ると分かりやすいでしょう。

> Average            Cumulative
> Actual                    7031.19            182811.0
> Prediction (s.d.)         5088.55 (171.67)   132302.41 (4463.33)
> 95% CI                    [4762.14, 5435.06] [123815.75, 141311.68]


> Absolute effect (s.d.)    1942.64 (171.67)   50508.59 (4463.33)
> 95% CI                    [1596.13, 2269.05] [41499.32, 58995.25]

> Relative effect (s.d.)    38.18% (3.37%)     38.18% (3.37%)
> 95% CI                    [31.37%, 44.59%]   [31.37%, 44.59%]
>

数表の構成が少し分かりにくいかもしれませんが、以下のようになっています。

  • 横方向
    • 左側:平均値
    • 右側:累計値
  • 縦方向
    • Actual:実測値
    • Prediction:予測値
    • Absolute effect:実測値と予測値の差(実数)
    • Relative effect:実測値と予測値の差(比率)
    • 95% CI:各指標の95%信頼区間

※信頼区間:誤差を考慮した上で、真の値が含まれる可能性が高い範囲のこと

以上を踏まえて数表から読み解くと、タイトル改善施策の日次効果は実数値ベースで+1,942.64Click(95%信頼区間:+1,596.13〜+2,269.05Click)、比率で見ると+38.18%(95%信頼区間:+31.37%〜+44.59%)の効果があったと解釈できます。

 

グラフの解釈

グラフは3つあり、それぞれ以下の内容を描画しています。

  • 上段:予測値(点線)と実測値(実線)の比較
  • 中段:実測値と予測値の差分
  • 下段:施策後期間における実測値と予測値の差分の累積

まず一番上のグラフで、Predicted(予測値)とy(実測値)に注目してください。両者の線がかなり重なっていることがお分かりでしょう。これは、ClickとImpressionの共変関係を Causal Impact が学習し、波形を正確に予測できるようになったことを示しています。つまり、Impressionの増加によって生じるClick増加の影響についてはすでに学習済みなので、その影響を除外した形で施策の純粋な効果を把握できるというわけです。

またそれぞれのグラフに描かれているオレンジの範囲は、いわゆる信頼区間を表しています。この信頼区間は、誤差の可能性を考慮した上で取りうる値の範囲を示しています。

例えば一番下のグラフを見ると、期間終了時のオレンジの範囲がおよそ40,000〜60,000の間を示しています。これは誤差を考慮した上で、タイトル改善施策による累積効果として取りうる値の範囲を表しているのです。

ここまでの実験で挙動はなんとなく分かりましたが、Causal Impact の限界についても知りたいのでもう2パターンほど実験してみました。

 

別パターンその1 〈共変量なしで回してみる〉

先ほどの実験したデータから共変量に当たるImpressionカラムを取り除いてみます。共変量を無しにした時、予測値がどうなるかをみてみましょう。

 

Inputデータ(Impressionなし)

date Click
2020-01-01 7352
2020-01-02 7323
2020-01-03 4136
2020-01-04 4170
2020-01-05 4423
2020-01-06 4031
2020-01-07 4096
2020-01-08 7308
2020-01-09 7193
2020-01-10 4130
2020-01-11 4090
2020-01-12 4164
2020-01-13 4124
2020-01-14 4310
2020-01-15 7464
2020-01-16 7423
2020-01-17 4245
2020-01-18 4098
2020-01-19 4011
2020-01-20 4064
2020-01-21 4283
2020-01-22 7404
2020-01-23 7480
2020-01-24 4211
2020-01-25 4291
2020-01-26 4494
2020-01-27 4489
2020-01-28 4054
2020-01-29 7431
2020-01-30 7380
2020-01-31 4360
2020-02-01 5887
2020-02-02 5628
2020-02-03 5296
2020-02-04 5124
2020-02-05 7943
2020-02-06 7635
2020-02-07 6692
2020-02-08 6733
2020-02-09 6551
2020-02-10 6932
2020-02-11 6532
2020-02-12 9838
2020-02-13 9756
2020-02-14 6231
2020-02-15 6451
2020-02-16 6488
2020-02-17 6908
2020-02-18 6573
2020-02-19 9572
2020-02-20 9395
2020-02-21 6387
2020-02-22 6023
2020-02-23 6589
2020-02-24 6213
2020-02-25 6220
2020-02-26 9214

 

Outputグラフ(Impressionなし)

 

一番上のグラフを見ていただくと、学習用データとして与えた前期間の予測値(Predicted)が実際の値(y)から大きく乖離してしまっていることがお分かりいただけると思います。変動の少ないデータであれば共変量を設定しなくても精度の高い予測が可能ですが、今回のように一定以上の変動が存在するデータについては、適切な共変量を設定した方が予測精度が向上しそうです。

共変量の例としては、最初の実験のように実測値に影響を与える指標(例:Clickに対するImpression)を設定するパターンのほか、テスト以外の条件・傾向が揃っている非テスト群の実測値を入れてみるパターンなどが考えられます。どの共変量を設定すれば予測が正確になるかは状況によって様々です。そのため、データと実験対象の特性を考慮しながら、試行錯誤してみるのがよいでしょう。

 

別パターンその2 〈規則性のないデータを元にAAテストを回してみる〉

また、学習が困難なデータの扱いにも課題があるのではないかと考えました。そこで、何の施策も実施していないという前提で入力データを用意し、Causal Impact を適用してみることにしました(いわゆるAAテスト)。

 

Inputデータ(不規則な変化)

date Click Impression
2020-01-01 5937 49427
2020-01-02 5376 40764
2020-01-03 9836 18395
2020-01-04 4876 38858
2020-01-05 2937 17133
2020-01-06 20443 14058
2020-01-07 9454 46000
2020-01-08 6074 30951
2020-01-09 9372 36974
2020-01-10 3249 10778
2020-01-11 7059 24643
2020-01-12 18932 32762
2020-01-13 3201 35758
2020-01-14 3454 42654
2020-01-15 5642 15379
2020-01-16 4973 44152
2020-01-17 8269 27102
2020-01-18 7222 47742
2020-01-19 16337 15665
2020-01-20 9178 20444
2020-01-21 1090 25416
2020-01-22 4381 14568
2020-01-23 9107 28640
2020-01-24 3690 32918
2020-01-25 8373 23165
2020-01-26 5468 24005
2020-01-27 6296 15991
2020-01-28 1692 48932
2020-01-29 5454 34796
2020-01-30 3483 29899
2020-01-31 4130 35383
2020-02-01 2881 10478
2020-02-02 1874 22467
2020-02-03 923 14103
2020-02-04 873 13304
2020-02-05 1932 47672
2020-02-06 2022 16744
2020-02-07 3345 22346
2020-02-08 3155 20359
2020-02-09 4147 17610
2020-02-10 7298 49650
2020-02-11 1260 34437
2020-02-12 4298 38343
2020-02-13 3534 29264
2020-02-14 4554 28002
2020-02-15 8398 45654
2020-02-16 1581 37156
2020-02-17 3575 41462
2020-02-18 10283 31711
2020-02-19 3486 15716
2020-02-20 3238 34430
2020-02-21 3853 43767
2020-02-22 2660 44705
2020-02-23 3720 37555
2020-02-24 2425 11900
2020-02-25 7032 28964
2020-02-26 15639 15444

 

Outputグラフ(不規則な変化)

 

上記の例では施策を実施していないにもかかわらず、後期間で統計的な有意差が確認されてしまっています。共変量としてImpressionを設定したものの、Clickの増減との関連性が特に見られないため、予測が正確に成り立っていません。このような状況下では施策の効果を検証しようとしても、それが施策の効果なのか、それとも偶然によるものなのか、判断が困難になってしまいます。

精度を向上させる試みとして、テスト群の再選定やデータクレンジング、他の共変量の検討といった可能性が考えられます。しかし、常に適切な解決策が見つかるとは限りません。このように Causal Impact が不向きなケースが存在することを認識しておくことも重要だと考えています。

 

ここまで Causal Impact を使って、その可能性を実験ベースで探ってきました。

Causal Impact の特徴を3点でまとめるなら、以下の感じかなと。

  • 値を予測する際、信頼区間を算出してくれるので、誤差を定量的に把握できる
  • 共変量をうまく設定すれば、他の要因の影響を排除した上で予測できる
  • ただし共変量で説明できない不規則な変化があると予測が困難に

確かに予測が難しいケースも存在しますが、共変量を用いて他要因の影響を排除し、施策の効果を統計的かつ定量的に示せるツールとして、Causal Impact の威力を実感しました。何やかんやで Causal Impact すごい。

 

R・Pythonなんて書けないよ……と思ったそこのあなたへ

「え、なんかしれっとPythonが登場してない……?」

「プログラミングなんて書けないよ……」

安心してください。実は私もPythonをまともに触ったことがありません。

ただそんな私でも、LLMやGoogle検索が普及した現代では、仕様さえ詳細に言語化できれば、Causal Impact のような分析をノンプログラマーでも実装し、統計的有意差があるかを語れる時代になりました。改めて振り返ってみても自分の業務の多くは、LLMがなければ手の届かなかったものばかりです。技術の進化に感謝ですね。

最後にそんなノンプログラマーの私が、LLMが登場した現代においてアドホックなプログラムを組む必要が生じた時に意識していることをご紹介し、このブログを締めたいと思います。

  1. プログラミングは人間から機械への依頼であることを強く意識する。
  2. プログラミングの文法よりも、そもそも機械にどんなことができるのかを知る。
  3. 機械ができることを組み合わせたら、どんなものが出来上がるのかイメージできるようになる。
  4. プログラミングの文法については覚えていたらラッキー程度のスタンス。覚えていなかったらLLMやGoogle検索を頼ればよい。

Causal Impact は確かに簡単なプログラミング実装が必要ですが、今は実装を助ける便利な情報やツールが溢れている時代です。使いこなせるようになれば、統計的かつ定量的に効果を検証できる強力な手段となり、心強い味方になることは間違いありません。

まずは遊んでみることから。Causal Impact、皆さんもぜひチャレンジしてみてください!

 

なお実際のSEO施策で Causal Impact を活用した話は、弊社長山執筆の以下ブログに記載があります。こちらもよろしければぜひご覧ください!

blog.ja.dev