Skip to content

Commit a6ddda9

Browse files
authored
Fix calculation/plotting mistake to now focus on posterior expectation (#539)
1 parent edb7f8d commit a6ddda9

File tree

10 files changed

+739
-536
lines changed

10 files changed

+739
-536
lines changed

causalpy/experiments/interrupted_time_series.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ class InterruptedTimeSeries(BaseExperiment):
7070
... }
7171
... ),
7272
... )
73+
74+
Notes
75+
-----
76+
For Bayesian models, the causal impact is calculated using the posterior expectation
77+
(``mu``) rather than the posterior predictive (``y_hat``). This means the impact and
78+
its uncertainty represent the systematic causal effect, excluding observation-level
79+
noise. The uncertainty bands in the plots reflect parameter uncertainty and
80+
counterfactual prediction uncertainty, but not individual observation variability.
7381
"""
7482

7583
expt_type = "Interrupted Time Series"

causalpy/experiments/synthetic_control.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ class SyntheticControl(BaseExperiment):
6767
... }
6868
... ),
6969
... )
70+
71+
Notes
72+
-----
73+
For Bayesian models, the causal impact is calculated using the posterior expectation
74+
(``mu``) rather than the posterior predictive (``y_hat``). This means the impact and
75+
its uncertainty represent the systematic causal effect, excluding observation-level
76+
noise. The uncertainty bands in the plots reflect parameter uncertainty and
77+
counterfactual prediction uncertainty, but not individual observation variability.
7078
"""
7179

7280
supports_ols = True

causalpy/pymc_models.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,44 @@ def score(self, X: xr.DataArray, y: xr.DataArray) -> pd.Series:
305305
def calculate_impact(
306306
self, y_true: xr.DataArray, y_pred: az.InferenceData
307307
) -> xr.DataArray:
308-
impact = y_true - y_pred["posterior_predictive"]["y_hat"]
308+
"""
309+
Calculate the causal impact as the difference between observed and predicted values.
310+
311+
The impact is calculated using the posterior expectation (`mu`) rather than the
312+
posterior predictive (`y_hat`). This means the causal impact represents the
313+
difference from the expected value of the model, excluding observation noise.
314+
This approach provides a cleaner measure of the causal effect by focusing on
315+
the systematic difference rather than including sampling variability from the
316+
observation noise term.
317+
318+
Parameters
319+
----------
320+
y_true : xr.DataArray
321+
The observed outcome values with dimensions ["obs_ind", "treated_units"].
322+
y_pred : az.InferenceData
323+
The posterior predictive samples containing the "mu" variable, which
324+
represents the expected value (mean) of the outcome.
325+
326+
Returns
327+
-------
328+
xr.DataArray
329+
The causal impact with dimensions ending in "obs_ind". The impact includes
330+
posterior uncertainty from the model parameters but excludes observation noise.
331+
332+
Notes
333+
-----
334+
By using `mu` (the posterior expectation) rather than `y_hat` (the posterior
335+
predictive with observation noise), the uncertainty in the impact reflects:
336+
- Parameter uncertainty in the fitted model
337+
- Uncertainty in the counterfactual prediction
338+
339+
But excludes:
340+
- Observation-level noise (sigma)
341+
342+
This makes the impact plots focus on the systematic causal effect rather than
343+
individual observation variability.
344+
"""
345+
impact = y_true - y_pred["posterior_predictive"]["mu"]
309346
return impact.transpose(..., "obs_ind")
310347

311348
def calculate_cumulative_impact(self, impact):

docs/source/_static/interrogate_badge.svg

Lines changed: 3 additions & 3 deletions
Loading

docs/source/notebooks/geolift1.ipynb

Lines changed: 25 additions & 15 deletions
Large diffs are not rendered by default.

docs/source/notebooks/its_covid.ipynb

Lines changed: 27 additions & 31 deletions
Large diffs are not rendered by default.

docs/source/notebooks/its_pymc.ipynb

Lines changed: 296 additions & 180 deletions
Large diffs are not rendered by default.

docs/source/notebooks/multi_cell_geolift.ipynb

Lines changed: 142 additions & 132 deletions
Large diffs are not rendered by default.

docs/source/notebooks/sc_pymc.ipynb

Lines changed: 44 additions & 34 deletions
Large diffs are not rendered by default.

docs/source/notebooks/sc_pymc_brexit.ipynb

Lines changed: 148 additions & 140 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)