Stacked regression

Fit the Q-weighted event-study (or single-ATT) regression on a stacked dataset, reporting the average post-period ATT with a delta-method standard error.

R stackreg()   ↔︎   Stata stacked reg

Usage

stackreg(
  stack_data, outcome_var,
  cluster_var = NULL, ref_period = -1L, covariates = NULL,
  model = c("event_study", "att"),
  fe = c("saturated", "interacted"),
  unit_var = NULL, time_var = NULL, by_group = FALSE
)

Arguments

Argument Description
stack_data A stack from build_stack().
outcome_var Outcome variable name.
cluster_var Clustering variable for SEs (default NULL).
ref_period Reference event time normalized to zero (default -1).
covariates Additional control variables.
model "event_study" (full dynamics) or "att" (single treat×post).
fe "saturated" (default, no FE) or "interacted" (unit^sub_exp + time^sub_exp; needs fixest + unit_var/time_var).
unit_var, time_var Required when fe = "interacted".
by_group Also estimate per timing group; returns a stackreg_groups object carrying cohort fits and aggregation weights.
stacked reg depvar [, cluster(varname) ref(#) model(str) fe(str) bygroup ///
    covariates(varlist) absorb(fvlist) unitvar(varname) timevar(varname) level(#)]

Options

Option Description
cluster(varname) Cluster-robust SEs.
ref(#) Reference event time (default -1).
model(str) eventstudy (default) or att.
fe(str) saturated (default) or interacted (via reghdfe).
bygroup Also estimate per cohort; stores r(group_att), r(n_groups).
covariates(varlist) Additional controls.
absorb(fvlist) High-dimensional FE passed to reghdfe (e.g. absorb(state#sub_exp year#sub_exp)).
unitvar(), timevar() Overrides; normally read from what stacked build recorded.
level(#) Confidence level for the reported ATT interval.

stacked reg uses reghdfe when installed (required for absorb() / fe(interacted)) and falls back to regress. Weights enter as aweights, matching R’s fixest::feols WLS.

R ↔︎ Stata mapping

R Stata
outcome_var depvar
cluster_var cluster()
ref_period ref()
covariates covariates()
model = "event_study" / "att" model(eventstudy) / model(att)
fe = "saturated" / "interacted" fe(saturated) / fe(interacted)
unit_var / time_var unitvar() / timevar()
by_group bygroup
(none; R has no absorb, uses fe = "interacted") absorb()
(fixed 95%) level()

Value / Stored results

R returns a fixest (or lm) model with an avg_post_att attribute — a list with estimate, se, ci_lower, ci_upper, n_periods. With by_group = TRUE, a stackreg_groups object holding per-cohort fits, the pooled fit, and each cohort’s aggregation weight (so pooled ATT = Σ weight × cohort ATT).

Stata leaves the regression in e() and stores r(att), r(att_se), r(att_lb), r(att_ub), r(n_post), r(ref), r(model), r(fe); with bygroup, additionally r(group_att) (rows: sub_exp, att, se, lb, ub, weight) and r(n_groups). See event-study coefficients.

Example

library(stacked)
data(medicaid)
stack <- build_stack(medicaid, "year", "state", "adopt_year",
                     kappa_pre = 3, kappa_post = 2)

model <- stackreg(stack, "uninsured", cluster_var = "state")
attr(model, "avg_post_att")[c("estimate", "se")]
$estimate
[1] -0.02187775

$se
[1] 0.005628133
stacked use medicaid, clear
stacked build, time(year) unit(state) adopt(adopt_year) kpre(3) kpost(2)
stacked reg uninsured, cluster(state)

* single ATT with the canonical interacted fixed effects
stacked reg uninsured, cluster(state) model(att) fe(interacted)

See also