from _api_doc_utils import *SyntheticControl
Single-treated-unit donor weighting
1 Where it fits
Group: Causal inference
SyntheticControl fits nonnegative donor weights that sum to one, minimizing pre-treatment imbalance between the treated path and a convex combination of donor paths:
\[ \min_{w\ge 0,\;1'w=1}\|y_{\mathrm{treated,pre}} - Y_{\mathrm{donor,pre}}w\|_2^2. \]
It is the lower-level single-path API; the panel estimators use the newer fit(Y, W) contract.
2 Python API
Constructor: cm.SyntheticControl
Call fit(donors, treated) where donors is (n_periods, n_donors) and treated is the treated pre-period vector. predict(donors) applies the learned weights to a donor matrix. summary() reports weights and pre-fit RMSE.
print(inspect.signature(cm.SyntheticControl))(max_iterations=500)
cls = cm.SyntheticControl
display(HTML(html_table(["Public method"], public_methods(cls))))| Public method |
|---|
bootstrap(self, /, n_bootstrap, seed=None) |
fit(self, /, donors, treated) |
predict(self, /, donors) |
summary(self, /) |
3 Minimal example
rng=np.random.default_rng(15)
donors=rng.normal(size=(40,4)); w_true=np.array([.45,.25,.2,.1]); treated=donors@w_true+rng.normal(scale=.02,size=40)
model=cm.SyntheticControl(max_iterations=500); model.fit(donors, treated)
print(model.summary()["weights"])
print(model.predict(donors[-3:]))[0.45260904 0.25299333 0.19448108 0.09991655]
[ 0.54589872 0.43772007 -0.93213339]
4 summary() contract
The table below is generated by fitting the live class in this repository and then inspecting summary(). Shapes are shown because most values are plain NumPy arrays or scalars.
rng=np.random.default_rng(115); donors=rng.normal(size=(30,4)); treated=donors@np.array([.45,.25,.2,.1])
model=cm.SyntheticControl(max_iterations=300); model.fit(donors,treated)
summary = model.summary()
display(HTML(html_table(["summary() key", "shape"], summary_shape_rows(summary))))| summary() key | shape |
|---|---|
weights |
(4,) |
pre_rmse |
() |