Skip to content

Commit 141caa9

Browse files
authored
Merge branch 'main' into basic_ci
2 parents 07df35f + b7ac1d8 commit 141caa9

14 files changed

+943
-6717
lines changed

README.md

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ Another distinctive feature of this package is the ability to use different mode
1515

1616
| | [CausalImpact](https://google.github.io/CausalImpact/) from Google | [GeoLift](https://github.com/facebookincubator/GeoLift/) from Meta | CausalPy from [PyMC Labs](https://www.pymc-labs.io) |
1717
|---------------------------|--------------------------------|---------|----------------------------------------|
18-
| Interrupted time series ||||
19-
| Synthetic control ||||
18+
| Synthetic control ||||
2019
| Regression discontinuity ||||
2120
| Difference in differences ||||
2221
| Language | R (but see [tfcausalimpact](https://github.com/WillianFuks/tfcausalimpact)) | R | Python |
@@ -92,22 +91,6 @@ This is appropriate when you have multiple units, one of which is treated. You b
9291

9392
> The data (treated and untreated units), pre-treatment model fit, and counterfactual (i.e. the synthetic control) are plotted (top). The causal impact is shown as a blue shaded region. The Bayesian analysis shows shaded Bayesian credible regions of the model fit and counterfactual. Also shown is the causal impact (middle) and cumulative causal impact (bottom).
9493
95-
### Interrupted time series
96-
This is appropriate when you have a single treated unit, and therefore a single time series, and do _not_ have a set of untreated units.
97-
98-
| Time | Outcome |
99-
|------|-----------|
100-
| 0 | $y_0$ |
101-
| 1 | $y_1$ |
102-
|$\ldots$ | $\ldots$ |
103-
| T | $y_T$ |
104-
105-
| Frequentist | Bayesian |
106-
|--|--|
107-
| ![](img/interrupted_time_series_skl.svg) | ![](img/interrupted_time_series_pymc.svg) |
108-
109-
> The data (treated and untreated units), pre-treatment model fit, and counterfactual (i.e. the synthetic control) are plotted (top). The causal impact is shown as a blue shaded region. The Bayesian analysis shows shaded Bayesian credible regions of the model fit and counterfactual. Also shown is the causal impact (middle) and cumulative causal impact (bottom).
110-
11194
### Difference in Differences
11295

11396
This is appropriate when you have a single pre and post intervention measurement and have a treament and a control group.

causalpy/data/simulate_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def generate_synthetic_control_data(
6767
return df, weightings_true
6868

6969

70-
def generate_interrupted_time_series_data(
70+
def generate_time_series_data(
7171
N=100, treatment_time=70, beta_temp=-1, beta_linear=0.5, beta_intercept=3
7272
):
7373
x = np.arange(0, 100, 1)

causalpy/pymc_experiments.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ def __init__(
113113
self.post_impact_cumulative = self.post_impact.cumsum(dim="obs_ind")
114114

115115
def plot(self):
116+
116117
"""Plot the results"""
117118
fig, ax = plt.subplots(3, 1, sharex=True, figsize=(7, 8))
118119

@@ -193,21 +194,18 @@ class SyntheticControl(TimeSeriesExperiment):
193194

194195
expt_type = "Synthetic Control"
195196

196-
def plot(self):
197+
def plot(self, plot_predictors=False):
197198
"""Plot the results"""
198199
fig, ax = super().plot()
199-
# plot control units as well
200-
ax[0].plot(self.datapre.index, self.pre_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
201-
ax[0].plot(self.datapost.index, self.post_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
200+
if plot_predictors:
201+
# plot control units as well
202+
ax[0].plot(self.datapre.index, self.pre_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
203+
ax[0].plot(
204+
self.datapost.index, self.post_X, "-", c=[0.8, 0.8, 0.8], zorder=1
205+
)
202206
return (fig, ax)
203207

204208

205-
class InterruptedTimeSeries(TimeSeriesExperiment):
206-
"""A wrapper around the TimeSeriesExperiment class"""
207-
208-
expt_type = "Interrupted Time Series"
209-
210-
211209
class DifferenceInDifferences(ExperimentalDesign):
212210
"""A class to analyse data from Difference in Difference settings.
213211

causalpy/skl_experiments.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ def __init__(self, prediction_model=None, **kwargs):
2121

2222

2323
class TimeSeriesExperiment(ExperimentalDesign):
24-
def __init__(self, data, treatment_time, formula, prediction_model=None, **kwargs):
24+
def __init__(
25+
self,
26+
data,
27+
treatment_time,
28+
formula,
29+
prediction_model=None,
30+
**kwargs,
31+
):
2532
super().__init__(prediction_model=prediction_model, **kwargs)
2633
self.treatment_time = treatment_time
2734
# split data in to pre and post intervention
@@ -141,27 +148,18 @@ def plot_coeffs(self):
141148
)
142149

143150

144-
# InterruptedTimeSeries and SyntheticControl are basically the same thing but with
145-
# different predictor variables. So we just have a TimeSeriesExperiment class and
146-
# InterruptedTimeSeries and SyntheticControl are both equal to the TimeSeriesExperiment
147-
# class
148-
149-
150-
class InterruptedTimeSeries(TimeSeriesExperiment):
151-
"""A wrapper around the TimeSeriesExperiment class"""
152-
153-
pass
154-
155-
156151
class SyntheticControl(TimeSeriesExperiment):
157152
"""A wrapper around the TimeSeriesExperiment class"""
158153

159-
def plot(self):
154+
def plot(self, plot_predictors=False):
160155
"""Plot the results"""
161156
fig, ax = super().plot()
162-
# plot control units as well
163-
ax[0].plot(self.datapre.index, self.pre_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
164-
ax[0].plot(self.datapost.index, self.post_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
157+
if plot_predictors:
158+
# plot control units as well
159+
ax[0].plot(self.datapre.index, self.pre_X, "-", c=[0.8, 0.8, 0.8], zorder=1)
160+
ax[0].plot(
161+
self.datapost.index, self.post_X, "-", c=[0.8, 0.8, 0.8], zorder=1
162+
)
165163
return (fig, ax)
166164

167165

docs/examples.rst

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@ Synthetic Control
66

77
notebooks/sc_pymc.ipynb
88
notebooks/sc_skl.ipynb
9-
10-
11-
Interrupted Time Series
12-
=======================
13-
14-
.. toctree::
15-
:titlesonly:
16-
17-
notebooks/its_pymc.ipynb
18-
notebooks/its_skl.ipynb
9+
notebooks/sc2_pymc.ipynb
10+
notebooks/sc2_skl.ipynb
1911

2012

2113
Difference in Differences

docs/index.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,6 @@ This is appropriate when you have multiple units, one of which is treated. You b
7474

7575
.. image:: ../img/synthetic_control_pymc.svg
7676

77-
Interrupted time series
78-
"""""""""""""""""""""""
79-
80-
This is appropriate when you have a single treated unit, and therefore a single time series, and do not have a set of untreated units.
81-
82-
.. image:: ../img/interrupted_time_series_pymc.svg
83-
8477
Difference in differences
8578
"""""""""""""""""""""""""
8679

0 commit comments

Comments
 (0)