Attempt to replicate Callaway and Sant’Anna (2021).

Get libraries loaded:

library(tidyverse)
library(did)
library(broom)

The example dataset supplied with {did}:

dat <- mpdta  # In case I wanted to change anything...
head(dat)

Estimate ATT(g, t) for each group g and time t:

did_mod <- att_gt(
  yname = "lemp",
  gname = "first.treat",
  control_group = "notyettreated",
  idname = "countyreal",
  tname = "year",
  data = dat,
  est_method = "reg",
  base_period = "varying"
)

did_mod

Call:
att_gt(yname = "lemp", tname = "year", idname = "countyreal", 
    gname = "first.treat", data = dat, control_group = "notyettreated", 
    est_method = "reg", base_period = "varying")

Reference: Callaway, Brantly and Pedro H.C. Sant'Anna.  "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015> 

Group-Time Average Treatment Effects:
---
Signif. codes: `*' confidence band does not cover 0

P-value for pre-test of parallel trends assumption:  0.16814
Control Group:  Not Yet Treated,  Anticipation Periods:  0
Estimation Method:  Outcome Regression

Now my attempt, initially focussed on the estimates. Standard errors can come later!

What made intuitive sense:

Here’s what initially tripped me up:

ATT_group_time <- function(the_group, the_year) {
  # The first time point we choose as we go depends on whether
  # the unit is treated in this "canonical" 2×2 dataset
  comparision_year <- ifelse(the_year < the_group,
                             the_year - 1,
                             the_group - 1)
  
  this_dat <- dat |>
    mutate(treat = as.numeric(first.treat == the_group),
           time  = as.numeric(year == the_year)) |>
    filter(treat |                # ever treated (current group)
           first.treat == 0 |     # never treated (weird convention of {did})
           year < first.treat) |> # not yet treated (other groups)
    filter(year %in% c(comparision_year, the_year))
  
  mod <- lm(lemp ~ 0 + factor(countyreal) + time + time:treat,
            data = this_dat)
  summary(mod) |>
    tidy() |>
    filter(term == "time:treat") |>
    mutate(group = the_group, .before = "term") |>
    mutate(year = the_year, .before = "term") |>
    mutate(sub_n = nrow(this_dat)) |>
    rename(my_est = estimate) |>
    select(-term)
}

Now zap the whole dataset and compare with {did}’s estimates.

res <- map2(did_mod$group, did_mod$t, ATT_group_time) |>
  bind_rows() |>
  mutate(did_est = did_mod$att, .after = "my_est") |>
  mutate(correct = abs(my_est - did_est) < 1e-6, .after = "did_est")
stopifnot(all(res$correct))
res |> select(group, year, my_est, did_est, correct, sub_n)

Hurrah - it worked! I’m going to worry about the standard errors another day.

Pooling the ATT(g,t)s?

Here are {did}’s estimates, pooled by group:

did_agg_group <- aggte(did_mod, type = "group")
did_agg_group

Call:
aggte(MP = did_mod, type = "group")

Reference: Callaway, Brantly and Pedro H.C. Sant'Anna.  "Difference-in-Differences with Multiple Time Periods." Journal of Econometrics, Vol. 225, No. 2, pp. 200-230, 2021. <https://doi.org/10.1016/j.jeconom.2020.12.001>, <https://arxiv.org/abs/1803.09015> 


Overall summary of ATT's based on group/cohort aggregation:  


Group Effects:
---
Signif. codes: `*' confidence band does not cover 0

Control Group:  Not Yet Treated,  Anticipation Periods:  0
Estimation Method:  Outcome Regression

We can replicate the estimated by just averaging the ATT(g,t) estimates across the t’s:

pool_estimates_naive <- function(ests) {
  data.frame(
    my_pooled_est = mean(ests),
    n_t = length(ests)
  )
}

agg_res <- res |>
  filter(year >= group) |>
  group_by(group) |>
  summarise(pool_estimates_naive(my_est)) |>
  mutate(did_agg_es = did_agg_group$att.egt, .after = "my_pooled_est") |>
  mutate(correct = abs(my_pooled_est - did_agg_es) < 1e-6)
stopifnot(all(agg_res$correct))

agg_res

That works.

References

Callaway, B., & Sant’Anna, P. H. C. (2021). Difference-in-Differences with multiple time periods. Journal of Econometrics, 225(2), 200–230.

