Inference methods for synthetic control and related methods
Project description
scinference
A Python package for inference methods for synthetic control and related methods.
This is a Python port of the R scinference package by Victor Chernozhukov, Kaspar Wuthrich, and Yinchu Zhu.
Installation
pip install scinference
Validation Against R Package
All results in this README are generated using data from the original R package to demonstrate that Python and R produce identical results.
Example 1: Conformal Inference
Conformal inference works with a small number of post-treatment periods and provides valid p-values and confidence intervals.
Data
We use simulated data generated by the R package with set.seed(12345):
- J = 50 control units
- T0 = 50 pre-treatment periods
- T1 = 5 post-treatment periods
- True treatment effect = 2
import numpy as np
from scinference import scinference
# Load data (generated by R for exact comparison)
# Y0: control outcomes (T x J matrix)
# Y1: treated outcome (T x 1 vector)
T0, T1 = 50, 5
Testing a Null Hypothesis
We test the null hypothesis H0: theta = (4, 4, 4, 4, 4)'. Since the true effect is 2, this is a false null and we expect to reject it.
# Synthetic Control with Moving Block permutations
result_sc = scinference(Y1, Y0, T1=T1, T0=T0, theta0=4,
estimation_method="sc", permutation_method="mb")
# Difference-in-Differences
result_did = scinference(Y1, Y0, T1=T1, T0=T0, theta0=4,
estimation_method="did", permutation_method="mb")
# Constrained Lasso
result_classo = scinference(Y1, Y0, T1=T1, T0=T0, theta0=4,
estimation_method="classo", permutation_method="mb")
Results: P-values for H0: theta = 4 (Moving Block Permutations)
| Method | Python | R | Match |
|---|---|---|---|
| Synthetic Control | 0.018182 | 0.018182 | YES |
| Difference-in-Diff | 0.036364 | 0.036364 | YES |
| Constrained Lasso | 0.036364 | 0.036364 | YES |
All three methods reject the false null at the 5% level.
Pointwise Confidence Intervals
Compute 90% pointwise confidence intervals using the synthetic control method:
result_ci = scinference(Y1, Y0, T1=T1, T0=T0,
estimation_method="sc",
ci=True,
ci_grid=np.arange(-2, 8.1, 0.1),
alpha=0.1)
print("90% Confidence Intervals:")
for t in range(T1):
print(f" Period {t+1}: [{result_ci['lb'][t]:.2f}, {result_ci['ub'][t]:.2f}]")
Results: 90% Pointwise Confidence Intervals
| Period | Python LB | R LB | Python UB | R UB | Match |
|---|---|---|---|---|---|
| 1 | 0.80 | 0.80 | 4.10 | 4.10 | YES |
| 2 | 1.50 | 1.50 | 4.60 | 4.60 | YES |
| 3 | 0.40 | 0.40 | 4.00 | 4.00 | YES |
| 4 | 1.80 | 1.80 | 5.20 | 5.20 | YES |
| 5 | -0.50 | -0.50 | 2.60 | 2.60 | YES |
The true treatment effect (2) is covered by the confidence intervals in all periods.
Example 2: T-test Based Inference
The t-test method requires a larger number of post-treatment periods and provides estimates of the Average Treatment Effect on the Treated (ATT).
Data
Data generated by R with set.seed(12345):
- J = 30 control units
- T0 = 30 pre-treatment periods
- T1 = 30 post-treatment periods
- True ATT = 2
# T-test with K=2 cross-fits
result = scinference(Y1, Y0, T1=T1, T0=T0,
inference_method="ttest", K=2, alpha=0.1)
print(f"ATT estimate: {result['att']:.4f}")
print(f"Standard Error: {result['se']:.4f}")
print(f"90% CI: [{result['lb']:.4f}, {result['ub']:.4f}]")
Results: T-test with Synthetic Control (K=2)
| Metric | Python | R | Match |
|---|---|---|---|
| ATT | 1.488715 | 1.488715 | YES |
| Standard Error | 0.292220 | 0.292220 | YES |
| 90% CI Lower | -0.356287 | -0.356287 | YES |
| 90% CI Upper | 3.333716 | 3.333716 | YES |
Results: T-test with Synthetic Control (K=3)
result_K3 = scinference(Y1, Y0, T1=T1, T0=T0,
inference_method="ttest", K=3, alpha=0.1)
| Metric | Python | R | Match |
|---|---|---|---|
| ATT | 1.526818 | 1.526818 | YES |
| Standard Error | 0.194858 | 0.194858 | YES |
| 90% CI Lower | 0.957835 | 0.957835 | YES |
| 90% CI Upper | 2.095801 | 2.095801 | YES |
Results: T-test with Difference-in-Differences (K=2)
result_did = scinference(Y1, Y0, T1=T1, T0=T0,
inference_method="ttest",
estimation_method="did", K=2, alpha=0.1)
| Metric | Python | R | Match |
|---|---|---|---|
| ATT | 1.624656 | 1.624656 | YES |
| Standard Error | 0.192063 | 0.192063 | YES |
| 90% CI Lower | 0.412019 | 0.412019 | YES |
| 90% CI Upper | 2.837293 | 2.837293 | YES |
All methods produce estimates close to the true ATT of 2, with the true value covered by the confidence intervals.
API Reference
Main Function
scinference(Y1, Y0, T1, T0,
inference_method="conformal",
alpha=0.1,
ci=False,
theta0=0,
estimation_method="sc",
permutation_method="mb",
ci_grid=None,
n_perm=5000,
K=2)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
Y1 |
array | Required | Outcome for treated unit (T x 1) |
Y0 |
array | Required | Outcomes for control units (T x J) |
T1 |
int | Required | Number of post-treatment periods |
T0 |
int | Required | Number of pre-treatment periods |
inference_method |
str | "conformal" | "conformal" or "ttest" |
alpha |
float | 0.1 | Significance level |
ci |
bool | False | Compute confidence intervals (conformal) |
theta0 |
float/array | 0 | Null hypothesis value |
estimation_method |
str | "sc" | "did", "sc", or "classo" |
permutation_method |
str | "mb" | "mb" (moving block) or "iid" |
ci_grid |
array | None | Grid for CI computation |
n_perm |
int | 5000 | Permutations for IID method |
K |
int | 2 | Number of cross-fits (t-test) |
Returns
Conformal inference:
p_val: p-value for the null hypothesislb: lower bounds of pointwise CIs (ifci=True)ub: upper bounds of pointwise CIs (ifci=True)
T-test:
att: Average Treatment Effect on the Treatedse: Standard errorlb: Lower bound of confidence intervalub: Upper bound of confidence interval
Estimation Methods
| Method | Description |
|---|---|
did |
Difference-in-differences (simple average of controls) |
sc |
Synthetic control (Abadie et al.) - constrained weighted average |
classo |
Constrained lasso - L1-penalized with sum-to-one constraint |
References
-
Chernozhukov, V., Wuthrich, K., & Zhu, Y. (2021). "An Exact and Robust Conformal Inference Method for Counterfactual and Synthetic Controls." Journal of the American Statistical Association. arXiv:1712.09089
-
Chernozhukov, V., Wuthrich, K., & Zhu, Y. (2019). "Practical and robust t-test based inference for synthetic control and related methods." arXiv:1812.10820
License
GPL-3.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scinference-0.1.0.tar.gz.
File metadata
- Download URL: scinference-0.1.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b96898da2b3e10ff5f89513111045bc603184804c57900e04574058b5aca0c6
|
|
| MD5 |
1d55bfc2350114c207222d004608354e
|
|
| BLAKE2b-256 |
b2c631361f75204522050e2a6ed474fd447e114314aa661b73c55657523b591a
|
Provenance
The following attestation bundles were made for scinference-0.1.0.tar.gz:
Publisher:
publish.yml on anzonyquispe/scinference
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scinference-0.1.0.tar.gz -
Subject digest:
4b96898da2b3e10ff5f89513111045bc603184804c57900e04574058b5aca0c6 - Sigstore transparency entry: 842947484
- Sigstore integration time:
-
Permalink:
anzonyquispe/scinference@5d39c87007d713cf5813667e7f7cc96d065bb274 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/anzonyquispe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5d39c87007d713cf5813667e7f7cc96d065bb274 -
Trigger Event:
release
-
Statement type:
File details
Details for the file scinference-0.1.0-py3-none-any.whl.
File metadata
- Download URL: scinference-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ca216d3313a8e70e327d5110ff6083193b53a2c97432162842e0d34207fb301
|
|
| MD5 |
d84e8a5bf3a1a747386f64177546601c
|
|
| BLAKE2b-256 |
f1a42bce47e085d34b01860d0cd18a0f29b8a9feb6d0af2849b7e832705e3429
|
Provenance
The following attestation bundles were made for scinference-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on anzonyquispe/scinference
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scinference-0.1.0-py3-none-any.whl -
Subject digest:
5ca216d3313a8e70e327d5110ff6083193b53a2c97432162842e0d34207fb301 - Sigstore transparency entry: 842947489
- Sigstore integration time:
-
Permalink:
anzonyquispe/scinference@5d39c87007d713cf5813667e7f7cc96d065bb274 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/anzonyquispe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5d39c87007d713cf5813667e7f7cc96d065bb274 -
Trigger Event:
release
-
Statement type: