DiD Échelonnée

Module 4 — Callaway & Sant’Anna (2021)

Master GPE — FERDI IHEDD

2026-03-17

Rappel du problème

Le TWFE est biaisé quand :

  1. Les unités sont traitées à des moments différents (traitement échelonné)
  2. Les effets du traitement sont hétérogènes (varient entre unités et/ou dans le temps)

Goodman-Bacon (2021) montre que le TWFE utilise des unités déjà traitées comme contrôles → les coefficients peuvent être négatifs même si tous les effets individuels sont positifs !

Astuce

Solution : Construire des estimateurs qui ne comparent jamais des unités traitées à d’autres unités traitées.

L’approche de Callaway & Sant’Anna (2021)

Idée clé : Plutôt qu’un seul coefficient, estimer des effets par groupe et par période : \(ATT(g, t)\)

Définitions : - \(g\) (groupe) : l’année où une unité reçoit pour la première fois le traitement - \(t\) (période) : l’année calendaire - \(ATT(g,t)\) : effet moyen du traitement pour les unités du groupe \(g\) à la période \(t\)

Intuition :

Pour chaque cohorte \(g\), on compare : - Les unités traitées en \(g\) à la période \(t\) - vs. les unités qui ne seront jamais (ou pas encore) traitées

→ On évite les mauvais groupes de comparaison !

Le paramètre ATT(g,t) — définition formelle

Paramètre central :

\[ATT(g, t) = E[Y_t(g) - Y_t(0) \mid G = g]\]

  • \(Y_t(g)\) : résultat potentiel si traité en \(g\)
  • \(Y_t(0)\) : résultat potentiel si jamais traité
  • \(G = g\) : appartenir au groupe traité en \(g\)

Cette quantité mesure : L’effet moyen du traitement pour le groupe \(g\), à la période \(t\)

Note

Quand \(t < g\) : périodes pré-traitement\(ATT(g,t)\) doit être ≈ 0 (test de pré-tendances)

Quand \(t \geq g\) : périodes post-traitement → mesure l’effet causal

Hypothèse de tendances parallèles (version CS)

Hypothèse (Parallel Trends conditionnelle) :

Pour tout groupe \(g\) et toutes périodes \(t < g\) :

\[E[Y_t(0) - Y_{g-1}(0) \mid G = g] = E[Y_t(0) - Y_{g-1}(0) \mid C]\]

\(C\) est le groupe de comparaison (jamais traités ou pas encore traités).

→ En l’absence de traitement, l’évolution du groupe \(g\) aurait été la même que celle du groupe de comparaison.

Groupes de comparaison disponibles

Option 1 : Jamais traités ("nevertreated")

Utilise uniquement les unités qui ne reçoivent jamais le traitement comme groupe de contrôle.

✅ Groupe de contrôle “propre” ⚠️ Peut être petit ou absent

Option 2 : Pas encore traités ("notyettreated")

Utilise toutes les unités qui ne sont pas encore traitées à la période \(t\) comme contrôle.

✅ Plus d’observations → plus de précision ⚠️ Suppose que les unités traitées plus tard sont de bons contrôles

Astuce

Par défaut, CS recommande "nevertreated" pour maximiser la validité interne.

Application africaine — Traitement échelonné

Cas typique en Afrique de l’Ouest :

Programme Filets Sociaux Productifs (Sénégal) : - 2015 : 3 régions pilotes (Louga, Matam, Kédougou) - 2017 : extension à 4 nouvelles régions - 2019 : extension à 3 régions supplémentaires - Jamais traitées : 2 régions hors programme

→ Structure identique à mpdta : staggered adoption

Pourquoi ne pas utiliser TWFE ici ?

Le TWFE utiliserait les régions traitées en 2015 comme “contrôle” pour celles traitées en 2017 — faussant le résultat si les premiers bénéficiaires ont été transformés par le programme.

Callaway & Sant’Anna comparent chaque vague uniquement aux jamais traités → estimation propre.

Implémentation en R — package did

Voir le code R
library(did)

# Estimation des ATT(g,t)
att_gt_res <- att_gt(
  yname         = "lemp",         # variable de résultat
  tname         = "year",         # variable de temps
  idname        = "countyreal",   # identifiant des unités
  gname         = "first.treat",  # année du 1er traitement (0 = jamais traité)
  data          = mpdta,
  control_group = "nevertreated", # groupe de comparaison
  est_method    = "reg"           # méthode d'estimation
)

