| scm_balance_frontier | R Documentation |
Traces how the two pre-treatment imbalances of partially pooled SCM trade
off as the pooling parameter nu varies: q_pool, the imbalance of the
average of the treated units, which the aggregate ATT rests on, and
q_sep, the root mean square of the per-block imbalances, which the
block-level effects rest on. Both are the cohort-level measures of
Ben-Michael, Feller & Rothstein (2022, Appendix A.2), in which a block
enters through the sum over its treated units, so a block of n_g
units counts n_g times towards q_pool and n_g^2 times towards
q_sep. Supplying weights to scm_fit() replaces the unit count with
the mass it gives them, and the frontier is traced on that same objective.
scm_balance_frontier(fit, nu_grid = seq(0, 1, length.out = 11L))
fit |
A staggered |
nu_grid |
Values of |
Ben-Michael, Feller & Rothstein (2022) call this plot "an important tool for
using partially pooled SCM in practice" (S.4.2): the curve is strongly
convex, so a little pooling usually buys a large reduction in one imbalance
for a small rise in the other, and where that bargain stops being worth it
is a judgement the data can inform but not settle. Their nu heuristic,
which scm_fit() uses by default, is one point on this curve.
A fit made with cov_method = "balance" is traced on the objective that
includes its covariate term, and the frontier reports that term's two
measures in q_cov_sep and q_cov_pool. The plot still draws the outcome
imbalances, which are then only part of what the fit trades off.
A data.frame of class scm_frontier, one row per nu, with
nu, q_sep, q_pool, their values normalised by the separate solution
(q_sep_rel, q_pool_rel), estimate, and heuristic marking the row
closest to the fit's own nu. A fit made with cov_method = "balance"
trades off a covariate imbalance as well, so its frontier carries
q_cov_sep and q_cov_pool too, and the two normalisation constants are
then the combined measure of the paper's footnote 7 rather than the
outcome imbalance alone – which is why q_sep_rel and q_pool_rel are
not 1 at nu = 0 there. Plot it with plot().
Ben-Michael, E., Feller, A., & Rothstein, J. (2022). Synthetic controls with staggered adoption. JRSS-B, 84(2), 351-381.
set.seed(1)
panel <- expand.grid(unit = 1:15, year = 1:20)
adopt <- c(`1` = 12, `2` = 15, `3` = 17)
panel$treated <- as.integer(!is.na(adopt[as.character(panel$unit)]) &
panel$year >= adopt[as.character(panel$unit)])
panel$treated[is.na(panel$treated)] <- 0L
panel$gdp <- panel$unit + 0.4 * panel$year +
rnorm(nrow(panel)) + 2 * panel$treated
fit <- scm_fit(gdp ~ treated | unit + year, data = panel, method = "scm")
fr <- scm_balance_frontier(fit, nu_grid = c(0, 0.5, 1))
fr
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.