Difference-in-Differences: метод quasi-экспериментов

Что такое Difference-in-Differences

Difference-in-Differences (DiD) — статистический метод для оценки причинного effect, когда нельзя провести рандомизированный эксперимент.

Идея: сравнить изменение outcome до и после intervention в treated group с изменением в control group. Разница этих разниц — эффект intervention.

Используется когда:

  • AB-тест невозможен (территориальные rollouts, policy changes).
  • Intervention уже произошла — нужно оценить effect постфактум.
  • Natural experiments в данных.

Формула

Простейшая форма:

DiD = (Y_after_treated - Y_before_treated) - (Y_after_control - Y_before_control)

Первая разница — изменение в treated group. Вторая — в control group. Их разница — эффект treatment, очищенный от общих трендов.

Пример

Компания запустила новую фичу в RU. DE — control (фичу не получили).

Средняя retention до запуска:

  • RU: 35%
  • DE: 33%

После запуска:

  • RU: 40% (+5pp)
  • DE: 34% (+1pp)

DiD estimate:

(40% - 35%) - (34% - 33%) = 5pp - 1pp = 4pp

Эффект фичи на retention = +4 процентных пункта. Общий 1% рост (наблюдаемый в DE) — это тренд, не связанный с фичей.

Без DiD можно было бы сказать «retention вырос на 5pp» — и переоценить эффект.

Assumption: Parallel trends

Главное предположение DiD — parallel trends. Без treatment обе группы изменялись бы одинаково.

Это не testable directly (не наблюдаем counterfactual), но можно проверить pre-treatment periods:

График retention за 6 месяцев до запуска:
- RU: 30% → 35% (рост на 5pp, 0.8pp/месяц)
- DE: 28% → 33% (рост на 5pp, 0.8pp/месяц)

Если pre-trend параллельны — assumption правдоподобна.

Если treated растёт быстрее ДО treatment — красный флаг. Дальнейший рост может быть продолжением тренда, а не эффектом.

DiD в регрессии

Более гибкий способ — через регрессию с interaction:

Y = β₀ + β₁·Treated + β₂·Post + β₃·(Treated × Post) + ε

Где:

  • Treated = 1 если в treated group
  • Post = 1 если после intervention
  • Treated × Post = 1 только в treated group после intervention

Коэффициент β₃ — DiD estimate.

Преимущества регрессии:

  • Можно добавить controls (очистить от других факторов).
  • Легко получить SE и p-values.
  • Легко расширить на multiple periods, multiple treatments.

Python implementation

import statsmodels.formula.api as smf
import pandas as pd

# Данные: user_id, group ('treated'/'control'), period ('pre'/'post'), retention
df['treated'] = (df['group'] == 'treated').astype(int)
df['post'] = (df['period'] == 'post').astype(int)
df['treat_post'] = df['treated'] * df['post']

model = smf.ols('retention ~ treated + post + treat_post', data=df).fit()
print(model.summary())

# Коэффициент treat_post — DiD estimate

Если treat_post значим и положителен — treatment увеличил retention.

Multiple time periods

Для событий с длительным rollout — Two-Way Fixed Effects (TWFE):

Y_it = α_i + γ_t + β·Treatment_it + ε_it

Где:

  • α_i — fixed effect unit (user, region)
  • γ_t — fixed effect time
  • Treatment_it = 1 если unit i получил treatment к time t

Коэффициент β — средний effect treatment.

В Python:

import statsmodels.formula.api as smf

model = smf.ols(
    'retention ~ treatment + C(user_id) + C(week)',
    data=df
).fit()

Fixed effects убирают unobserved time-invariant differences и common time shocks. Focus — на variation от treatment.

Staggered DiD — новая проблема

Если treatment наступает в разное время для разных unit (staggered rollout) — классический TWFE может давать смещённые оценки.

Проблема: когда уже-treated unit используется как control для позже-treated unit, возникает bias.