summary(att_gt_res)
#> 
#> Call:
#> att_gt(yname = "lemp", tname = "year", idname = "countyreal", 
#>     gname = "first.treat", data = mpdta, control_group = "nevertreated", 
#>     est_method = "reg")
#> 
#> 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:
#>  Group Time ATT(g,t) Std. Error [95% Simult.  Conf. Band]  
#>   2004 2004  -0.0105     0.0237       -0.0744      0.0534  
#>   2004 2005  -0.0704     0.0299       -0.1510      0.0101  
#>   2004 2006  -0.1373     0.0377       -0.2386     -0.0359 *
#>   2004 2007  -0.1008     0.0342       -0.1928     -0.0088 *
#>   2006 2004   0.0065     0.0230       -0.0554      0.0685  
#>   2006 2005  -0.0028     0.0194       -0.0550      0.0495  
#>   2006 2006  -0.0046     0.0182       -0.0536      0.0445  
#>   2006 2007  -0.0412     0.0203       -0.0958      0.0133  
#>   2007 2004   0.0305     0.0144       -0.0083      0.0694  
#>   2007 2005  -0.0027     0.0170       -0.0486      0.0431  
#>   2007 2006  -0.0311     0.0186       -0.0812      0.0191  
#>   2007 2007  -0.0261     0.0168       -0.0713      0.0192  
#> ---
#> Signif. codes: `*' confidence band does not cover 0
#> 
#> P-value for pre-test of parallel trends assumption:  0.16812
#> Control Group:  Never Treated,  Anticipation Periods:  0
#> Estimation Method:  Outcome Regression

Visualisation des ATT(g,t) bruts

Voir le code R
ggdid(att_gt_res,
      title = "ATT(g,t) — Impact du salaire minimum sur l'emploi des jeunes")

Agrégation des ATT(g,t)

Pourquoi agréger ? On a des dizaines de \(ATT(g,t)\) — on veut résumer l’information en quelques paramètres interprétables.

Trois types d’agrégation (aggte()) :

Type Paramètre Interprétation
"simple" Effet moyen global ATT moyen sur tous les traités
"group" Effet par cohorte ATT moyen par groupe \(g\)
"dynamic" Effet par période relative Event study — \(k\) périodes après traitement

Agrégation simple — ATT moyen

Voir le code R
# Effet moyen global
agg_simple <- aggte(att_gt_res, type = "simple")
summary(agg_simple)
#> 
#> Call:
#> aggte(MP = att_gt_res, type = "simple")
#> 
#> 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> 
#> 
#> 
#>    ATT    Std. Error     [ 95%  Conf. Int.]  
#>  -0.04        0.0119    -0.0633     -0.0166 *
#> 
#> 
#> ---
#> Signif. codes: `*' confidence band does not cover 0
#> 
#> Control Group:  Never Treated,  Anticipation Periods:  0
#> Estimation Method:  Outcome Regression

Note

Lecture : L’effet moyen du salaire minimum sur l’emploi des jeunes est d’environ -3.4 % sur l’ensemble des comtés traités.

Agrégation par groupe (cohorte)

Voir le code R
# Effet moyen par cohorte de traitement
agg_group <- aggte(att_gt_res, type = "group")
summary(agg_group)
#> 
#> Call:
#> aggte(MP = att_gt_res, 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:  
#>     ATT    Std. Error     [ 95%  Conf. Int.]  
#>  -0.031         0.012    -0.0546     -0.0075 *
#> 
#> 
#> Group Effects:
#>  Group Estimate Std. Error [95% Simult.  Conf. Band]  
#>   2004  -0.0797     0.0285       -0.1413     -0.0182 *
#>   2006  -0.0229     0.0167       -0.0591      0.0132  
#>   2007  -0.0261     0.0169       -0.0625      0.0104  
#> ---
#> Signif. codes: `*' confidence band does not cover 0
#> 
#> Control Group:  Never Treated,  Anticipation Periods:  0
#> Estimation Method:  Outcome Regression

Astuce

Permet de détecter l’hétérogénéité des effets selon le moment de traitement.

Agrégation dynamique — event study

Voir le code R
# Event study agrégée (periods relatives au traitement)
agg_dynamic <- aggte(att_gt_res, type = "dynamic")

ggdid(agg_dynamic,
      title = "Event Study — Callaway & Sant'Anna",
      ylab  = "ATT estimé",
      xlab  = "Périodes relatives au traitement")

Lecture du graphique d’event study

