Fast synthetic control tooling with two estimator families:
PenguinSynth: lean, adelie-backed regularized estimators for long-format panel dataSynth: full, pyensmallen-backed estimators for matrix-format workflows and inference
Check the notebooks/ directory for synthetic and real-data examples.
Features are indicated by:
- pending
- implemented
- unit weights
- simplex
- lasso
- ridge
- matching
- intercept support
- entropy weights
- multiple treated units with aggregate or granular matching
- time weights for SDID
- time-distance penalized weights
- matrix completion augmentation
- latent factor models
- two-way kernel ridge weights
- jackknife confidence intervals
- permutation tests
- conformal inference
- treated versus synthetic trajectories
- treatment-effect event studies
- weight plots
For local development:
git clone https://github.com/apoorvalal/synthlearners.git
cd synthlearners
uv sync --extra full --extra test --extra docsFor the adelie-backed API:
uv add synthlearnersLean installs expose:
PenguinSynthPenguinResultsPenguinSynth(method="synth")PenguinSynth(method="sdid")PenguinSynth(method="did")
For the traditional synthetic-control stack and auxiliary utilities:
uv sync --extra fullIf you are adding the package to another project instead of working from source:
uv add "synthlearners[full]"Full installs add:
SynthSynthResultsDynamicBalanceDynamicBalanceResultsSynth(method="simplex")Synth(method="linear")Synth(method="lp_norm")Synth(method="matching")Synth(method="matrix_completion")Synth(method="sdid")DynamicBalance.fit(...)for exact treatment-history contrastsPanelCrossValidatorand related cross-validation utilities
MatrixCompletionEstimator is available from synthlearners.mcnnm; it is not exported from the package root.
Static API docs are generated with pdoc into docs/.
uv sync --extra full --extra docs
./scripts/build_docs.shfrom synthlearners import PenguinSynth
estimator = PenguinSynth(method="synth", l1_ratio=0.0)
result = estimator.fit(df, "unit", "time", "treatment", "outcome")
print(f"Treatment effect: {result.att:.3f}")from synthlearners import DynamicBalance, Synth, PenguinSynth
synth = Synth(method="simplex")
result = synth.fit(Y, treated_units=15, T_pre=10)
penguin = PenguinSynth(method="synth", l1_ratio=0.5)
result = penguin.fit(df, "unit", "time", "treatment", "outcome")
dynbal = DynamicBalance(l1_ratio=0.0)
res = dynbal.fit(
df=df,
unit_id="unit",
time_id="time",
treatment="treatment",
outcome="outcome",
covariates=["x", "lag_outcome"],
target_history=[1, 1],
reference_history=[0, 0],
)PenguinSynth is the faster default path for regularized estimation.
Synth carries the broader constrained-optimization toolbox, matrix completion support, and inference utilities that rely on the full dependency set.