Exercices — Module 3

DiD avec Effets Fixes Bidirectionnels (TWFE)

Auteur·rice

Master GPE — FERDI IHEDD

Date de publication

17 mars 2026

Objectifs de ce module

À la fin de ces exercices, vous saurez :

  1. Charger et explorer le dataset mpdta
  2. Estimer un modèle TWFE avec fixest::feols()
  3. Comparer les résultats avec et sans effets fixes
  4. Réaliser et interpréter un graphique d’event study
  5. Utiliser les erreurs standard groupées
Travailler dans RStudio ?

Téléchargez le script R complet du module avec tous les exercices à compléter :

⬇ Télécharger le script R — Module 3

Ouvrez-le dans RStudio et complétez les ___ au fur et à mesure. Exécutez bloc par bloc avec Ctrl+Enter.


Pourquoi ce concept est-il crucial pour un fonctionnaire ?

Dans la réalité des données administratives africaines et asiatiques, les unités (communes, districts, hôpitaux, écoles) sont très hétérogènes : une commune urbaine du Sénégal est incomparable à une commune rurale du Sahel. Les effets fixes bidirectionnels (TWFE) permettent de “contrôler” cette hétérogénéité permanente et les chocs communs à toutes les unités (crises économiques, sécheresses), rendant la comparaison beaucoup plus juste. C’est le modèle standard dans les évaluations soumises aux revues académiques et aux rapports de la Banque mondiale.


1 Exploration des données mpdta

1.1 Exercice 3.1 — Charger et explorer mpdta

Contexte : Les données mpdta proviennent de l’étude de Callaway & Sant’Anna (2021) sur l’impact des hausses de salaire minimum sur l’emploi des jeunes aux États-Unis. Imaginez que vous travaillez sur un contexte similaire pour le Sénégal : plusieurs régions adoptent un salaire minimum régional à des dates différentes (2004, 2005, 2006), et vous voulez évaluer l’impact sur le niveau d’emploi. La structure des données est identique — seul le contexte change.

nb_unites <- n_distinct(mpdta$countyreal)
cat("Nombre de comtés :", nb_unites, "\n")  # 500

annees <- sort(unique(mpdta$year))
cat("Années :", annees, "\n")  # 2003 2004 2005 2006 2007

prop_jamais <- mpdta |>
  filter(year == min(year)) |>
  summarise(prop = mean(first.treat == 0)) |>
  pull(prop)
cat("Part jamais traités :", round(100 * prop_jamais, 1), "%\n")  # environ 20%

Interprétation : Les données couvrent 500 comtés sur 5 ans (2003-2007). Environ 20 % des comtés n’ont jamais été traités et serviront de groupe de contrôle “pur”. Dans un contexte de politique publique en Afrique, ce pourcentage est crucial : trop peu de contrôles non-traités peut fragiliser l’identification causale.

Point clé : Toujours vérifier combien d’unités sont dans chaque vague de traitement et combien ne sont jamais traitées. Un déséquilibre fort (ex: 5 % seulement de jamais-traités) peut rendre les estimations instables.


1.2 Exercice 3.2 — Statistiques descriptives

mpdta_desc <- mpdta |>
  mutate(
    groupe = case_when(
      first.treat == 0    ~ "Jamais traité",
      first.treat == 2004 ~ "Traité en 2004",
      first.treat == 2005 ~ "Traité en 2005",
      first.treat == 2006 ~ "Traité en 2006",
      TRUE                ~ "Autre"
    )
  )

resume <- mpdta_desc |>
  group_by(groupe, year) |>
  summarise(moy_lemp = mean(lemp), n = n(), .groups = "drop")

ggplot(resume, aes(x = year, y = moy_lemp, color = groupe, group = groupe)) +
  geom_line(size = 1.1) +
  geom_point(size = 3) +
  labs(title = "Tendances du log emploi par groupe de traitement",
       x = "Année", y = "Log emploi moyen (lemp)", color = "Groupe") +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom")

Interprétation : Observez attentivement les courbes avant les dates de traitement respectives. Si les courbes sont approximativement parallèles avant 2004, cela est encourageant pour la validité de la DiD. Une divergence visible avant le traitement serait un signal d’alarme.

Point clé : Ce graphique de tendances brutes est votre premier “diagnostic” avant toute estimation formelle. Dans tout rapport d’évaluation sérieux, ce graphique doit apparaître en premier.


2 Estimation TWFE