Que regarder ?

  1. Avant le traitement (\(k < 0\)) : → Les barres doivent passer par 0 (test pré-tendances)

  2. À l’impact (\(k = 0\)) : → Première estimation de l’effet

  3. Après le traitement (\(k > 0\)) : → Persistance ou atténuation de l’effet

Intervalle de confiance : Barres à 95 % calculées par bootstrap.

Comparaison TWFE vs Callaway-Sant’Anna

Voir le code R
# TWFE (pour comparaison)
twfe <- feols(lemp ~ treat_tv | countyreal + year, data = mpdta, cluster = ~countyreal)

# CS simple
cs_simple <- aggte(att_gt_res, type = "simple")

cat("=== Comparaison des estimateurs ===\n")
#> === Comparaison des estimateurs ===
Voir le code R
cat("TWFE          :", round(coef(twfe)["treat_tv"], 4), "\n")
#> TWFE          : -0.0365
Voir le code R
cat("CS (simple)   :", round(cs_simple$overall.att, 4), "\n")
#> CS (simple)   : -0.04
Voir le code R
cat("\nLes deux sont similaires ici, mais peuvent diverger\n")
#> 
#> Les deux sont similaires ici, mais peuvent diverger
Voir le code R
cat("fortement quand les effets sont très hétérogènes.\n")
#> fortement quand les effets sont très hétérogènes.

Quand les estimateurs divergent-ils ?

Le TWFE et CS divergent davantage quand :

  1. Les effets varient fortement selon le groupe ou le temps (forte hétérogénéité)
  2. Beaucoup d’unités sont traitées tôt (les “early adopters” servent alors souvent de contrôle)
  3. L’effet du traitement croît (ou décroît) significativement après le traitement
  4. Il y a peu d’unités jamais traitées

→ Plus les effets sont hétérogènes, plus le TWFE est suspect.

Baker et al. (2022) : Simulations montrant que le coefficient TWFE peut être de signe opposé à la plupart des effets individuels !

L’inférence statistique avec CS

Voir le code R
# Bootstrap pour les erreurs standard
att_gt_boot <- att_gt(
  yname         = "lemp",
  tname         = "year",
  idname        = "countyreal",
  gname         = "first.treat",
  data          = mpdta,
  control_group = "nevertreated",
  bstrap        = TRUE,     # bootstrap (recommandé)
  biters        = 999,      # nombre d'itérations bootstrap
  print_details = FALSE
)

agg_boot <- aggte(att_gt_boot, type = "simple")
summary(agg_boot)
#> 
#> Call:
#> aggte(MP = att_gt_boot, type = "simple")
#> 
#> 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> 
#> 
#> 
#>    ATT    Std. Error     [ 95%  Conf. Int.]  
#>  -0.04        0.0118    -0.0631     -0.0168 *
#> 
#> 
#> ---
#> Signif. codes: `*' confidence band does not cover 0
#> 
#> Control Group:  Never Treated,  Anticipation Periods:  0
#> Estimation Method:  Doubly Robust

Résumé du Module 4

À retenir :

  1. Le TWFE est biaisé avec des traitements échelonnés et des effets hétérogènes
  2. Callaway & Sant’Anna (2021) estiment les \(ATT(g,t)\) par groupe et par période
  3. Les groupes de comparaison : jamais traités (nevertreated) ou pas encore traités (notyettreated)
  4. En R : att_gt()aggte()ggdid()
  5. L’agrégation "dynamic" produit un event study propre
  6. Tester les pré-tendances avec les périodes pré-traitement (\(k < 0\))

Prochain module : L’approche de de Chaisemartin & D’Haultfoeuille — une alternative avec intuition différente

Interpréter l’ATT pour un décideur

Traduction pratique du résultat CS (type aggte(type="simple")) :

Supposons overall.att = -0.034 (comme dans nos données mpdta) :

Message pour votre ministre : “Sur l’ensemble des comtés ayant bénéficié d’une hausse de salaire minimum, l’emploi des jeunes a diminué en moyenne de 3,4 % dans les années suivant la réforme. Cet effet est estimé en comparant chaque vague d’adoption uniquement à des comtés qui n’avaient pas encore bénéficié de la réforme, ce qui garantit la solidité de la comparaison.”

Astuce

Avantage CS pour les rapports : L’agrégation "group" permet de montrer si l’effet varie selon la vague d’adoption — information précieuse pour comprendre pourquoi un programme fonctionne mieux dans certaines régions/années.