Estimates a classic difference-in-differences model of the form
outcome ~ D + covariates | fixed effects on the package's internal
fixed-effects OLS engine (numerically equivalent to fixest::feols()).
The formula is the one used by event_study() and att(): swap the
function to get effects by event time or aggregated staggered ATTs.
did() supersedes run_did() as of fixes 1.0.0.
Treatment is given in one of three ways, as in event_study():
# D: 1 for treated units in post-treatment periods
did(y ~ D | id + year, data = df)
# each unit's first treated period (NA = never treated)
did(y ~ 1 | id + year, data = df, time = year, timing = g)
# a treated-group dummy and one treatment date
did(y ~ treated | id + year, data = df, time = year, timing = 2006)With timing, D = treatment * (time >= timing) is built internally.
For staggered-adoption settings see att(); for dynamic effects see
event_study().
Usage
did(
formula,
data,
time = NULL,
timing = NULL,
unit = NULL,
cluster = NULL,
weights = NULL,
conf_level = 0.95,
vcov = "HC1",
vcov_args = list(),
outcome,
treatment,
fe = NULL,
covariates = NULL
)Arguments
- formula
A model formula
outcome ~ treatment + covariates | fixed effects. The left-hand side may be an expression (e.g.log(y)); without|the model has no fixed effects. The first right-hand-side term is D withouttiming, the treated-group dummy with a singletimingdate, and absent with a timing column (see Description). All variables must be columns ofdata.- data
A data.frame (panel format).
formulaanddatamay come in either order.- time
Unquoted time variable. Required with
timing; with plain fixed effects such as| id + yearit also letsdid()report the unit (seeevent_study(), Panel identifiers).- timing
Treatment timing: an unquoted column giving each unit's first treatment period (
NA= never treated), or a single numeric treatment date. DefaultNULL: the formula holds D.- unit
Unquoted unit identifier column (for metadata). Taken from the fixed effects when possible.
- cluster
Clustering specification: a one-sided formula (
~ id), a single character column name, or a numeric vector of lengthnrow(data). Whenclusteris specified andvcovis the default"HC1", cluster-robust standard errors are used automatically.- weights
Observation weights (formula or numeric vector).
- conf_level
Confidence level(s) for CIs. Scalar or vector (e.g.,
c(0.90, 0.95)). Default0.95.- vcov
VCOV type string passed to
fixest::vcov(). Default"HC1". Ignored in favour of cluster-robust SE whenclusteris supplied andvcovis left at its default"HC1".- vcov_args
Named list of additional arguments forwarded to
fixest::vcov().- outcome, treatment, fe, covariates
The model arguments of the older interface: the unquoted outcome, the treatment column (D, or the treated-group dummy when
timingis given), a one-sided fixed-effects formula (NULLwith bothunitandtimegives~ unit + time), and a one-sided covariate formula. They still work in fixes 1.x, with a deprecation warning that shows the equivalent formula call; fixes 2.0.0 is planned to accept onlyformula. Name them when you use them: the second argument is nowdata.
Value
A did_result object (named list) with elements:
estimatesData frame with the treatment coefficient:
term,estimate,std.error,statistic,p.value, andconf_low_XX/conf_high_XXfor eachconf.levelentry.coeftableData frame with all kept coefficients (treatment and covariates):
term,estimate,std.error,statistic,p.value.vcovFull coefficient covariance matrix.
fit_statsModel-level statistics (nobs, R-squareds, sigma, logLik, AIC, BIC) used by
broom::glance().df.tDegrees of freedom of the t inference.
Attributes: call, formula_str, outcome, treatment, timing,
fe, vcov_type, cluster_vars, conf.level, N, N_units,
N_treated, unit, time (and timing_var with a timing column).
N, N_units, and N_treated describe the estimation sample (after
rows with missing values are dropped), matching broom::glance(), not
nrow(data).
See also
event_study() for dynamic effects, att() for staggered
aggregation, and run_did() for the deprecated verb-style predecessor.
Examples
if (FALSE) { # \dontrun{
res <- did(y ~ D | id + year, data = df)
# Built from a treated-group dummy and the treatment date
res <- did(y ~ treated | id + year, data = df, time = year, timing = 2006)
# Covariates and cluster-robust SE
res <- did(y ~ D + x1 | id + year, data = df, cluster = ~ id)
print(res)
broom::tidy(res)
broom::glance(res)
# modelsummary::modelsummary(res)
} # }