Difference-in-Differences простыми словами

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Зачем это знать

Marketplace запустил фичу в одном городе, в другом нет — как измерить эффект? A/B-тест невозможен: нельзя юзеру одновременно «видеть и не видеть». На помощь приходит DiD — классика quasi-experimental methods.

На собесах в B2C / marketplace / delivery компаниях DiD — обязательный навык для middle+ аналитика.

Короткое объяснение

Difference-in-Differences сравнивает изменения в treatment и control группах до и после воздействия.

Effect = (Treatment_after - Treatment_before) - (Control_after - Control_before)

Первая разница — что случилось у treatment. Вторая — что случилось у control (baseline trend). Разница разниц — чистый эффект.

Пример

Москва получила фичу, Санкт-Петербург — нет.

До После
Москва 100 orders 130 orders
СПб 90 orders 110 orders
  • Москва: +30
  • СПб: +20 (общий тренд сезонный)

Effect = 30 - 20 = +10 orders — чистый эффект фичи.

Без DiD мы бы сказали «фича дала +30», что неверно (+20 был бы и без фичи).

Parallel trends assumption

Ключевое assumption: без воздействия тренды в двух группах были бы параллельны.

Т.е. разница между Москвой и СПб оставалась бы такой же.

Если это не так — DiD не работает.

Как проверить

Посмотрите исторические данные. Если тренды паралельны в pre-period — assumption likely holds.

В формуле

Y = α + β₁ × Treatment + β₂ × Post + β₃ × (Treatment × Post) + ε

Где:

  • Treatment = 1 если в treatment group
  • Post = 1 если после воздействия
  • β₃ — это и есть эффект (DiD estimate)

Пример в SQL

SELECT
    city, period,
    SUM(orders) AS total
FROM data
WHERE city IN ('Moscow', 'SPb')
GROUP BY 1, 2;

-- Потом в Python / Excel:
effect = (moscow_after - moscow_before) - (spb_after - spb_before)

В Python

import statsmodels.api as sm

data['treatment'] = (data['city'] == 'Moscow').astype(int)
data['post'] = (data['period'] == 'after').astype(int)
data['interaction'] = data['treatment'] * data['post']

X = sm.add_constant(data[['treatment', 'post', 'interaction']])
model = sm.OLS(data['orders'], X).fit()
print(model.summary())  # коэффициент interaction = DiD estimate

Когда использовать

  • A/B невозможен (географическое воздействие, legal reasons)
  • Несколько групп (более 2)
  • Временные панельные данные
  • Natural experiments (minimum wage, закон, эпидемия)

Проблемы и pitfalls

Нарушение parallel trends

Если Москва рос быстрее СПб и без фичи — DiD завышает эффект.

Решение: placebo-тест. Применить DiD на pre-period — если виден «эффект» там, где его нет — assumption нарушено.

Spillover effects

Если Москва «заражает» СПб (пользователи мигрируют) — control не чистый.

Composition changes

Если в treatment group изменился состав — эффект смешан с compositional effect.

Anticipation

Если treatment group «знает заранее» о будущем воздействии и меняет поведение → bias.

Расширения

Synthetic control

Вместо одного control города — weighted combination нескольких. Более precise.

Event study

Смотреть эффект по периодам: какие дни после? Показывает dynamics.

Triple-differences (DDD)

Три размерности: treatment × post × подгруппа.

На собесе

«Что такое DiD?» Метод измерения эффекта без randomized assignment, через сравнение изменений в группах.

«Ключевое assumption?» Parallel trends — без воздействия тренды были бы параллельны.

«Как проверить?» Placebo tests, визуализация pre-period trends.

«Когда использовать?» Когда нельзя A/B (geo, legal, etc.).

Частые ошибки

Не проверять parallel trends

Самая частая и критичная ошибка.

Игнорировать spillover

Treatment может влиять на control indirectly.

Pre-period слишком короткий

Нужно достаточно long pre-period, чтобы оценить trends.

Связанные темы

FAQ

Все равно предвзятый?

Если assumption выполняется — unbiased. Иначе смещённый.

Работает ли с несколькими группами?

Да, через panel data methods.

DiD vs A/B?

A/B — gold standard (randomized). DiD — alternative когда A/B нельзя.


Тренируйте статистику — откройте тренажёр с 1500+ вопросами для собесов.