build_stack(
data, time_var, unit_var, adopt_var,
kappa_pre = 3L, kappa_post = 2L,
control_type = c("both", "never_treated", "not_yet_treated"),
nyt_horizon = NULL, weight_var = NULL,
data_type = c("panel", "repeated_cross_section"),
weight_type = c("unit_weights", "population_between", "pop_constant",
"pop_total_periods", "pop_period_specific", "sample_share"),
pop_var = NULL, copy = TRUE, overwrite_conflicts = FALSE, duck = FALSE
)Build a stack
Build a stacked difference-in-differences dataset: one sub-experiment per feasible adoption cohort, aligned by event time, with clean controls and Q-weights for correct aggregation.
R build_stack() ↔︎ Stata stacked build
Usage
Arguments
| Argument | Description |
|---|---|
data |
data.frame/data.table long panel (one row per unit-time). |
time_var |
Calendar-time column (numeric, Date, or POSIXt). |
unit_var |
Unit/group identifier column. |
adopt_var |
Adoption-time column; NA for never-treated. |
kappa_pre, kappa_post |
Pre/post event-window periods (default 3, 2). |
control_type |
"both", "never_treated", or "not_yet_treated". |
nyt_horizon |
Cap not-yet-treated controls to units adopting within this many periods after the window. |
weight_var |
Survey sampling-weight column. |
data_type |
"panel" or "repeated_cross_section" (adds event-time level adjustment). |
weight_type |
Q-weight scheme (see below). |
pop_var |
Population column; required by the population weight types. |
copy |
Copy input before modifying (default TRUE). |
overwrite_conflicts |
Overwrite reserved output columns if present. |
duck |
Build inside DuckDB for larger-than-memory data — see DuckDB. |
stacked build, time(varname) unit(varname) adopt(varname) ///
[kpre(#) kpost(#) controltype(str) nythorizon(#) ///
weightvar(varname) datatype(str) weighttype(str) popvar(varname) replace]stacked build replaces the data in memory with the stacked dataset.
Options
| Option | Description |
|---|---|
time(varname) |
Calendar-time variable (numeric or Stata date). |
unit(varname) |
Unit identifier. |
adopt(varname) |
Adoption time; missing for never-treated. Constant within unit. |
kpre(#), kpost(#) |
Event-window bounds (defaults 3, 2). |
controltype(str) |
both (default), never_treated/never, not_yet_treated/notyet. |
nythorizon(#) |
Restrict not-yet-treated controls to units adopting within # periods after the window. |
weightvar(varname) |
Survey/sampling weights. |
datatype(str) |
panel (default) or repeated_cross_section/rcs. |
weighttype(str) |
Q-weight scheme (see below). |
popvar(varname) |
Population column; required by the population weight types. |
replace |
Overwrite existing sub_exp/event_time/treat/post/q_weight. |
Weight types (same names both languages): unit_weights (default), population_between, pop_constant, pop_total_periods, pop_period_specific, sample_share. The pop_* and population_between types require the population column. See the kappa trade-offs vignette and the paper’s Appendix 0 for the estimand each targets.
R ↔︎ Stata mapping
| R | Stata |
|---|---|
time_var |
time() |
unit_var |
unit() |
adopt_var |
adopt() |
kappa_pre / kappa_post |
kpre() / kpost() |
control_type |
controltype() |
nyt_horizon |
nythorizon() |
weight_var |
weightvar() |
data_type |
datatype() |
weight_type |
weighttype() |
pop_var |
popvar() |
overwrite_conflicts |
replace |
duck = TRUE |
parquet() — see DuckDB |
copy |
(none; Stata always modifies data in memory) |
Value / Stored results
R returns a data.table with all original columns plus sub_exp (sub-experiment id = adoption time), event_time, treat (0/1), post (0/1), and q_weight. Design settings are stamped in a stacked_meta attribute read by stack_summary().
Stata replaces the data in memory with the same variables and stores r(n_obs), r(n_treated), r(n_control), r(n_sub_exp), r(n_unidentified_sub_exp), r(adoption_times).
Feasible sub-experiments with no eligible control (or treated) units are dropped with a warning before Q-weights are computed — most often the latest cohorts under not_yet_treated with a long post-window.
Example
library(stacked)
data(medicaid)
stack <- build_stack(
medicaid,
time_var = "year",
unit_var = "state",
adopt_var = "adopt_year",
kappa_pre = 3,
kappa_post = 2
)
dim(stack)[1] 600 10
head(stack[, .(state, year, sub_exp, event_time, treat, post, q_weight)]) state year sub_exp event_time treat post q_weight
1: AL 2011 2014 -3 0 0 2.888889
2: AL 2012 2014 -2 0 0 2.888889
3: AL 2013 2014 -1 0 0 2.888889
4: AL 2014 2014 0 0 1 2.888889
5: AL 2015 2014 1 0 1 2.888889
6: AL 2016 2014 2 0 1 2.888889
stacked use medicaid, clear
stacked build, time(year) unit(state) adopt(adopt_year) kpre(3) kpost(2)See also
stackreg()/stacked reg— fit the Q-weighted regressionkappa_trade_offs()/stacked kappa— choose the windowadd_pscore_weights()/stacked pscore— propensity-score weights- Introduction vignette