Skip to main content

mlsynth

coverage

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)


Install

pip install -U git+https://github.com/jgreathouse9/mlsynth.git

mlsynth 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 worth knowing:

  • The two extra backends are imported lazily, so import mlsynth and importing any estimator class always works on the base install. The extra is consulted only when you actually call the design optimiser (SYNDES / MAREX) or SPOTSYNTH's Bayesian path; without it those raise a clear error pointing you at the missing package, while everything else runs unchanged.
  • pyscipopt ships prebuilt wheels (bundling SCIP) for the common platforms, so mlsynth[design] is normally a plain pip install with 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.

Quickstart

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.

Estimators

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 $L_\infty$-balanced variants; 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.

Canonical & convex-hull

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

Donor selection / forward

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

High-dimensional / robust / relaxed-hull

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

Factor / time-series / Bayesian

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

SDID family / staggered adoption

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

Spillover / interference (SUTVA)

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

Multiple outcomes / interventions / proximal

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

Matrix completion / missing data

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

Distributional / nonlinear / continuous / IV / micro

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

Experimental design & geo-testing

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
GeoLift Market Selection mlsynth (GeoLift); conformal design — Ben-Michael, Feller & Rothstein (2021); Chernozhukov, Wüthrich & Zhu (2021) GEOLIFT
Multi-cell GeoLift Analysis mlsynth; multi-cell extension of GeoLift MULTICELLGEOLIFT

Contributing

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.

License

mlsynth is open source and distributed under the MIT License.

Metadata

Release files for mlsynth 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mlsynth 1.0.0
File Size Uploaded
mlsynth-1.0.0.tar.gz 1.1 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for mlsynth 1.0.0
File Interpreter ABI Platform
mlsynth-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.4 MB

Release files / mlsynth-1.0.0.tar.gz

Download URL mlsynth-1.0.0.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
a7e7338851bf37191b9f02f475d7eec76b79e8bfee0a73329ac871175a8f6fcd
BLAKE2b-256 checksum
How to use checksums
2de8776aa9c247a309a795b72154afc552f2e31bcf64407bbb105d56c9ec9b03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.

Transparency log

Release files / mlsynth-1.0.0-py3-none-any.whl

Download URL mlsynth-1.0.0-py3-none-any.whl
Size 1.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
90bd26fee339aae0f37f98c790174caa77a6e1f4cde2e4979f1071be8c6bd3c8
BLAKE2b-256 checksum
How to use checksums
de409b9cc04f4a6e36866471f2ef54a02ed024c0993f8f245c4f98971ead9748
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page