# tfcausalimpact: Google's Causal Impact algorithm in Python

> tfcausalimpact ports the Causal Impact method from Google's R package to Python on top of TensorFlow Probability, so a team can estimate the effect of an intervention from a pre-period baseline and covariates. The default fit is variational inference, the summary reports a posterior rather than a point estimate, and the package version is still 0.0.x.

**WillianFuks/tfcausalimpact** — Python Causal Impact Implementation Based on Google's R Package. Built using TensorFlow Probability.

- Repository: https://github.com/WillianFuks/tfcausalimpact
- Stars: 679 · Forks: 75
- Language: Python
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/willianfuks-tfcausalimpact

## A Python port of the method Google wrote in R

Causal Impact is an algorithm for estimating the effect of an intervention on a metric, and the reference implementation is an R package. tfcausalimpact reimplements that algorithm in Python on top of TensorFlow Probability, which is what makes it usable inside an existing Python data stack rather than requiring an R subprocess. The mechanism is a Bayesian structural time series. The model is fitted on the period before the intervention, using the observed series and a set of covariates, and the fit is then used to predict what the metric would have looked like without the intervention. The counterfactual prediction is compared against what was actually observed, and the gap is the estimated effect. The intervention is usually the start or stop of something, such as a marketing campaign that begins on a given date. The audience is analysts who already have a pre-period of history and a set of control variables, and who want a probabilistic answer rather than a before-and-after average.

## Four inputs define the question: y, X, pre_period and post_period

The API is small, and the four arguments are the whole contract. The observed series y is the metric you care about. The covariates X are the other series that help the model, and they enter through a linear regression inside the fit, which is the mechanism that turns a noisy pre-period into a usable counterfactual. The pre_period selects everything that happened before the intervention and is the window the model learns from. The post_period covers the data after the intervention, which is what gets compared against the prediction. Choosing the pre-period is the decision that determines whether the result means anything, because a pre-period that contains the effect itself or that does not resemble the post-period will produce a confident and wrong number. The documentation points to an introductory notebook in the repository and a Medium article for the ideas behind the library, and it recommends a recorded presentation by Kay Brodersen, one of the creators of the R implementation.

## The summary reports a posterior, not a point estimate

The printed summary is a distribution rather than a single number, and that changes how it should be read:

```
Posterior Inference {Causal Impact}
                          Average            Cumulative
Actual                    125.23             3756.86
Prediction (s.d.)         120.34 (0.31)      3610.28 (9.28)
95% CI                    [119.76, 120.97]   [3592.67, 3629.06]

Absolute effect (s.d.)    4.89 (0.31)        146.58 (9.28)
95% CI                    [4.26, 5.47]       [127.8, 164.19]

Relative effect (s.d.)    4.06% (0.26%)      4.06% (0.26%)
95% CI                    [3.54%, 4.55%]     [3.54%, 4.55%]

Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%
```

The average and cumulative views of the same effect are both reported, with the standard deviation and a 95 percent credible interval attached to the prediction, the absolute effect and the relative effect. The last two lines are the decision aids: a tail-area probability and the posterior probability of any causal effect at all. A run where the credible interval of the absolute effect spans zero is a different claim from one where it does not, and the summary gives you both in a form that can be pasted into a report. The plot method produces the familiar chart of actual against predicted with the effect band. The example in the documentation adds five units to the second half of a synthetic series and reads the effect back out of the summary.

## Variational inference is the default fit, with HMC available

The performance section states that the package uses Variational Inference from TensorFlow Probability by default, because it is faster and should work for most cases. The alternative is set through the model arguments, and the comparison example in the documentation passes it explicitly:

```python
ci = CausalImpact(data, pre_period, post_period, model_args={'fit_method': 'hmc'})
```

The fit method is therefore a per-run decision rather than a global setting, and the two produce slightly different posteriors on the same data. That difference is visible in the comparison the project publishes. Running the same comparison_data.csv fixture in the R package gives a relative effect of -0.83% with a 95 percent interval of [-2.6%, 1%], a tail-area probability of 0.20061 and a posterior probability of a causal effect of 80%. The Python run, using the hmc fit method, gives -0.89% with an interval of [-2.68%, 0.91%], a tail-area probability of 0.16 and a posterior probability of 84.12%. The project states that both results are equivalent, which is true in the sense that matters: the sign, the magnitude and the confidence interval all agree, and none of the differences change the conclusion.

## Running the example, and the shape of the API call

The minimal run takes a dataframe with the series and the covariates, the two periods, and then asks for a summary, a report and a plot:

```python
import pandas as pd
from causalimpact import CausalImpact


data = pd.read_csv('https://raw.githubusercontent.com/WillianFuks/tfcausalimpact/master/tests/fixtures/arma_data.csv')[['y', 'X']]
data.iloc[70:, 0] += 5

pre_period = [0, 69]
post_period = [70, 99]

ci = CausalImpact(data, pre_period, post_period)
print(ci.summary())
print(ci.summary(output='report'))
ci.plot()
```