LS0tDQp0aXRsZTogIkRpZmZlcmVuY2UtaW4tZGlmZmVyZW5jZXMgKGRpZmYtaW4tZGlmZnMpIGV4cGVyaW1lbnRzIg0KYXV0aG9yOiBBbmRpIEZ1Z2FyZA0KZGF0ZTogMjcgRGVjIDIwMjQNCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIGNvZGVfZm9sZGluZzogbm9uZQ0KLS0tDQoNCkF0dGVtcHQgdG8gcmVwbGljYXRlIENhbGxhd2F5IGFuZCBTYW504oCZQW5uYSAoMjAyMSkuDQoNCkdldCBsaWJyYXJpZXMgbG9hZGVkOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRpZCkNCmxpYnJhcnkoYnJvb20pDQpgYGANCg0KVGhlIGV4YW1wbGUgZGF0YXNldCBzdXBwbGllZCB3aXRoIHtkaWR9Og0KDQpgYGB7cn0NCmRhdCA8LSBtcGR0YSAgIyBJbiBjYXNlIEkgd2FudGVkIHRvIGNoYW5nZSBhbnl0aGluZy4uLg0KaGVhZChkYXQpDQpgYGANCg0KRXN0aW1hdGUgQVRUKGcsIHQpIGZvciBlYWNoIGdyb3VwIF9nXyBhbmQgdGltZSBfdF86DQoNCmBgYHtyIHJvd3MucHJpbnQgPSAyMH0NCmRpZF9tb2QgPC0gYXR0X2d0KA0KICB5bmFtZSA9ICJsZW1wIiwNCiAgZ25hbWUgPSAiZmlyc3QudHJlYXQiLA0KICBjb250cm9sX2dyb3VwID0gIm5vdHlldHRyZWF0ZWQiLA0KICBpZG5hbWUgPSAiY291bnR5cmVhbCIsDQogIHRuYW1lID0gInllYXIiLA0KICBkYXRhID0gZGF0LA0KICBlc3RfbWV0aG9kID0gInJlZyIsDQogIGJhc2VfcGVyaW9kID0gInZhcnlpbmciDQopDQoNCmRpZF9tb2QNCmBgYA0KDQoNCk5vdyBteSBhdHRlbXB0LCBpbml0aWFsbHkgZm9jdXNzZWQgb24gdGhlIGVzdGltYXRlcy4gU3RhbmRhcmQgZXJyb3JzIGNhbiBjb21lIGxhdGVyIQ0KDQpXaGF0IG1hZGUgaW50dWl0aXZlIHNlbnNlOg0KDQoqIFdlJ3JlIHN3ZWVwaW5nIGFsb25nIHRpbWVzIGFuZCBncm91cHMgKHRoZSB5ZWFyIHdoZW4gYSB1bml0IGlzIGZpcnN0IHRyZWF0ZWQpLCBidWlsZGluZyB0aGUgY2Fub25pY2FsIDLDlzIgZGF0YXNldHMgYW5kIGVzdGltYXRpbmcgdGhlIHVzdWFsIFRXRkUgbW9kZWwgYXMgd2Ugem9vbSBhbG9uZy4NCg0KSGVyZSdzIHdoYXQgaW5pdGlhbGx5IHRyaXBwZWQgbWUgdXA6DQoNCiogX2F0dF9ndF8gdHJlYXRzIGdyb3VwID0gMCBhcyBuZXZlciB0cmVhdGVkLiBBIGJldHRlciBjaG9pY2UgbWlnaHQgaGF2ZSBiZWVuIGFueSBudW1iZXIgZ3JlYXRlciB0aGFuIHRoZSBtYXhpbXVtIHRpbWUgKGUuZy4sIHllYXIpIGluIHRoZSBkYXRhc2V0IChpbmNsdWRpbmcgX0luZl8pLg0KKiBBcyB3ZSBzd2VlcCBhbG9uZyBhbmQgYnVpbGQgdGhlIDLDlzIgZGF0YXNldHMsIHdlIGNvbnNpZGVyIGEgdW5pdCAidHJlYXRlZCIgaWYgaXQncyBldmVyIHRyZWF0ZWQgYW5kIGluIHRoZSBzZWNvbmQgdGltZSBwb2ludCwgaS5lLiwgc28gd2UgY2FuIGNoZWNrIGZvciBiYXNlbGluZSBwYXJhbGxlbCB0cmVuZHMuDQoqIElmIHdlIGFyZSBzdGlsbCBpbiB0aGUgdW50cmVhdGVkIHBoYXNlLCB0aGUgY29tcGFyaXNvbiB0aW1lIHBvaW50IGlzIG9uZSBiZWZvcmUgdGhlIGN1cnJlbnQgdGltZSBwb2ludC4gSWYgd2UgYXJlIGluIHRoZSB0cmVhdGVkIHBoYXNlLCB0aGVuIHRoZSBjb21wYXJpc29uIHRpbWUgcG9pbnQgaXMgdGhlIG9uZSBqdXN0IGJlZm9yZSB3aGVuIHRoZSB1bml0IGZpcnN0IHJlY2VpdmVkIHRyZWF0bWVudC4NCiogQWxzbyBhIGJpdCBvZiBzaWxsaW5lc3Mgd2l0aCBob3cgSSBzZXR1cCB0aGUgZml4ZWQgZWZmZWN0IG1vZGVsOiBJIHRyaWVkIHRvIGluY2x1ZGUgYSBtYWluIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50IGdyb3VwOyBob3dldmVyLCB0aGF0J3MgcGVyZmVjdGx5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgdW5pdCBmaXhlZCBlZmZlY3RzLCBvYnZzLg0KDQpgYGB7cn0NCkFUVF9ncm91cF90aW1lIDwtIGZ1bmN0aW9uKHRoZV9ncm91cCwgdGhlX3llYXIpIHsNCiAgIyBUaGUgZmlyc3QgdGltZSBwb2ludCB3ZSBjaG9vc2UgYXMgd2UgZ28gZGVwZW5kcyBvbiB3aGV0aGVyDQogICMgdGhlIHVuaXQgaXMgdHJlYXRlZCBpbiB0aGlzICJjYW5vbmljYWwiIDLDlzIgZGF0YXNldA0KICBjb21wYXJpc2lvbl95ZWFyIDwtIGlmZWxzZSh0aGVfeWVhciA8IHRoZV9ncm91cCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlX3llYXIgLSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVfZ3JvdXAgLSAxKQ0KICANCiAgdGhpc19kYXQgPC0gZGF0IHw+DQogICAgbXV0YXRlKHRyZWF0ID0gYXMubnVtZXJpYyhmaXJzdC50cmVhdCA9PSB0aGVfZ3JvdXApLA0KICAgICAgICAgICB0aW1lICA9IGFzLm51bWVyaWMoeWVhciA9PSB0aGVfeWVhcikpIHw+DQogICAgZmlsdGVyKHRyZWF0IHwgICAgICAgICAgICAgICAgIyBldmVyIHRyZWF0ZWQgKGN1cnJlbnQgZ3JvdXApDQogICAgICAgICAgIGZpcnN0LnRyZWF0ID09IDAgfCAgICAgIyBuZXZlciB0cmVhdGVkICh3ZWlyZCBjb252ZW50aW9uIG9mIHtkaWR9KQ0KICAgICAgICAgICB5ZWFyIDwgZmlyc3QudHJlYXQpIHw+ICMgbm90IHlldCB0cmVhdGVkIChvdGhlciBncm91cHMpDQogICAgZmlsdGVyKHllYXIgJWluJSBjKGNvbXBhcmlzaW9uX3llYXIsIHRoZV95ZWFyKSkNCiAgDQogIG1vZCA8LSBsbShsZW1wIH4gMCArIGZhY3Rvcihjb3VudHlyZWFsKSArIHRpbWUgKyB0aW1lOnRyZWF0LA0KICAgICAgICAgICAgZGF0YSA9IHRoaXNfZGF0KQ0KICBzdW1tYXJ5KG1vZCkgfD4NCiAgICB0aWR5KCkgfD4NCiAgICBmaWx0ZXIodGVybSA9PSAidGltZTp0cmVhdCIpIHw+DQogICAgbXV0YXRlKGdyb3VwID0gdGhlX2dyb3VwLCAuYmVmb3JlID0gInRlcm0iKSB8Pg0KICAgIG11dGF0ZSh5ZWFyID0gdGhlX3llYXIsIC5iZWZvcmUgPSAidGVybSIpIHw+DQogICAgbXV0YXRlKHN1Yl9uID0gbnJvdyh0aGlzX2RhdCkpIHw+DQogICAgcmVuYW1lKG15X2VzdCA9IGVzdGltYXRlKSB8Pg0KICAgIHNlbGVjdCgtdGVybSkNCn0NCmBgYA0KDQpOb3cgemFwIHRoZSB3aG9sZSBkYXRhc2V0IGFuZCBjb21wYXJlIHdpdGgge2RpZH0ncyBlc3RpbWF0ZXMuDQoNCmBgYHtyIHJvd3MucHJpbnQgPSAyMH0NCnJlcyA8LSBtYXAyKGRpZF9tb2QkZ3JvdXAsIGRpZF9tb2QkdCwgQVRUX2dyb3VwX3RpbWUpIHw+DQogIGJpbmRfcm93cygpIHw+DQogIG11dGF0ZShkaWRfZXN0ID0gZGlkX21vZCRhdHQsIC5hZnRlciA9ICJteV9lc3QiKSB8Pg0KICBtdXRhdGUoY29ycmVjdCA9IGFicyhteV9lc3QgLSBkaWRfZXN0KSA8IDFlLTYsIC5hZnRlciA9ICJkaWRfZXN0IikNCnN0b3BpZm5vdChhbGwocmVzJGNvcnJlY3QpKQ0KcmVzIHw+IHNlbGVjdChncm91cCwgeWVhciwgbXlfZXN0LCBkaWRfZXN0LCBjb3JyZWN0LCBzdWJfbikNCmBgYA0KDQpIdXJyYWggLSBpdCB3b3JrZWQhIEknbSBnb2luZyB0byB3b3JyeSBhYm91dCB0aGUgc3RhbmRhcmQgZXJyb3JzIGFub3RoZXIgZGF5Lg0KDQoNCiMjIyBQb29saW5nIHRoZSBBVFQoZyx0KXM/DQoNCkhlcmUgYXJlIHtkaWR9J3MgZXN0aW1hdGVzLCBwb29sZWQgYnkgZ3JvdXA6DQoNCmBgYHtyfQ0KZGlkX2FnZ19ncm91cCA8LSBhZ2d0ZShkaWRfbW9kLCB0eXBlID0gImdyb3VwIikNCmRpZF9hZ2dfZ3JvdXANCmBgYA0KDQoNCldlIGNhbiByZXBsaWNhdGUgdGhlIGVzdGltYXRlZCBieSBqdXN0IGF2ZXJhZ2luZyB0aGUgQVRUKGcsdCkgZXN0aW1hdGVzIGFjcm9zcyB0aGUgdCdzOg0KDQpgYGB7cn0NCnBvb2xfZXN0aW1hdGVzX25haXZlIDwtIGZ1bmN0aW9uKGVzdHMpIHsNCiAgZGF0YS5mcmFtZSgNCiAgICBteV9wb29sZWRfZXN0ID0gbWVhbihlc3RzKSwNCiAgICBuX3QgPSBsZW5ndGgoZXN0cykNCiAgKQ0KfQ0KDQphZ2dfcmVzIDwtIHJlcyB8Pg0KICBmaWx0ZXIoeWVhciA+PSBncm91cCkgfD4NCiAgZ3JvdXBfYnkoZ3JvdXApIHw+DQogIHN1bW1hcmlzZShwb29sX2VzdGltYXRlc19uYWl2ZShteV9lc3QpKSB8Pg0KICBtdXRhdGUoZGlkX2FnZ19lcyA9IGRpZF9hZ2dfZ3JvdXAkYXR0LmVndCwgLmFmdGVyID0gIm15X3Bvb2xlZF9lc3QiKSB8Pg0KICBtdXRhdGUoY29ycmVjdCA9IGFicyhteV9wb29sZWRfZXN0IC0gZGlkX2FnZ19lcykgPCAxZS02KQ0Kc3RvcGlmbm90KGFsbChhZ2dfcmVzJGNvcnJlY3QpKQ0KDQphZ2dfcmVzDQpgYGANCg0KVGhhdCB3b3Jrcy4NCg0KDQojIyMgUmVmZXJlbmNlcw0KDQpDYWxsYXdheSwgQi4sICYgU2FudOKAmUFubmEsIFAuIEguIEMuICgyMDIxKS4gW0RpZmZlcmVuY2UtaW4tRGlmZmVyZW5jZXMgd2l0aCBtdWx0aXBsZSB0aW1lIHBlcmlvZHNdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouamVjb25vbS4yMDIwLjEyLjAwMSkuIEpvdXJuYWwgb2YgRWNvbm9tZXRyaWNzLCAyMjUoMiksIDIwMOKAkzIzMC4gDQoNCg==