
Difference in differences after matching on pre-treatment trajectories
Source:R/panel_causal.R
mtchdid.RdMatches each treated unit to the comparison units most like it before treatment (its outcomes in the pre-period and, optionally, covariates), within an exact grouping if given, and estimates the difference in differences on the matched sample with the matching weights.
Usage
mtchdid(
data,
unit,
time,
y,
ftreat,
covs = NULL,
ratio = 1L,
exact = NULL,
caliper = NULL,
covm = c("pooled", "full"),
conflvl = 0.95,
cl = NULL
)Arguments
- data
A data frame, one row per unit and period.
- unit, time, y
Column names: the unit, the period (numeric, for example a year or a month index) and the outcome.
- ftreat
Column name of the period a unit is first treated (
NA, 0 orInffor a unit never treated). Treatment is taken as staying on.- covs
Optional covariate columns to match on (their pre-period means).
- ratio
Comparison units per treated unit (default 1).
- exact
Optional column name: match only within its values (a region, a district).
- caliper
Optional maximum distance, in standard deviations of the distances.
- covm
"pooled"(default; the pooled within-group covariance) or"full"(the whole sample's).- conflvl
Confidence level of the intervals reported (default 0.95).
- cl
Column name of the clusters (default the unit), or two column names for two-way clustering (Cameron, Gelbach and Miller 2011): \(V_a + V_b - V_{ab}\), each term with the small-sample factor of the dimension with fewer clusters, and t on its \(G - 1\) degrees of freedom. A composite cluster (district by month, say) is one column made with
interaction(). Fewer than ten clusters give a warning (CR1 errors are unreliable with so few;wcbis made for that case), and so does a cluster that changes within a unit.
Value
A list of class rmbl_matched_did: estimate (a
plndid result), matches (treated unit, comparison
unit, distance), weights (per unit), balance (a
baltab of the matching features before and after).
Details
Each unit is described by its outcome in each pre-period (the
periods before the first adoption) and the pre-period means of the
covariates. Distances are Mahalanobis, with the pooled within-group
covariance of those features (covariance = "pooled", as MatchIt
computes it) or their covariance in the whole sample ("full", as
stats::mahalanobis() is usually given it); each treated unit takes its
ratio nearest comparison units, with replacement (so the matches do
not depend on the order of the treated units), only within its exact
group, and only within caliper (in units of the distance's standard
deviation) if given. A comparison unit's weight is the sum over the treated
units it serves of \(1/\code{ratio}\). The estimate is plndid
on the matched units with those weights, with errors clustered by unit;
matching on pre-period outcomes makes parallel trends more credible but can
bring in regression to the mean when the treated were chosen for an unusual
pre-period (Daw and Hatfield 2018).
References
Daw JR, Hatfield LA (2018). Matching and regression to the mean in difference-in-differences analysis. Health Services Research 53(6):4138-4156. doi:10.1111/1475-6773.12993
Applied with spatial nearest-facility matching within judicial districts: Zorro Medina A (2020). The failed war on pre-trial detention: evidence from a quasi-experimental reform. doi:10.2139/ssrn.3686855
Examples
p <- polex()
m <- mtchdid(p, "district", "month", "crmrate", "refmonth", ratio = 2)
m$estimate
#> ╭── Difference in differences ────────────────────────────────────────────────╮
#> │ Method fixed-effects least squares, cluster-robust (CR1) errors │
#> │ Observations 720 │
#> │ Clusters 20 │
#> │ Confidence 95% │
#> │ Comparison mean 26.3 │
#> │ Relative effect -11.7% of the comparison mean │
#> │ │
#> │ Estimates │
#> │ term estimate se 95% CI t p_value │
#> │ ------- -------- ------ ---------------- ------ ------- │
#> │ treated -3.081 0.1208 [-3.334, -2.829] -25.51 < 0.001 │
#> │ │
#> │ The policy's effect on the outcome is -3.081 (95% interval [-3.334, │
#> │ -2.829]): the interval excludes 0, so the data distinguish it from no │
#> │ effect. │
#> │ │
#> │ The comparison mean is the pre-period mean outcome of the units not │
#> │ (yet) treated. │
#> ╰─────────────────────────────────────────────────────────────────────────────╯
m$balance
#> feature smdbef smdafter
#> 1 y_1 0.6234337 0.6305205
#> 2 y_2 0.4933815 0.5333419
#> 3 y_3 0.3630111 0.4016449
#> 4 y_4 0.5185005 0.5671520
#> 5 y_5 0.5394918 0.5670062
#> 6 y_6 0.5953617 0.6497642
#> 7 y_7 0.5296771 0.5555045
#> 8 y_8 0.4786997 0.5442183
#> 9 y_9 0.6411876 0.6298522
#> 10 y_10 0.5844047 0.7157425
#> 11 y_11 0.5414501 0.5442063
#> 12 y_12 0.4630436 0.5330361
# your own panel: eight towns over ten years, four adopting a by-law (two
# in 2019, two in 2021), with each town's population, county and income
own <- data.frame(
town = rep(c("A", "B", "C", "D", "E", "F", "G", "H"), each = 10),
year = rep(2015:2024, times = 8)
)
i <- match(own$town, unique(own$town))
own$first <- c(2019, 2019, 2021, 2021, NA, NA, NA, NA)[i]
own$bylaw <- as.integer(!is.na(own$first) & own$year >= own$first)
own$pop <- c(12, 30, 8, 22, 15, 40, 9, 18)[i] * 1000
own$county <- rep(c("North", "South"), 4)[i]
own$income <- 50 + own$year - 2015 + cos(seq_len(80))
own$rate <- 30 + i + 0.5 * (own$year - 2015) - 4 * own$bylaw +
0.2 * own$income + sin(seq_len(80))
# each adopting town matched to one never treated on its path before 2019,
# the standard errors clustered by county: with two counties the package
# warns that so few clusters cannot be trusted
mtchdid(own, "town", "year", "rate", "first", cl = "county")$estimate
#> Warning: mtchdid: `cl` (county) gives only 2 clusters: cluster-robust (CR1) standard errors are unreliable with so few; wcb() is made for this case
#> ╭── Difference in differences ────────────────────────────────────────────────╮
#> │ Method fixed-effects least squares, cluster-robust (CR1) errors │
#> │ Observations 60 │
#> │ Clusters 2 │
#> │ Confidence 95% │
#> │ Comparison mean 46.48 │
#> │ Relative effect -8.7% of the comparison mean │
#> │ │
#> │ Estimates │
#> │ term estimate se 95% CI t p_value │
#> │ ------- -------- ------ ------------------ ------ ------- │
#> │ treated -4.052 0.3065 [-7.9460, -0.1577] -13.22 0.048 │
#> │ │
#> │ The policy's effect on the outcome is -4.052 (95% interval [-7.9460, │
#> │ -0.1577]): the interval excludes 0, so the data distinguish it from │
#> │ no effect. │
#> │ │
#> │ The comparison mean is the pre-period mean outcome of the units not │
#> │ (yet) treated. │
#> ╰─────────────────────────────────────────────────────────────────────────────╯