こんにちは。2024年5月にJADEに入社した江越です。
前職でデータ加工を生業としていた関係で、現在はデータ分析に関わるサポートをメインに取り組んでいます。……とはいえ、法学部出身ということもあり、統計やデータ分析に関しては「素人に毛が生えた程度」の知識しかありません。
今回は、そんな統計素人の私が Causal Impact という分析パッケージに1ヶ月間触れてみた結果、施策の効果を統計的かつ定量的に説明できる手段が得られた経験をシェアしたいと思います。
【もくじ】
Causal Impactとの出会い
統計素人の私が Causal Impact と出会ったきっかけは、端的に言えば弊社が開催したウェビナーでした。
※弊社では継続的に学び合うための勉強会があり、その中で自社が登壇したセミナーを振り返るカリキュラムがあります。素敵ですよね。
そのウェビナーで「Causal Impact」という聞き慣れないワードを耳にした当時の私。「どうやら簡単なプログラミング実装で統計的に施策の効果検証ができる代物らしいけれど、それ以上のことは分からんな〜」とモヤモヤしていました。曖昧な理解を放っておけない性分の私は、気になるあの子のことを想うように、Causal Impact のことを考えて眠れない夜が続きました。
……という冗談はさておき、やはり気になるものは気になるものです。加えて、個人的に効果検証の手法について行き詰まりを感じていた部分もあり、試しに Causal Impact を使ってみることにしました。
(実はウェビナーのアーカイブ公開しております……!よろしければどうぞ!)
効果検証について持っていた課題感
Causal Impact を知る前の効果検証手段
Causal Impact を学ぶ前、私が抱えていた課題は「統計的有意差を定量的に示す」手段を効果検証に用いていなかったことでした。
※統計的有意差がある:「偶然生じうる誤差の範囲を超えて差がある」状態を指します。
では、当時の私が効果検証を求められたら、どのような説明をしていたのでしょうか。大まかには以下のようなものでした。
「施策後の数値から施策前の数値を引いたところ、これだけの差分が生じました。経験則から言えば、この程度の差分があれば施策に効果があったと判断できると思います。」
上記の説明の何が問題なのか?
「え、上記の説明で十分じゃないの?」と思われる方もいらっしゃるでしょう。確かに、意思決定がスムーズに進み、施策が順調に展開され効果を発揮できるなら、結果的には問題ないかもしれません。
しかし、大規模な予算や工数を投じる施策の場合、以下のような観点からの説明も求められることがあるのではないでしょうか?
- 施策の前後に生じた差分が、単なる偶然の誤差ではないことを確認したい
- 誤差の可能性を考慮した上で、実際のインパクトがどの程度あったのかを知りたい
- 可能であれば、季節変動による差分を除外し、施策の純粋な効果を定量的に把握したい
せっかく予算を投じて施策を実行したのに、「あの時の効果は単なる偶然でした。申し訳ありません」では、あまりにもったいないですよね。
さらに、各施策がもたらす影響をより正確に把握し、それぞれにどれだけのリソースを割り当てるべきか判断したいケースも少なくありません。
これらの要求に応えるには、単純な差分を示すだけでは不十分で「統計的な有意差を定量的に示す」必要があります。かといって統計学やプログラミングをしっかり学んだ経験がなかった自分は、最適な手段を持ち合わせているわけもありませんでした。
こんな状況で出会ったのが Causal Impact であり、もしかすると自分の課題感を解決する鍵になるかも?と思い立った私は、この未知のパッケージとの戯れに身を投じてみることにしました。
実際に遊んでみる
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)
統計的有意差が見える……見えるぞっ!
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が登場した現代においてアドホックなプログラムを組む必要が生じた時に意識していることをご紹介し、このブログを締めたいと思います。
- プログラミングは人間から機械への依頼であることを強く意識する。
- プログラミングの文法よりも、そもそも機械にどんなことができるのかを知る。
- 機械ができることを組み合わせたら、どんなものが出来上がるのかイメージできるようになる。
- プログラミングの文法については覚えていたらラッキー程度のスタンス。覚えていなかったらLLMやGoogle検索を頼ればよい。
Causal Impact は確かに簡単なプログラミング実装が必要ですが、今は実装を助ける便利な情報やツールが溢れている時代です。使いこなせるようになれば、統計的かつ定量的に効果を検証できる強力な手段となり、心強い味方になることは間違いありません。
まずは遊んでみることから。Causal Impact、皆さんもぜひチャレンジしてみてください!
なお実際のSEO施策で Causal Impact を活用した話は、弊社長山執筆の以下ブログに記載があります。こちらもよろしければぜひご覧ください!