Closed andrewbaxter439 closed 4 months ago
Hi Andrew,
I might be missing something, but I don't think you're doing triple-diff from your example code. In the classic triple-difference design, you would have either the male or the female group be treated in a treated region, not both. One gender's region-trend is used as a stand in for the other. So I would not call this a triple-diff. Things are working out in your DGP since you are not generating differential trends by gender or by group. See example code here https://github.com/Mixtape-Sessions/Madrid-2024/blob/main/Labs/DDD/ddd2.R and https://academic.oup.com/ectj/article-pdf/25/3/531/45842047/utac010.pdf
I believe what you're doing here is not triple diff but just doing diff-in-diff using treated groups compare to untreated groups. Additionally, you're interacting treatment with gender to get subgroup ATT estimates which is an okay thing to do. Note you're implicitly assuming no gender-specific trends in the first-stage. Doing first_stage = ~ 0 | gender^t + group
would estimate gender-specific trends which is probably preferable.
You can compare two subgroup-ATTs with proper standard errors using marginaleffects::hypotheses
. You could also split the df and use vcovSUR
package to perform hypothesis tests using separate diff-in-diff.
library(tidyverse)
library(did2s)
set.seed(101)
df <- tibble(
group = c(rep("a", 20), rep("b", 20)),
gender = rep(c(rep("m", 10), rep("f", 10)), 2) |>
factor(levels = c("m", "f")),
t = rep(1:10, times = 4),
t_f = factor(t),
period = (t > 5),
treat = period * (group == "b"),
treat_f = treat * (gender == "f"),
treat_m = treat * (gender == "m"),
y = 1 * (group == "b") +
2 * treat +
4 * (gender == "f") +
8 * treat_f +
rnorm(40, 0, 0.5)
)
est = did2s(
df,
"y",
first_stage = ~ gender | t + group,
second_stage = ~i(treat, gender, ref = 0),
treatment = "treat",
cluster_var = "group"
)
library(marginaleffects)
hypotheses(est, "`treat::1:gender::m` - `treat::1:gender::f` = 0")
Ah thanks for the clarity Kyle - I think I had applied the term 'triple diff' out of laziness rather than precisely describing what I was doing. The marginaleffects::hypotheses
approach seems perfect for getting proper standard errors out of it too. Thanks for the tips with this and for the excellent and adaptable package!
Thanks for the comment in #12 on how to do triple differences. Following on from this I wanted to check if there was a good way of using this setup to return both the interaction coefficient and the two effect estimates for subgroups?
Constructing a population where:
To check with a linear model (as one treatment time point), this recovers:
groupb
genderf
groupb:periodTRUE
groupb:periodTRUE:genderf
In models with
did2s
, these also return the right numbers. Non-subgrouped effect of +6 (male treatment = 2, female treatment = 2 + 8)To do triple-differences, building from your suggested model (although time/group fixed effects not working here - have substituted equivalent factors) recovers the interaction effect (difference from male effect seen in females):
Fitting a separate model with two interacting variables in
i()
can recover the treatment effect of each subgroup - i.e. their difference from respective baselines:My questions relating to the above are twofold. Firstly, is the final model a valid way of getting subgroup estimates, rather than splitting the dataframe? Secondly, can both of these estimates - interaction term and estimates of subgroups from respective baselines - be recovered from the same model? In theory the coefficients in the two-group model can be subtracted, but standard errors I imagine would be a lot more complex.
In my dataset which is a lot more complex than this example, I want to perform subgroup analyses to estimate both an interaction term for additional effects on vulnerable groups and a set of subgroup differences. The changes to the first-stage formula between these models is making the estimates differ slightly from a straightforward subtraction sum, so if recovering both from the same model was possible it would give more continuity across analyses.
Thanks in advance for any pointers on this.