Современные методы (после 2021):

  • Callaway-Sant'Anna estimator.
  • Sun-Abraham estimator.
  • De Chaisemartin-D'Haultfœuille.

Для crucial analysis (особенно в academic papers) используют эти методы. Для rough business estimates TWFE часто достаточно.

Causal inference — отличный skill для продвинутых аналитиков. В тренажёре Карьерник есть задачи по AB-тестам, causal inference и статистике.

Event study

Расширение DiD для визуализации dynamic effects.

Идея: оцениваем effect в каждый период относительно treatment:

Y_it = α_i + γ_t + Σ β_k · D_(it, k) + ε_it

Где D_(it, k) = 1 если unit i в k-м периоде относительно своего treatment event.

График β_k по k показывает:

  • Pre-treatment (k < 0): должен быть близок к 0 (parallel trends).
  • Post-treatment (k >= 0): показывает dynamic effect.

Полезно видеть:

  • Immediate vs delayed effect.
  • Peak и fade out.
  • Violation of parallel trends (pre-trends не zero).

Real-world examples

Card & Krueger (1994). Классика: повышение минимальной зарплаты в New Jersey. Control — Pennsylvania. Нашли, что повышение не снизило занятость (контр-интуитивный результат).

Google Ads rollout. Запуск feature в отдельных регионах. DiD показывает incremental impact.

Mobile Apps. Feature rollout по iOS versions. iOS 16 vs iOS 15 — DiD оценка feature.

Pricing changes. Повышение цены в одной категории. Control — похожие категории без повышения.

Company M&A. Эффект purchase на target company — DiD vs similar company peers.

Когда DiD не работает

Anticipation effect. Люди знают о будущем treatment и меняют поведение заранее. Parallel trends violated.

Spillovers. Control group тоже затронута treatment (через competitors, mutual users). Effect underestimated.

Shocks между treatments. Что-то другое случилось в treated area одновременно с treatment.

Small sample. Мало units → big standard errors. DiD нуждается в multiple treated и control units.

Non-random selection. Treatment назначен не случайно, а на основе characteristics, которые сами меняются во времени.

DiD с controls

Добавление covariates делает оценку robust:

model = smf.ols(
    'retention ~ treated + post + treat_post + age + tenure_days + country',
    data=df
).fit()

Controls «очищают» DiD от confounding. Особенно важно если treated/control отличаются по observed characteristics.

Но: control variables не должны сами меняться от treatment (post-treatment bias). Например, tenure_days растёт со временем одинаково в обеих группах — OK. Но если treatment influenced tenure (через retention) — problematic.

SUTVA assumption

Stable Unit Treatment Value Assumption: treatment одного unit не влияет на outcome других.

Нарушения:

  • Network effects. В social network treatment пользователя влияет на его friends.
  • Market equilibrium. В ride-sharing если drivers get subsidies, riders тоже бенефит.

Если SUTVA violated — DiD оценки смещены. Решения: cluster-level randomization, network-aware methods.

Типичные ошибки

Skipping parallel trends check. Критический шаг. Без него DiD бессмыслен.

Cherry-picking periods. Выбор «удобных» pre/post periods, где результат выгодный. Pre-register analysis.

Ignoring standard errors. Simple OLS SE могут underestimate. Использовать clustered SE (на уровне group/region).

Treating staggered as simple DiD. Для multiple treatment times — используйте современные methods.

Не показывать pre-trends. Visualization убеждает stakeholders, что parallel trends holds.

Читайте также

FAQ

DiD и AB-тест — когда что?

AB-тест предпочтительнее если доступен (randomization дает clean causality). DiD когда AB невозможен (territorial, regulatory, timing constraints).

Можно ли DiD с одним treated unit?

Сложно. Синтетический контроль — расширение DiD для такого случая.

Parallel trends — как проверить?

Визуально (график pre-trends), статистически (test на significance pre-trends). Plus robustness checks с different controls.

DiD оценка — causal?

Да, ЕСЛИ parallel trends assumption holds. Это главное условие.