The class is imported from a module named causalimpact even though the distribution on PyPI is called tfcausalimpact, which is worth knowing before searching for the import in a codebase. The two summary calls differ only in output mode, with the report form printing the extra detail line that refers back to the report summary command. The fixture used here is the same synthetic series that appears in the original R implementation, which makes the printed output comparable with the R documentation. The repository also holds a notebooks/ directory with a getting started notebook and a comparison folder that contains both the R and the Python plots.

## Dependencies are pinned tightly enough to matter

The package installs with pip, and the requirements are listed in the documentation and again in setup.py:

```bash
    pip install tfcausalimpact
```

The supported Python versions run from 3.8 through 3.13. The runtime dependencies are TensorFlow 2.10 or later, TensorFlow Probability 0.18 or later, pandas 1.3.5 or later, matplotlib and jinja2, and setup.py narrows two of them further, with pandas capped at 2.2.3 and tensorflow-probability at 0.25. Those upper bounds are the practical constraint of this package, because a shared environment that already carries a newer pandas or a newer TensorFlow Probability will need a separate environment. The test suite is where the packaging metadata shows its age and its discipline at the same time: setup.py lists pytest, pytest-cov, mock, pytest-xdist and tox under tests_require, while the repository carries pytest.ini, tox.ini, .coveragerc and .flake8 at the root, and a stubs/ directory for type information. To run the tests without installing Python or the dependencies on the host, the documentation points at a container script:

```bash
./scripts/test_docker.sh 3.13
```

The version argument is optional and defaults to Python 3.13.

## A 0.0.x package with a clear boundary around its scope

The version line is the clearest statement about the maturity of the API. The recent releases are v0.0.19 from 2026-09-20, v0.0.18 from 2025-01-13 and v0.0.17 from 2024-10-19, and the last push was on 2026-09-20. A 0.0.x series means the public surface can change between patch releases, so pinning is the only safe approach for a production pipeline. The scope is also narrow in a way that is easy to mistake for a limitation of the method rather than of the implementation. The algorithm assumes you can model the counterfactual from the pre-period alone, and it does not attempt to design the experiment: there is no randomisation, no holdout, no treatment assignment logic. When the pre-period is not comparable to the post-period, the output is a confident number with a wide interval rather than an error. The library is Apache-2.0 licensed, the build is a classic setup.py with a build_wheels.sh script invoked for publishing, and the project publishes to PyPI under the tfcausalimpact name.

## Conclusion

tfcausalimpact suits Python teams that already have a pre-intervention series and control variables and want the Causal Impact method without an R toolchain, since the summary and plot output match the R package in structure. Do not reach for it if the question needs a causal design rather than a pre-period fit, since the method assumes you can model the counterfactual from the past. Before adopting, check the pandas and TensorFlow Probability bounds in setup.py, where pandas is capped at 2.2.3 and tensorflow-probability at 0.25, and pin accordingly.

## FAQ

### How do I install tfcausalimpact?

Install it with pip install tfcausalimpact from PyPI. The supported Python versions are 3.8 through 3.13, and the runtime dependencies include TensorFlow 2.10 or later and TensorFlow Probability 0.18 or later.

### What do pre_period and post_period do in tfcausalimpact?

The pre_period selects the observations before the intervention, and that window is what the model is fitted on, together with the observed series y and the covariates X. The post_period holds the data after the intervention, which is compared against the counterfactual prediction to extract the effect.

### Does the Python version of Causal Impact give the same answer as the R package?

The project states that both packages should give equivalent results, and publishes the comparison side by side on the same fixture. The Python run in that example uses the hmc fit method and reports a relative effect of -0.89% against the R result of -0.83%, with the same sign and overlapping intervals.

### How do I change the inference method in tfcausalimpact?

The fit method is passed through model_args, for example model_args={'fit_method': 'hmc'}. The default is Variational Inference from TensorFlow Probability, which the documentation describes as faster and expected to work for most cases.

### Can I run the tfcausalimpact test suite without installing Python locally?

Yes. The documentation points to a Docker script for that, ./scripts/test_docker.sh 3.13, where the version argument is optional and defaults to Python 3.13.

## Sources

- [Issues](https://github.com/WillianFuks/tfcausalimpact/issues)
- [License: Apache-2.0](https://github.com/WillianFuks/tfcausalimpact/blob/master/LICENSE)
- [README](https://github.com/WillianFuks/tfcausalimpact/blob/master/README.md)
- [Releases](https://github.com/WillianFuks/tfcausalimpact/releases)
- [WillianFuks/tfcausalimpact on GitHub](https://github.com/WillianFuks/tfcausalimpact)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/willianfuks-tfcausalimpact
