The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
coresynth provides six causal-inference estimators
for panel data behind a single formula interface, with the computational
core (QP solving, SVD, Kalman filtering) written in C++ via
RcppArmadillo. This vignette walks through the basics: fitting a model,
comparing methods, and pulling results out with broom and
plot().
Every estimator is reached through scm_fit() with the
same formula syntax:
outcome ~ treatment | unit_id + time_id
The data must be a long-format balanced panel (one
row per unit–time), and treatment is a 0/1 indicator that
switches on for treated units in post-treatment periods.
method = selects the estimator.
We simulate a balanced panel of 10 units over 20 periods. Unit
u1 is treated from period 11 onward with a true ATT of
2.0.
set.seed(42)
N <- 10; TT <- 20; T_pre <- 10
f <- cumsum(rnorm(TT, 0, 0.5)) # common factor
lam <- rnorm(N, 1, 0.3) # unit loadings
dat <- expand.grid(time = seq_len(TT), id = paste0("u", seq_len(N)))
dat$y <- as.vector(outer(f, lam)) + rnorm(nrow(dat), 0, 0.3)
dat$d <- as.integer(dat$id == "u1" & dat$time > T_pre)
dat$y[dat$d == 1] <- dat$y[dat$d == 1] + 2.0 # inject the treatment effect
head(dat)
#> time id y d
#> 1 1 u1 0.7590559 0
#> 2 2 u1 0.5774968 0
#> 3 3 u1 0.8414384 0
#> 4 4 u1 0.6355518 0
#> 5 5 u1 1.1532557 0
#> 6 6 u1 0.4384856 0fit <- scm_fit(y ~ d | id + time, data = dat, method = "scm")
fit
#> === coresynth fit ===
#> Method : SCM
#> Estimate (ATT): 2.2712
#> Pre-treatment periods: 10The estimated ATT lives in fit$estimate:
Because the interface is shared, swapping estimators is a one-word change. Here we run all six on the same data (true ATT = 2.0).
methods <- c("scm", "sdid", "gsc", "mc", "tasc", "si")
fits <- lapply(methods, function(m) scm_fit(y ~ d | id + time, data = dat, method = m))
names(fits) <- methods
data.frame(
method = methods,
estimate = round(sapply(fits, `[[`, "estimate"), 3)
)
#> method estimate
#> scm scm 2.271
#> sdid sdid 2.150
#> gsc gsc 2.255
#> mc mc 2.696
#> tasc tasc 1.154
#> si si 2.346| Method | Reference |
|---|---|
scm |
Abadie, Diamond & Hainmueller (2010) |
sdid |
Arkhangelsky et al. (2021) |
gsc |
Xu (2017) |
mc |
Athey et al. (2021) |
tasc |
Rho et al. (2026) |
si |
Agarwal et al. (2025) |
plot.coresynth() offers three views via
type =.
coresynth integrates with broom, so results drop
straight into tidy workflows and paper tables.
library(broom)
tidy(fits$scm) # donor weights as a data frame
#> term estimate type
#> 1 u2 0.24733877 unit_weight
#> 2 u3 0.00000000 unit_weight
#> 3 u4 0.07036082 unit_weight
#> 4 u5 0.00000000 unit_weight
#> 5 u6 0.14754253 unit_weight
#> 6 u7 0.32811909 unit_weight
#> 7 u8 0.00000000 unit_weight
#> 8 u9 0.00000000 unit_weight
#> 9 u10 0.20663878 unit_weight
glance(fits$scm) # one-row model summary
#> method estimate n_controls n_treated T_pre T_post staggered multi_arm
#> 1 scm 2.271164 9 1 10 10 FALSE FALSEexport_json() writes a fit to disk as JSON for
reproducibility or downstream (e.g. AI) workflows:
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.