Causal Impact
便利そうなので使えるようにしておく
インタフェース
カテゴリ変数はどう渡すのがいいのかな?
これは tfp のお作法がある?
model
カスタムする例がコメントにある
build_default_model 読むと
tfp.sts.LocalLevel をベースに
入力列が 2 以上(y含む)なら tfp.sts.SparseLinearRegression を
nseasons が渡されていたら tfp.sts.Seasonal を追加する
デフォルトのモデルで機能しないなら変える...という感じだろうけど
It's important to note that if you want to have the data standardized, then your customized model must be built with data already standardized and the input data must be the original denormalized data. Also, the model must be built with data of dtype 32 bytes (either np.float32 or tf.float32) as otherwise it may not work when running through TensorFlow
model_args
nseasons/ season_duration で周期渡せる
1h ごとのデータ(24行で1d)で 1w 周期のとき → neseasons=7, season_duration=24
prior_level_sd (default: 0.01)
None なら automatic optimization of the local level される
事前値が適しているのか不明のときに None 渡す
これ pycausalimpact の話だわ
ここでの Piror value って何? 予測値?
共変量が予測値を説明してる場合小さく / 線形回帰で説明できなさそうな場合は大きく
ランダムウォークの要素が強めな場合も
fit_method: (default: 'vi') or hmc
CausalImpact
ci.summary_data に summary の元になる数値が入ってる
ci.model
Bayesian Structural Time Series
Causal Impact の話
仮定
つまり「介入による効果は受けない」と同時に「spillover effectが互いに生じない」さらには「共変量同士でも何がしかの影響を互いに与えない」ことが期待されるわけで、これを厳密に満たす共変量なんて特にマーケティングの現場だとなかなか見つけにくいのではないでしょうか。
"What assumptions does the model make?" の項
確認
共変量をプロットし, 介入前後で共変量が変化していないことを確認する.
介入前のデータにモデルが当てはまっていることを確認する.
介入後のデータ (yt(1)) とモデルの予測値 ŷ t(0) が大きくかけ離れていないことを確認する.
y を説明する値で、かつ介入の影響がない(はず)のものを共変量に選ぶ
予測するのは反実仮想 (counterfactual) の方だから
手順 2 でコントロール地域の選択を検証するには、「キャンペーン前の期間」における検索数の時系列データを 2:1 の比率に分割し、Causal Impact を実施します。その期間中にはプロモーションキャンペーンがなかったため、リフトはないと予想できます。
もしこの時点で有意なリフトが確認できた場合は、手順 1 に戻り、コントロールグループの選定条件を厳しくして、再び手順 2 で検証します。
まず介入前の範囲で予測できてるか、ないはずのリフトが起きてないか見る
? 非線形の関係から予測しようとしているときも起きうる?
Links
ビジターバイアス / トレンドバイアス
傾向スコアで補正する話
ATT; Average Treatment Effect on the Treated
差の差推定法 (DID) は, 施策の前後の差をとり, さらに施策の有無で差をとることで介入効果 (ATT) を推定する方法である.
DID は, 処置群・対照群は介入効果を除いて, 全く同じ外部要因から, 同じ大きさの影響を受けているという前提 (共通トレンド仮定) で ATT を推定しているのに等しい.
予測残差を使った古典的な異常検知とどう違うのかわからない, と考えるだろう. ありていに言えば, 同じである. 正常系であるデータで回帰し, 予測残差の大きさを異常値として扱うというのは, すでに様々な異常検知の教科書で紹介されている
CI がうまく機能しない事例について, シミュレーションによる例を紹介する.
CI で要求される仮定を, 以下の4つだと考えてみた ...
めちゃいいやん
実際にGoogle社におけるglobalのオペレーションでも, 対称群のデータを共変量(covariate)としてモデルに加えることが推奨されているとのことだった. 彼らからはそうすることでより本来の, 反事実(counterfuctual)のデータを予測するができるというアドバイスを受けた.
推定における共変量の良し悪しの判断は, 「介入前の予測残差(plot(,"pointwise"))」に注目することで検証できる
honntoni?
HMC
こういうのもある
Colaboratory でやる
code:tf.py
!pip install tensorflow tensorflow-probability tfcausalimpact > /dev/null
import tensorflow as tf
import tensorflow_probability as tfp
from causalimpact import CausalImpact
code:random.py
df = pd.DataFrame(np.random.rand(100))
ci.plot()
print(ci.summary())
https://gyazo.com/86ddb22367c711f692dadb14975b69f6
Predicted: オリジナルの値(y)と予測される値のライン + 塗りつぶしが信頼区間
乱数なので時系列の予測がまともにできず信頼区間が広い
Point Effects: もとの系列と予測の差
予測がうまくいっていれば線にもっとフィットする ← 共変量からうまく予測できている
Cumlative Effect: 累積効果
時間の経過と累積されるポイント効果の和 & 信頼区間
code:summary
# はコメント
Posterior Inference {Causal Impact}
Average Cumulative
Actual 0.63 18.98
# ↑ 介入後の期間の平均 # 介入後の y の合計
Prediction (s.d.) 0.49 (0.05) 14.64 (1.51)
# ↑ 予測(介入ない)の平均 # 予測の y の合計 (カッコ内は標準偏差)
# Confidence Interval # 予測の 95% 信頼区間 # 合計の 95% 信頼区間
# 0.63 はその外
Absolute effect (s.d.) 0.14 (0.05) 4.34 (1.51)
# 介入効果絶対値の平均
Relative effect (s.d.) 29.62% (10.31%) 29.62% (10.31%)
# 介入効果相対値の平均、相対的には +29.62% の効果
Posterior tail-area probability p: 0.0
# 偶然(介入がyに影響を与えないとした時に)この結果が得られる確率
Posterior prob. of a causal effect: 99.6%
# 因果関係の事後確率
# 観測された影響が介入によるものである確率
カッコ内の標準偏差はどう使う? 予測値のばらつきが大きいなら不安定や予測値の確からしさが低い?
y の plot を見るだけだと「ベースは上がってそうだけど微妙な効果ですね」みたいな会話して終わりなこともあるけど、平均 0.14 上がって介入の影響である確率は 99.6% ですよと言えるのは大きい
? 関数でやる
$ y=0.8x+50+e_{yt} (t\lt70)
$ y=0.8x+50+e_{yt}+20 (t\gt70)
$ x=0.9x_{x-1}+0.2t+e_{xt}
$ e_x, e_y = N(0, 10^2)
70番目から20ずつ増える
https://gyazo.com/977c3bf7e17977fcc40f2ddd213d4bbd https://gyazo.com/d3413fc534ab0f5525bcd2252ef099db
code:summary
Average Cumulative
Actual 188.26 5647.69
Prediction (s.d.) 163.35 (8.39) 4900.4 (251.62)
Absolute effect (s.d.) 24.91 (8.39) 747.28 (251.62)
Relative effect (s.d.) 15.25% (5.13%) 15.25% (5.13%)
Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%
ぱっとみわからんけど100%
平均介入効果は 24.91 / 正解は 20
$ e_yの分散でかく(σ: 10 → 50) したら prob が怪しい感じになるけど、介入効果はほぼ変わらず出てる
https://gyazo.com/2beb754994860c60d5e4fe4151250a4e https://gyazo.com/77a0ad447adb76e7b6ccebe0eeb1bcd1
code:summary
Average Cumulative
Actual 186.79 5603.64
Prediction (s.d.) 161.8 (35.38) 4854.08 (1061.4)
Absolute effect (s.d.) 24.99 (35.38) 749.57 (1061.4)
Relative effect (s.d.) 15.44% (21.87%) 15.44% (21.87%)
Posterior tail-area probability p: 0.24
Posterior prob. of a causal effect: 75.52%
? 介入効果が現れるのが遅延した場合はどうなる?
遅延だけ見たいので関数はシンプルにする
$ y_t = 0.3x+100 (t\lt70)
$ y_t = 0.3x+100+10 (t\geq70)
$ x=0.9x_{x-1}+0.2t
t=70 で介入したことにする(普通) vs t=60 で介入したことにする(効果が遅延)
https://gyazo.com/f337356c29304d76eaed9ac533968b7e https://gyazo.com/27ef841e7660e9c80b8e9f159cad9d8f
[60~70) Cumulative Effect が 0 のまま、効果出たあとの信頼区間がちょっと広がる?
code:summary
Average Cumulative
# t=70
Absolute effect (s.d.) 12.29 (2.17) 368.69 (65.24)
Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%
# t=60
Absolute effect (s.d.) 7.73 (2.44) 309.13 (97.69)
Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 99.9%
どっちも効果ある
Absolute Effect は期間のぶんだけ薄まる、単純に 7.73 * 40 / 30 = 10.30 とすると
12.29 より真実の介入効果に近いけどなぜだろう? 効果 0 の期間があるから分散がちょっとでかくなった影響?
? 季節性を指定する/しない 場合にどう変わる?
季節性のあるデータを作る
曜日の影響を受けるとして、土日は儲からない、週頭から週末にかけて高くなる何かがあるとする
$ w_d=\{w_{sun}, w_{mon}, ...\}=\{0.6, 0.9, 0.9, 1.0, 1.2, 1.3, 0.7\} みたいな係数がかかるとして
$ y_t = w_{dt}(0.3x+100) (t\lt70)
$ y_t = w_{dt}(0.3x+100)+10 (t\geq70)
$ x=0.9x_{x-1}+0.2t
https://gyazo.com/7081afd6c4df9a8434a13381a9e9ae00 https://gyazo.com/4a84b676d62d9eaec27ddc9aa98e5c67
code:summary_noseason
Average Cumulative
Actual 145.14 4354.13
Prediction (s.d.) 115.42 (8.41) 3462.59 (252.18)
Absolute effect (s.d.) 29.72 (8.41) 891.54 (252.18)
Relative effect (s.d.) 25.75% (7.28%) 25.75% (7.28%)
Posterior tail-area probability p: 0.01
Posterior prob. of a causal effect: 99.1%
これでも介入効果でてるけど 29.72 でだいぶおおきい
nseasons=7 にすると
https://gyazo.com/4c0b6106d0cf097a9ebf45e7cefaa9ad
code:summary_with_seasons
Average Cumulative
Actual 145.14 4354.13
Prediction (s.d.) 133.15 (9.68) 3994.57 (290.47)
Absolute effect (s.d.) 11.99 (9.68) 359.56 (290.47)
Relative effect (s.d.) 9.0% (7.27%) 9.0% (7.27%)
Posterior tail-area probability p: 0.11
Posterior prob. of a causal effect: 88.81%
予測線がめっちゃフィットする
最初の信頼区間が怪しいのはなぜ? 季節性が単調増加/減少なことを期待しつつ始める?
効果は 11.99 で正解の10に近いが、事後確率が 88% に落ちた & Cumlative Effect の信頼区間がだいぶ広い
共変量にも係数かけてみる
https://gyazo.com/d59d80b8b8a18fb9cdb90af44103e7d6 https://gyazo.com/2b692f4a3228b964555fd03132bd3098
code:summary
Posterior Inference {Causal Impact}
Average Cumulative
Actual 145.14 4354.13
Prediction (s.d.) 132.87 (7.28) 3986.24 (218.42)
Absolute effect (s.d.) 12.26 (7.28) 367.89 (218.42)
Relative effect (s.d.) 9.23% (5.48%) 9.23% (5.48%)
Posterior tail-area probability p: 0.06
Posterior prob. of a causal effect: 94.31%
? 複数の季節性=1時間おき / 1日おきはどうなる?
月別の平均気温 * 3年とかで
? 特定の曜日にだけ影響があるような場合
まあ単に期間で effect が薄まりそう
? 複数の共変量のどれが予測に使われているかわかる?
tfp.sts.decompose_by_component(ci.model, ci.observed_time_series, ci.model_samples)
code:beta.py
), axis=0)
最初の "関数でやる" の y の説明変数である x を x1 にし、x の誤差項を x2 としてやってみると
まあ x1 のほうが寄与している
getting_started.ipynb では standardize: False しているけど必要?
同じデータに対して True と False 渡してやってみる、よくわからんので極端な値で
https://gyazo.com/87097d20bec2e4c80d37151ee6b831ce
standardize: True
Absolute effect (s.d.) 11.95 (2.0) 358.46 (60.06)
standardize: False
Absolute effect (s.d.) 21.25 (2.75) 637.52 (82.45)
正解の効果は 10 なので standardize したほうが CI としてはよさそう
CausalImpact 実行のたびに微妙に結果が変わるものではあるけどうーん
標準化してないと比較不能なのでは、と一方を100倍とかにしてやってみる
True
Absolute effect (s.d.) 11.01 (2.6) 330.16 (77.96)
False
Absolute effect (s.d.) 13.91 (2.9) 417.34 (87.0)
正解にはより近づいている
カスタムモデルじゃない限り False にする理由特になさそうかな?
共変量から寄与しないやつ外す/入れ替える時もデフォルト(True)でやって 0 に近いものを対象にやればよさそう
? yや共変量の符号が反対でもよい?
まーそりゃよさそう、変わらんわ
? index が datetime のとき