2.1 Exercice 3.3 — Modèles emboîtés

Contexte : Pour illustrer la valeur ajoutée des effets fixes, imaginez que vous évaluez un programme de vaccination dans des districts du Mali. Certains districts sont naturellement plus riches, mieux équipés, et ont de meilleurs indicateurs de santé avant le programme (hétérogénéité permanente). De plus, une épidémie de choléra en 2005 a touché tous les districts simultanément (choc temporel commun). Sans effets fixes, votre estimateur mélangerait l’effet du programme avec ces facteurs. Comparez maintenant ces trois spécifications :

Dans fixest::feols(), les effets fixes s’ajoutent après le | dans la formule. Pour les effets fixes individuels (comté), écrivez | countyreal. Pour le TWFE (comté + année), écrivez | countyreal + year.

# Syntaxe feols avec effets fixes :
# feols(Y ~ X | ef1 + ef2, data = ..., cluster = ~var_cluster)
#
# Modèle 2 : effets fixes comté uniquement
feols(lemp ~ treat_tv | countyreal, data = mpdta)
#
# Modèle 3 : TWFE = effets fixes comté ET année
feols(lemp ~ treat_tv | countyreal + year, data = mpdta, cluster = ~countyreal)
modele_ols    <- feols(lemp ~ treat_tv, data = mpdta)
modele_ef_ind <- feols(lemp ~ treat_tv | countyreal, data = mpdta)
modele_twfe   <- feols(lemp ~ treat_tv | countyreal + year, data = mpdta, cluster = ~countyreal)

etable(modele_ols, modele_ef_ind, modele_twfe,
       headers = c("OLS", "EF comté", "TWFE"), digits = 4, se.below = TRUE)

# Interprétation :
# - OLS : fortement biaisé (pas de contrôle des effets fixes)
# - EF comté : contrôle les différences permanentes, mais pas les chocs temporels
# - TWFE : le plus complet — compare les évolutions relatives

Interprétation : Le passage de l’OLS au TWFE change généralement l’estimateur de manière substantielle. L’OLS est biaisé par les différences permanentes entre comtés (certains comtés ont toujours eu plus d’emploi). Les effets fixes comté “demeaning” ces différences. Les effets fixes année absorbent les chocs communs (récessions, crises). Le TWFE isole les variations “dans les unités, dans le temps” au-delà des tendances communes.

Point clé : Dans les données de politique publique en pays en développement, ignorer les effets fixes peut conduire à des biais massifs. Toujours préférer le TWFE à l’OLS simple pour les données de panel.

Référence : Wooldridge (2010) Econometric Analysis of Cross Section and Panel Data, chap. 10-11 pour les estimateurs Within et TWFE.


2.2 Exercice 3.4 — Erreurs standard groupées

twfe_ols     <- feols(lemp ~ treat_tv | countyreal + year, data = mpdta)
twfe_hc1     <- feols(lemp ~ treat_tv | countyreal + year, data = mpdta, se = "hetero")
twfe_cluster <- feols(lemp ~ treat_tv | countyreal + year, data = mpdta, cluster = ~countyreal)

etable(twfe_ols, twfe_hc1, twfe_cluster,
       headers = c("OLS std.", "HC1", "Groupées (comté)"), digits = 4)

# Les erreurs groupées sont les plus larges → intervalles de confiance plus larges
# → interférence statistique plus conservative (recommandée pour les DiD)

Interprétation : Les erreurs standard groupées (clustered SE) sont systématiquement plus larges que les erreurs OLS standard. Cela signifie que les intervalles de confiance sont plus larges et la conclusion statistique plus conservative. Dans les données de panel, les observations d’une même unité (même comté, même commune) sont corrélées dans le temps — les erreurs OLS standard ignorent cette corrélation et sous-estiment l’incertitude.

Point clé : En DiD, les erreurs standard groupées au niveau de l’unité (commune, district, région) sont la norme recommandée. Les utiliser est un signe de rigueur méthodologique que les reviewers et les partenaires techniques (Banque mondiale, BAD) attendent systématiquement.

Référence : Bertrand, Duflo & Mullainathan (2004) “How Much Should We Trust Differences-in-Differences Estimates?” Quarterly Journal of Economics.


3 Test des pré-tendances

3.1 Exercice 3.5 — Event study avec fixest

