mlsynth is a Python framework for synthetic control causal inference and
synthetic-control-based experimental design. It bundles 46 modern estimators
under a single typed Config / .fit() / typed-results interface, so swapping
between, say, Forward DiD, TASC, and SPCD is a one-line change.
Documentation · Which estimator should I use? (decision tree) · Validation — proven against the original code
pip install -U git+https://github.com/jgreathouse9/mlsynth.gitmlsynth supports Python 3.9 and later. The base install pulls in every core
dependency and runs every estimator except two that lean on heavier, specialised
backends. Those two backends are packaged as optional extras, so you only
install the weight you actually use:
| Extra | Adds | Needed for |
|---|---|---|
design |
pyscipopt (the SCIP mixed-integer solver) |
the experimental-design estimators SYNDES and MAREX, whose market-selection step is a MIQP |
bayes |
numpyro (JAX-based MCMC) |
SPOTSYNTH's Bayesian synthetic-control mode |
all |
both of the above | the full feature set |
Request an extra with the usual bracket syntax (quote it so the shell does not glob the brackets):
# SCIP solver for SYNDES / MAREX
pip install -U "mlsynth[design] @ git+https://github.com/jgreathouse9/mlsynth.git"
# NumPyro for SPOTSYNTH's Bayesian mode
pip install -U "mlsynth[bayes] @ git+https://github.com/jgreathouse9/mlsynth.git"
# everything
pip install -U "mlsynth[all] @ git+https://github.com/jgreathouse9/mlsynth.git"A few nuances:
- The two extra backends are imported lazily, so
import mlsynthand importing any estimator class always works on the base install. The extra is consulted only when you actually call the design optimiser (SYNDES/MAREX) orSPOTSYNTH's Bayesian path; without it those raise a clear error pointing you at the missing package, while everything else runs unchanged. pyscipoptships prebuilt wheels (bundling SCIP) for the common platforms, somlsynth[design]is normally a plainpip installwith no separate SCIP system install.- The test suite is a development artifact and is not shipped in the installed
package — clone the repository if you want to run
pytest.
import numpy as np
import pandas as pd
from mlsynth import FDID
rng = np.random.default_rng(0)
N, T1, T2 = 60, 24, 12 # 60 controls, 24 pre, 12 post
T = T1 + T2
def factors(T, rng, burn=200): # f1: AR(1); f2: ARMA(1,1); f3: MA(2)
Tt = T + burn; v = rng.standard_normal((Tt, 3)); f = np.zeros((Tt, 3))
for t in range(1, Tt): f[t, 0] = 0.8 * f[t-1, 0] + v[t, 0]
for t in range(1, Tt): f[t, 1] = -0.6 * f[t-1, 1] + v[t, 1] + 0.8 * v[t-1, 1]
f[1, 2] = v[1, 2] + 0.9 * v[0, 2]
for t in range(2, Tt): f[t, 2] = v[t, 2] + 0.9 * v[t-1, 2] + 0.4 * v[t-2, 2]
f[0, 2] = v[0, 2]
return f[burn:]
sf = factors(T, rng).sum(1) # common factor path
y_tr = 1 + sf + rng.standard_normal(T) # treated: loading 1, true ATT = 0
loads = np.where(np.arange(N) < N // 2, 1.0, 2.0) # first 30 match, last 30 mismatch
Y = 1 + np.outer(sf, loads) + rng.standard_normal((T, N))
rows = [{"unit": "treated", "time": t, "gdp": y_tr[t], "treat": int(t >= T1)}
for t in range(T)]
for j in range(N):
rows += [{"unit": f"c{j}", "time": t, "gdp": Y[t, j], "treat": 0} for t in range(T)]
df = pd.DataFrame(rows)
res = FDID({"df": df, "outcome": "gdp", "treat": "treat",
"unitid": "unit", "time": "time", "display_graphs": False}).fit()
sel = res.fdid.selected_names
matching = sum(int(s[1:]) < N // 2 for s in sel)
print(f"FDID: ATT={res.fdid.att:+.3f} R2={res.fdid.r_squared:.3f} "
f"selected {len(sel)} donors, {matching} from the matching group")
print(f"DID : ATT={res.did.att:+.3f} R2={res.did.r_squared:.3f} (all {N} donors)")The same five df/outcome/unitid/time/treat fields work for every
estimator. Swap FDID for TASC, CLUSTERSC, BVSS, or any other class in the
table below; only the class name and any estimator-specific hyperparameters
change.
mlsynth implements 46 estimator classes spanning the full synthetic-control
landscape. Several classes expose multiple methods through one configuration
(e.g. PDA covers four donor-selection / relaxation variants; RESCM covers
relaxed- and PROXIMAL dispatches several
proximal estimators). Each Class below links to its documentation page; the
estimator name links to the source paper. Not sure which one fits your problem?
Walk the decision tree.
| Estimator | Reference | Class |
|---|---|---|
| Synthetic Control Method (vanilla SCM) | Abadie & Gardeazabal (2003); Abadie, Diamond & Hainmueller (2010), JASA 105(490):493–505 | VanillaSC |
| Two-Step Synthetic Control | Li & Shankar (2024), Management Science 70(6):3734–3755 | TSSC |
| Modified Unbiased Synthetic Control | Bottmer, Imbens, Spiess & Warnick (2024), JBES 42(2):762–773 | MUSC |
| Matching & Synthetic Control (MASC) | Kellogg, Mogstad, Pouliot & Torgovitsky (2021), JASA | MASC |
| Estimator | Reference | Class |
|---|---|---|
| Forward Difference-in-Differences | Li (2024), Marketing Science 43(2):267–279 | FDID |
| Optimal Initial Donor Selection (FSCM) | Cerulli (2024), Economics Letters 244:111976 | FSCM |
| Panel Data Approach (HCW) | Hsiao, Ching & Wan (2012), J. Applied Econometrics | PDA |
| L1-PDA | Li & Bell (2017), J. Econometrics 197(1):65–75 | PDA |
| Forward-Selected Panel Data Approach | Shi & Huang (2023), J. Econometrics 234(2):512–535 | PDA |
| L2-Relaxation | Shi & Wang (2024) | PDA |
| Estimator | Reference | Class |
|---|---|---|
| Principal Component Regression SC | Agarwal et al. (2021), JASA 116(536); Amjad, Shah & Shen (2018) | CLUSTERSC |
| Robust PCA Synthetic Control | Bayani (2022), CUNY Academic Works | CLUSTERSC |
| CLUSTERSC (donor clustering) | Rho, Tang, Bergam, Cummings & Misra (2024), arXiv:2503.21629 | CLUSTERSC |
| Sparse Synthetic Control (L1 predictor selection) | Vives-i-Bastida (2023), Predictor Selection for Synthetic Controls | SparseSC |
| Multivariate Square-root Lasso SC | Shen, Song & Abadie | MSQRT |
| Relaxed Balanced Synthetic Control | Liao, Shi & Zheng (2025), arXiv:2508.01793 | RESCM |
| $L_\infty$ Synthetic Control | Wang, Xing & Ye (2025), arXiv:2510.26053 | RESCM |
| Estimator | Reference | Class |
|---|---|---|
| Factor Model Approach | Li & Sonnier (2023), JMR 60(3):449–472 | FMA |
| Harmonic Synthetic Control | Liu & Xu (2026), The Harmonic Synthetic Control Method | HSC |
| Time-Aware Synthetic Control | Rho, Illick, Narasipura, Abadie, Hsu & Misra (2026), arXiv:2601.03099 | TASC |
| Synthetic Business Cycle | Shi, Xi & Xie (2025), arXiv:2505.22388 | SBC |
| Bayesian SC with Soft Simplex Constraint | Xu & Zhou (2025), arXiv:2503.06454 | BVSS |
| Dynamic SC for Auto-Regressive Processes | Zheng & Chen (2024), JRSS-B 86(1):155–176 | DSCAR |
| Estimator | Reference | Class |
|---|---|---|
| Synthetic Difference-in-Differences | Arkhangelsky, Athey, Hirshberg, Imbens & Wager (2021), AER 111(12):4088–4118 | SDID |
| Sequential Synthetic Difference-in-Differences | Arkhangelsky & Samkov (2025), arXiv:2404.00164 | SequentialSDID |
| Partially Pooled SCM (staggered) | Ben-Michael, Feller & Rothstein (2022), JRSS-B 84(2):351–381 | PPSCM |
| Staggered Synthetic Control | Cao, Lu & Wu | SSC |
| Rolling-Transformation DiD | Lee & Wooldridge (2026), J. Applied Econometrics | ROLLDID |
| Estimator | Reference | Class |
|---|---|---|
| SCM with Spillover Effects | Cao & Dowd (2023) | SPILLSYNTH |
| Spatial Synthetic Difference-in-Differences | Serenini & Masek (2024), SSRN 4736857 | SpSyDiD |
| Imperfect Synthetic Controls | Powell (2026), J. Applied Econometrics 41(3):253–264 | ISCM |
| Spillover-Detecting Synthetic Control | Gilligan-Lee (2025); Zeitler et al. (2023) | SPOTSYNTH |
| Estimator | Reference | Class |
|---|---|---|
| SCM with Multiple Outcomes | Tian, Lee & Panchenko (2023), arXiv:2304.02272 | SCMO |
| Synthetic Interventions | Agarwal, Shah & Shen (2026), Operations Research | SI |
| Proximal SCM Framework | Shi, Li, Miao, Hu & Tchetgen Tchetgen (2023), arXiv:2108.13935 | PROXIMAL |
| Proximal SC with Surrogates | Liu, Tchetgen Tchetgen & Varjão (2023), arXiv:2308.09527 | PROXIMAL |
| Single Proxy Synthetic Control | Park & Tchetgen Tchetgen (2025), J. Causal Inference | PROXIMAL |
| Doubly Robust Proximal Synthetic Controls | Qiu, Shi, Miao, Dobriban & Tchetgen Tchetgen (2024), Biometrics 80(2) | PROXIMAL |
| Estimator | Reference | Class |
|---|---|---|
| Matrix Completion with Nuclear Norm Minimization | Athey, Bayati, Doudchenko, Imbens & Khosravi (2021), JASA 116(536) | MCNNM |
| Synthetic Nearest Neighbors / Causal Matrix Completion | Agarwal, Dahleh, Shah & Shen (2021), arXiv:2109.15154 | SNN |
| Robust Matrix estimation with Side Information | Agarwal, Choi & Yuan | RMSI |
| Estimator | Reference | Class |
|---|---|---|
| Distributional Synthetic Controls | Gunsilius (2023), Econometrica 91(3):1105–1117 | DSC |
| SCM with Nonlinear Outcomes | Tian (2023), arXiv:2306.01967 | NSC |
| Continuous-Treatment Synthetic Control | Powell (2022), JBES 40(3):1302–1314 | CTSC |
| Synthetic IV Estimation in Panels | Gulek & Vives-i-Bastida (2024), Job Market Paper | SIV |
| Micro-level Balancing Synthetic Control | Robbins & Davenport (2021), J. Statistical Software 97(2) | MicroSynth |
| Synthetic Control with Disaggregated Data | Bottmer (2026), Stanford job-market paper | MLSC |
| Synthetic Historical Control | Chen, Yang & Yang (2024), SSRN 4995085 | SHC |
| Estimator | Reference | Class |
|---|---|---|
| Synthetic Controls for Experimental Design | Abadie & Zhao (2026) | MAREX |
| Synthetic Design (optimization approach) | Doudchenko, Khosravi, Pouget-Abadie, Lahaie, Lubin, Mirrokni, Spiess & Imbens (2021) | SYNDES |
| Lexicographic Synthetic Control (validity → power) | Abadie & Zhao (2026); Vives-i-Bastida (2022) | LEXSCM |
| Synthetic Principal Component Design | Lu, Li, Ying & Blanchet (2022), arXiv:2211.15241 | SPCD |
| Parallel-Trends Supergeo Design | mlsynth (PANGEO), extending Supergeo Design — Chen, Doudchenko, Jiang, Stein & Ying (2023) |
PANGEO |
Fixes are always welcome. For new estimators, inference tests, or larger changes, please email Jared first. Estimators currently on the development list include continuous-treatment synthetic controls, Bayesian factor SCMs, random-forest-based SCMs, simplex-weight inference, and prediction-interval refinements.
Whatever change is proposed, it must reproduce either a canonical benchmark application from the SCM literature (Basque Country, California Proposition 99, or West Germany reunification) or the empirical findings reported in the originating methodological paper. Continuous integration runs the unit test suite, a fresh-install smoke check, and coverage reporting on every pull request.
In addition to code, you can also develop tutorials, presentations, and
educational materials using mlsynth, promote it on LinkedIn or in the
classroom, and help with outreach and onboarding new contributors.
mlsynth is open source and distributed under the MIT License.