Stata and Python implementations of the estimator in Grier (2026),
"Correlated Weights: Partial Pooling for Synthetic Control with Multiple
Outcomes" (working paper: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=7149398; PDF: correlated_weights_wp.pdf
in this repository).
A study that applies the synthetic control method to several outcomes
faces a choice: fit each outcome its own donor weights, or impose one
common set on all of them. ppsynth makes the middle available. Each
outcome gets its own weights, their dispersion around a common centroid
is penalized, no single penalty is ever selected (the estimator
aggregates over a grid by leave-one-out exponential weighting), and the
resulting mass profile reports how much pooling the data support. One
command returns the per-outcome effects, the weights, the mass profile,
and whole-pipeline placebo p-values.
- Download this repository (green Code button, Download ZIP) and unzip. Everything lives in one flat folder, which is exactly what Stata wants; keep it that way.
- In Stata,
cdinto that folder (or put it on your adopath). - Run once:
ppsynth_setupThis checks the Stata-Python binding, installs the numerical dependencies, self-tests both engines, and warms the numba cache. - Try it:
do ppsynth_example.do(usesgermany_panel.dta, included).
Requires Stata 16+ with Python integration configured (Python
3.10-3.13). ppsynth_setup diagnoses and repairs the common binding
problems, including obsolete system-Python bindings, and prints exact
instructions when it cannot repair automatically.
ppsynth_core.py (pure NumPy) and ppsynth_fast.py (numba, substantially
faster and the one the Stata command uses) are importable directly. The two
run one shared block of solver settings and return identical results:
from ppsynth_core import fit_ppsynth
fit = fit_ppsynth(Y_treated, Y_donors, T0=20, method="aggregate")ppsynth outcome1 outcome2 outcome3, trunit(#) trperiod(#) ///
id(id) time(year) inferenceOutput: per-outcome effects on the original scale, the aggregated
weights, the mass profile over the pooling grid (the data's verdict on
how much the outcomes share donor structure), and per-outcome + joint
placebo p-values. help ppsynth documents every option, including
method(cv) for the cross-validation companion, saving() for graphs,
and the fittability guardrail.
The placebo loop reruns the entire pipeline for every unit and blocks
Stata's interface for its full duration (typically 1-5 minutes; macOS
shows a spinning beachball, Windows shows "not responding" and offers
to kill the program — on Windows, all output appears only when the run
completes). This is normal. The computation is proceeding. Do not
close Stata; the command returns on its own. Details: help ppsynth,
Troubleshooting.
-
ppsynth 2.6.1 (2026-08-25): metadata-only. Moved the full version history out of the ado's starred header (which -which- prints in full) into CHANGELOG.md; -which ppsynth- now shows a two-line banner. Corrected the help file's stale internal version stamp. No numerical or behavioral change; engines identical to 2.6.0.
-
ppsynth 2.6.0 (2026-08-12): current. The default display now leads with realized weight pooling (percent reduction in weight dispersion relative to separate fitting) and the middle 50% of predictive mass on the pooling scale. The lambda-grid mass table moved behind the new
massprofileoption, with per-expert pooling percentages and a note that the pooling delivered by a given lambda is panel-specific. New returns:r(realized_pooling),r(pooling_q25),r(pooling_q75),r(pooling_grid). Reporting only; the estimator is unchanged. -
ppsynth 2.5.3 (2026-08-01): Adds the donor-support check, which flags any pre-treatment period in which the treated unit falls outside the donor range (report-only, on by default, returned in
r(support_warning)). The pure-NumPy engine's solver settings now match the numba engine's, so the two return bit-identical results. -
ppsynth 2.5.1 (2026-07-18): Stata front end + numba engine with pure-NumPy fallback, exact corner solutions, aggregation default, whole-pipeline placebo inference, fittability guardrail.
-
Version history and design rationale: Appendix B of the paper.
If you use ppsynth, please cite the working paper (CITATION.cff has the metadata; a BibTeX entry is in the paper PDF's first-page footnote).
MIT. See LICENSE.