Computes the synthetic diff-in-diff estimate for an average treatment effect on a treated block.
Source:R/synthdid.R
synthdid_estimate.RdSee 'Synthetic Difference in Differences' by Arkhangelsky et al. This implements Algorithm 1.
Usage
synthdid_estimate(
Y,
N0,
T0,
X = array(dim = c(dim(Y), 0)),
noise.level = NULL,
eta.omega = ((nrow(Y) - N0) * (ncol(Y) - T0))^(1/4),
eta.lambda = SYNTHDID_ETA_LAMBDA_DEFAULT,
zeta.omega = NULL,
zeta.lambda = NULL,
omega.intercept = TRUE,
lambda.intercept = TRUE,
weights = list(omega = NULL, lambda = NULL),
update.omega = is.null(weights$omega),
update.lambda = is.null(weights$lambda),
min.decrease = NULL,
max.iter = SYNTHDID_MAX_ITER_DEFAULT,
sparsify = sparsify_function,
max.iter.pre.sparsify = SYNTHDID_MAX_ITER_PRE_SPARSIFY,
estimate_se = FALSE,
se_method = c("bootstrap", "jackknife", "placebo"),
se_replications = SYNTHDID_SE_REPLICATIONS_DEFAULT,
suppress_convergence_warning = TRUE
)Arguments
- Y
the observation matrix.
- N0
the number of control units (N_co in the paper). Rows 1-N0 of Y correspond to the control units.
- T0
the number of pre-treatment time steps (T_pre in the paper). Columns 1-T0 of Y correspond to pre-treatment time steps.
- X
an optional 3-D array of time-varying covariates. Shape should be N X T X C for C covariates.
- noise.level,
an estimate of the noise standard deviation sigma. Defaults to the standard deviation of first differences of Y.
- eta.omega
determines the tuning parameter zeta.omega = eta.omega * noise.level. Defaults to the value (N_tr T_post)^(1/4).
- eta.lambda
analogous for lambda. Defaults to an 'infinitesimal' value 1e-6.
- zeta.omega
if passed, overrides the default zeta.omega = eta.omega * noise.level. Deprecated.
- zeta.lambda
analogous for lambda.
- omega.intercept
Binary. Use an intercept when estimating omega.
- lambda.intercept
Binary. Use an intercept when estimating lambda.
- weights
a list with fields lambda and omega. If non-null weights$lambda is passed, we use them instead of estimating lambda weights. Same for weights$omega.
- update.omega
If true, solve for omega using the passed value of weights$omega only as an initialization. If false, use it exactly as passed. Defaults to false if a non-null value of weights$omega is passed.
- update.lambda
Analogous.
- min.decrease
Tunes a stopping criterion for our weight estimator. Stop after an iteration results in a decrease in penalized MSE smaller than min.decrease^2.
- max.iter
A fallback stopping criterion for our weight estimator. Stop after this number of iterations.
- sparsify
A function mapping a numeric vector to a (presumably sparser) numeric vector of the same shape, which must sum to one. If not null, we try to estimate sparse weights via a second round of Frank-Wolfe optimization initialized at sparsify(the solution to the first round).
- max.iter.pre.sparsify
Analogous to max.iter, but for the pre-sparsification first-round of optimization. Not used if sparsify = NULL.
- estimate_se
Logical. If TRUE, attempt to compute a standard error for the estimate (stored as an attribute).
- se_method
Standard-error method to use when estimate_se = TRUE; one of "bootstrap", "jackknife", or "placebo".
- se_replications
Number of replications when using bootstrap or placebo standard errors.
- suppress_convergence_warning
Logical. If FALSE raise the warning flag for parameters that did not converge.
Value
An average treatment effect estimate with 'weights' and 'setup' attached as attributes. 'weights' contains the estimated weights lambda and omega and corresponding intercepts, as well as regression coefficients beta if X is passed. 'setup' is a list describing the problem passed in: Y, N0, T0, X. If estimate_se = TRUE, attributes 'se', 'se_method', and 'se_status' reflect the requested standard error computation.
Examples
# \donttest{
# Estimate treatment effect using California Proposition 99 data
data(california_prop99)
setup <- panel.matrices(california_prop99)
# Basic SynthDID estimate
tau.hat <- synthdid_estimate(setup$Y, setup$N0, setup$T0)
print(tau.hat)
#> synthdid: -15.604 +- NA. Effective N0/N0 = 16.4/38~0.4. Effective T0/T0 = 2.8/19~0.1. N1,T1 = 1,12. [NOT CONVERGED]
# With standard error computation
tau.hat.se <- synthdid_estimate(setup$Y, setup$N0, setup$T0,
estimate_se = TRUE, se_method = "jackknife"
)
#> Warning: jackknife standard errors require more than one treated unit and at least two controls with weight.
sqrt(vcov(tau.hat.se))
#> [,1]
#> [1,] NA
# Using covariates (if available)
# Suppose X is a 3D array of time-varying covariates
# tau.hat.cov <- synthdid_estimate(setup$Y, setup$N0, setup$T0, X = X)
# Access weights and check convergence
omega <- attr(tau.hat, "weights")$omega
lambda <- attr(tau.hat, "weights")$lambda
synthdid_converged(tau.hat)
#> [1] FALSE
# Using custom regularization
tau.hat.custom <- synthdid_estimate(setup$Y, setup$N0, setup$T0,
eta.omega = 0.5, eta.lambda = 1e-3
)
# }