scm_rank_pval: Rank-Based Permutation Test for Several Treated Units

View source: R/scm_rank.R

scm_rank_pvalR Documentation

Rank-Based Permutation Test for Several Treated Units

Description

Permutation inference on the aggregate effect when more than one unit is treated, following Abadie & L'Hour (2021, S.3.2). Each treated unit contributes its own test statistic; the identities of the treated units are then reassigned at random among all units, and the sum of the ranks of the real treated units' statistics is compared with its permutation distribution.

Usage

scm_rank_pval(
  fit,
  B = 500L,
  statistic = c("mspe_ratio", "effect", "abs_effect"),
  alternative = c("two.sided", "greater", "less"),
  seed = 1L
)

Arguments

fit

A coresynth object from scm_fit() with method = "scm" and more than one treated unit.

B

Number of treatment reassignments.

statistic

Per-unit statistic to rank. "mspe_ratio" (default) is the post/pre MSPE ratio of Abadie, Diamond & Hainmueller (2010), which adjusts for how well each unit was fitted; "effect" is the mean post-treatment gap and "abs_effect" its absolute value.

alternative

"two.sided" (default), "greater", or "less".

seed

Seed for the reassignment draw, so the p-value is reproducible without consuming the caller's RNG state.

Details

Ranking is what makes the test usable here. mspe_ratio_pval() compares one treated unit against placebo runs on single donors, which breaks down as soon as the treated series is an average: the average is less noisy than any single donor, so its pre/post MSPE ratio is inflated and the test rejects far too often. Ranks sidestep that, because every statistic entering the comparison, real or permuted, is computed on a single unit.

The fit must expose per-unit effects, so a staggered fit has to be made with pool_cohorts = FALSE. A sharp fit with several treated units pools them by design, and its per-unit statistics are computed here from the stored per-unit series.

Value

An object of class c("scm_rank_test", "coresynth_inference") with p_value, statistic (the observed rank sum), rank_sums (its permutation distribution), unit_statistics, n_treated, B and alternative.

References

Abadie, A., & L'Hour, J. (2021). A penalized synthetic control estimator for disaggregated data. JASA, 116(536), 1817-1834.

See Also

mspe_ratio_pval() for the single-treated-unit test.

Examples

set.seed(1)
panel <- expand.grid(unit = 1:12, year = 1:20)
panel$treated <- as.integer(panel$unit <= 3 & panel$year > 12)
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")
scm_rank_pval(fit, B = 50)

coresynth documentation built on Oct. 11, 2026, 5:07 p.m.