| Title: | Staggered Synthetic Control Estimation and Inference |
|---|---|
| Description: | Implements the Staggered Synthetic Control (SSC) method for estimating treatment effects in panel data with staggered adoption, as proposed by Cao, Lu, and Wu (2020) <doi:10.48550/arXiv.1912.06320>. Constructs synthetic control weights via constrained quadratic programming, estimates heterogeneous treatment effects and event-time average treatment effects on the treated (ATT), and provides placebo-in-time confidence intervals and p-values. |
| Authors: | Zhanchao Fu [aut, cre], Jianfei Cao [aut] |
| Maintainer: | Zhanchao Fu <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.1.0 |
| Built: | 2026-05-29 09:05:47 UTC |
| Source: | https://github.com/cran/stagsynth |
Implements the Staggered Synthetic Control (SSC) method of Cao, Lu, and Wu (2020) for estimating treatment effects in panel data with staggered adoption.
ssc: Estimate event-time ATT, overall ATT, and
placebo-in-time confidence intervals.
panel_to_matrices: Convert long-format panel
data to the matrices expected by ssc().
ssc_min_eigenvalue: Check the design matrix
invertibility condition.
synthetic_control: Estimate SC weights for a
single treated unit.
synthetic_control_batch: Estimate SC weights
for all units.
Maintainer: Zhanchao Fu [email protected]
Authors:
Jianfei Cao [email protected]
Transform a data frame in long format (one row per unit-period) into
the matrices Y and D expected by
ssc.
panel_to_matrices(data, unit, time, outcome, treatment)panel_to_matrices(data, unit, time, outcome, treatment)
data |
A data frame. |
unit |
Character: name of the unit identifier column. |
time |
Character: name of the time period column. |
outcome |
Character: name of the outcome variable column. |
treatment |
Character: name of the treatment indicator column (must be 0/1). |
A list with components
Numeric outcome matrix.
Numeric treatment matrix.
Sorted vector of unique unit identifiers.
Sorted vector of unique time periods.
df <- data.frame( id = rep(1:4, each = 6), time = rep(1:6, times = 4), Y = rnorm(24), D = c(rep(0, 12), rep(c(0,0,0,1,1,1), 2)) ) mat <- panel_to_matrices(df, unit = "id", time = "time", outcome = "Y", treatment = "D")df <- data.frame( id = rep(1:4, each = 6), time = rep(1:6, times = 4), Y = rnorm(24), D = c(rep(0, 12), rep(c(0,0,0,1,1,1), 2)) ) mat <- panel_to_matrices(df, unit = "id", time = "time", outcome = "Y", treatment = "D")
Plot Event-Time ATT from SSC Estimation
## S3 method for class 'ssc' plot( x, main = "Event-time ATT (SSC)", xlab = "Event time", ylab = "ATT estimate", ci = !anyNA(x$ci_lower_event), ... )## S3 method for class 'ssc' plot( x, main = "Event-time ATT (SSC)", xlab = "Event time", ylab = "ATT estimate", ci = !anyNA(x$ci_lower_event), ... )
x |
An object of class |
main |
Title string. |
xlab, ylab
|
Axis labels. |
ci |
Logical: draw the confidence band? Default |
... |
Additional arguments (currently unused). |
A ggplot object (invisibly) if ggplot2 is available;
otherwise a base-R plot is drawn and NULL is returned invisibly.
set.seed(1) N <- 10; Ttot <- 8 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1:3, 5:Ttot] <- 1L # units 1-3 treated from period 5 fit <- ssc(Y, D, S = 2, alpha = 0.05) plot(fit)set.seed(1) N <- 10; Ttot <- 8 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1:3, 5:Ttot] <- 1L # units 1-3 treated from period 5 fit <- ssc(Y, D, S = 2, alpha = 0.05) plot(fit)
Compact one-line summary of a "ssc" estimation result.
## S3 method for class 'ssc' print(x, ...)## S3 method for class 'ssc' print(x, ...)
x |
An object of class |
... |
Currently unused. |
x, invisibly.
Estimate treatment effects in a panel with staggered adoption using the Staggered Synthetic Control (SSC) method of Cao, Lu, and Wu (2020). Returns event-time ATT, overall ATT, heterogeneous treatment effects, and placebo-in-time confidence intervals.
ssc(Y, D, S = NULL, alpha = 0.05)ssc(Y, D, S = NULL, alpha = 0.05)
Y |
Numeric matrix ( |
D |
Binary matrix ( |
S |
Integer or |
alpha |
Significance level for confidence intervals (default 0.05). |
The SSC method proceeds in four steps:
SC weights. For every unit, estimate synthetic control weights from pre-treatment data.
Treatment structure.
Build the treatment assignment matrices that map
heterogeneous effects to unit-level outcomes at
each post-treatment period.
Estimation.
Solve a GLS-type system to recover , then
aggregate to event-time or overall ATT via a linear map .
Inference.
Construct a null distribution by applying the same estimator to
rolling windows of pre-treatment residuals (placebo-in-time).
Confidence intervals are the and
quantiles of this distribution, shifted by
the point estimate.
An object of class "ssc", a list containing:
Numeric vector of length : event-time ATT
estimates (averaged across units at each event time).
Numeric vectors of length
: lower and upper bounds of
placebo-in-time confidence intervals.
NA when (too few pre-treatment periods).
Scalar: overall ATT (simple average of all heterogeneous effects).
Scalar CI bounds for
the overall ATT. NA when .
Two-sided p-value for based on
the placebo distribution. NA when .
Numeric vector of length : heterogeneous
treatment effects for every treated (unit, post-period) pair.
Numeric matrix of
unit-level treatment effects at each post-treatment period.
Numeric SC weight matrix.
Numeric vector of length : SC intercepts.
Numeric matrix of pre-treatment
SC residuals.
Smallest eigenvalue of the sample analogue of
the design matrix .
Must be positive for the estimator to be well-defined.
Integer matrix. Each row
records the post-treatment period ,
unit , and event time for one element of
.
Panel dimensions.
Significance level used.
Cao, J., Lu, C., and Wu, Y. (2020). "Synthetic Control Inference for Staggered Adoption."
set.seed(1) N <- 5; Ttot <- 15 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1, 8:15] <- 1L D[2, 10:15] <- 1L result <- ssc(Y, D) print(result) summary(result)set.seed(1) N <- 5; Ttot <- 15 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1, 8:15] <- 1L D[2, 10:15] <- 1L result <- ssc(Y, D) print(result) summary(result)
A diagnostic function that builds the SSC design matrix
and returns its smallest eigenvalue.
This matrix must be positive definite for SSC estimates to exist.
ssc_min_eigenvalue(Y, D, S = NULL)ssc_min_eigenvalue(Y, D, S = NULL)
Y |
Numeric matrix ( |
D |
Binary matrix ( |
S |
Number of post-treatment periods (or |
A positive value means the SSC estimator is well-defined; a value near zero warns that identification is weak.
A scalar: the smallest eigenvalue.
set.seed(1) N <- 10; Ttot <- 8 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1:3, 5:Ttot] <- 1L # units 1-3 treated from period 5 ssc_min_eigenvalue(Y, D, S = 2)set.seed(1) N <- 10; Ttot <- 8 Y <- matrix(rnorm(N * Ttot), N, Ttot) D <- matrix(0L, N, Ttot) D[1:3, 5:Ttot] <- 1L # units 1-3 treated from period 5 ssc_min_eigenvalue(Y, D, S = 2)
Prints a detailed summary of a "ssc" estimation result, including
design diagnostics, the overall ATT with confidence interval and p-value,
and a table of event-time ATT estimates.
## S3 method for class 'ssc' summary(object, ...)## S3 method for class 'ssc' summary(object, ...)
object |
An object of class |
... |
Currently unused. |
object, invisibly.
Estimate synthetic control weights by solving a constrained quadratic
program on demeaned pre-treatment outcomes: minimise
subject to
, where and
are time-demeaned series for the treated unit and controls.
synthetic_control(Y)synthetic_control(Y)
Y |
Numeric matrix ( |
The QP is solved by solve.QP. A small ridge term
() is added to the Hessian for numerical stability when
is close to or smaller than .
A list with components
Scalar intercept
.
Numeric vector of length . Entry 1 is 0 (the
treated unit's self-weight); entries are the
non-negative weights summing to 1.
set.seed(1) Y <- matrix(rnorm(5 * 20), 5, 20) # 5 units, 20 pre-treatment periods res <- synthetic_control(Y) res$b_hat # SC weights for unit 1set.seed(1) Y <- matrix(rnorm(5 * 20), 5, 20) # 5 units, 20 pre-treatment periods res <- synthetic_control(Y) res$b_hat # SC weights for unit 1
For each unit in turn, treat that unit as the "treated" unit and
estimate SC weights from the remaining units. This produces an
weight matrix with zeros on the diagonal.
synthetic_control_batch(Y)synthetic_control_batch(Y)
Y |
Numeric matrix ( |
A list with components
Numeric vector of length : unit-level intercepts.
Numeric matrix of SC weights. Row
contains the weights used to construct the synthetic control
for unit ; .
set.seed(1) Y <- matrix(rnorm(5 * 20), 5, 20) res <- synthetic_control_batch(Y) res$B_hat # N x N weight matrixset.seed(1) Y <- matrix(rnorm(5 * 20), 5, 20) res <- synthetic_control_batch(Y) res$B_hat # N x N weight matrix