Contexte : Vous devez convaincre le Comité de Pilotage du programme que votre évaluation est crédible. La principale objection qui vous sera faite : “Les communes qui ont adopté la réforme en premier étaient peut-être déjà sur une meilleure trajectoire avant la réforme.” L’event study est votre réponse à cette objection : si les coefficients pré-traitement sont proches de zéro, les tendances étaient bien parallèles avant l’intervention.

La fonction sunab() prend deux arguments : (1) la variable indiquant l’année du premier traitement pour chaque unité (c’est first.treat dans mpdta), et (2) la variable temporelle (c’est year). Elle génère automatiquement les termes d’interaction pour chaque période relative au traitement.

# La syntaxe sunab() pour l'event study :
# feols(Y ~ sunab(var_groupe, var_temps) | EF_unité + EF_temps, ...)
#
# Dans mpdta :
# - var_groupe = first.treat  (année du 1er traitement, 0 si jamais traité)
# - var_temps  = year         (variable temporelle)
es_modele <- feols(
  lemp ~ sunab(first.treat, year) | countyreal + year,
  data = mpdta, cluster = ~countyreal
)
es_modele <- feols(
  lemp ~ sunab(first.treat, year) | countyreal + year,
  data    = mpdta,
  cluster = ~countyreal
)

iplot(es_modele,
      main = "Event Study — Impact du salaire minimum sur l'emploi des jeunes (Sun & Abraham)",
      xlab = "Périodes relatives au traitement",
      ylab = "Estimateur (log emploi)",
      col  = "#C2185B")

# Interprétation :
# - Périodes <0 : coefficients proches de zéro → tendances parallèles supportées
# - Périodes ≥0 : effets négatifs → le salaire minimum réduit l'emploi des jeunes

Interprétation : Le graphique d’event study est l’outil de validation le plus puissant de la DiD. Les barres d’intervalle de confiance pour les périodes avant le traitement (k = -2, -1) doivent inclure zéro — c’est ce qu’on appelle “pas de pré-tendances significatives”. Les périodes post-traitement (k = 0, 1, 2…) révèlent la trajectoire de l’effet causal dans le temps.

Point clé : L’approche Sun & Abraham (2021) corrige un biais présent dans l’event study TWFE classique lorsqu’il y a des traitements échelonnés. C’est donc la méthode recommandée pour ce type de données.

Référence : Sun, L. & Abraham, S. (2021) “Estimating dynamic treatment effects in event studies with heterogeneous treatment effects.” Journal of Econometrics.


3.2 Exercice 3.6 — Interpréter le graphique

Les coefficients pré-traitement (périodes -1, -2, -3…) doivent être proches de zéro et non significatifs. Cela valide l’hypothèse de tendances parallèles : les comtés traités et non traités avaient des évolutions similaires avant la mise en place du salaire minimum.

Si ces coefficients étaient significativement différents de zéro, cela suggérerait que la réforme a été anticipée, ou que les comtés traités différaient systématiquement dans leurs tendances avant même le traitement.

Dans un contexte africain ou asiatique, les violations de pré-tendances surviennent souvent parce que : (1) les programmes ciblent délibérément les zones les plus pauvres qui ont des tendances différentes (ciblage géographique), (2) les communes ont anticipé la réforme et commencé à se préparer avant son application officielle, ou (3) d’autres politiques contemporaines ont touché différemment les groupes traités et contrôles (contamination).

Point clé : Le test des pré-tendances ne “prouve” pas la validité de la DiD, mais son échec est un signal d’alarme sérieux. Un résultat non significatif est nécessaire mais pas suffisant.


3.3 Discussion — Application à votre contexte

Pensez à une politique publique de votre pays ou secteur que vous souhaiteriez évaluer.

  1. Quel serait le groupe traité et le groupe de contrôle ?
  2. Quelle serait la variable de résultat ?
  3. Pourquoi la DiD serait-elle (ou ne serait-elle pas) appropriée ici ?
  4. Quelle menace principale à l’hypothèse de tendances parallèles identifieriez-vous ?

Discutez en binôme pendant 5 minutes, puis partagez avec le groupe.


Fin du Module 3

Compétences validées :

  • ✅ Explorer et décrire mpdta
  • ✅ Comparer OLS, EF individuels, TWFE
  • ✅ Utiliser fixest::feols() avec effets fixes et erreurs groupées
  • ✅ Réaliser un event study avec sunab()
  • ✅ Tester et interpréter les pré-tendances

Prochain exercice : Module 4 — Callaway & Sant’Anna avec le package did