Модуль 3. Regression Discontinuity Design (RDD)

TL;DR

Если решение даётся по чёткому порогу — например, кредит одобряется при score ≥ 650, бесплатная доставка при заказе от 3000₽ — у нас есть готовый квазиэксперимент. Заявитель с 649 и заявитель с 651 — фактически одинаковые люди, но один получил, другой нет. Сравнение этих двух групп даёт причинный эффект — но только в окрестности порога. Метод называется Regression Discontinuity Design — RDD. Главное, что нужно проверить: люди не могут манипулировать своим значением переменной, по которой назначается treatment.

Фундаментальная интуиция

RDD строится на простой идее: у порога assignment как лотерея. Если правило «получают все с score ≥ 650», то заявитель с 649 баллами и заявитель с 651 баллом отличаются всего на 2 балла. Между ними нет значимой разницы по доходу, опыту, поведению — это точечная вариация в скоринге, а не системное различие. Но один из них одобрен, другой — нет. Если дальше у одобренного расходы выросли на 90 единиц — это эффект одобрения, а не эффект «он был лучше с самого начала».

Что мы измеряем: разрыв в outcome (расходах, retention, GMV) ровно в точке порога. Слева от порога — пользователи без treatment, справа — с treatment. Между ними outcome должен меняться плавно — это базовое условие. Скачок outcome в точке порога и есть эффект.

Что важно понимать: RDD говорит про эффект только у людей рядом с порогом. Заявитель с скорингом 800 или с 400 — мы о них ничего не знаем. Если расширять вывод на всех — это уже не RDD, а домысел.

Когда применять

RDD подходит когда выполняются 5 условий:

Если все 5 условий выполнены — RDD один из самых надёжных квазиэкспериментов: допущения слабые, проверки прозрачные, интерпретация чистая.

Что мы оцениваем

RDD оценивает LATE — Local Average Treatment Effect, или локальный эффект для пользователей у порога. Слово «локальный» здесь буквальное: эффект на тех, чьё значение running variable рядом с cutoff.

Running variable — это переменная, по которой назначается treatment (скоринг, сумма заказа, возраст). Cutoff — сам порог. На практике выбирается окно, например ±50 баллов вокруг порога, и в этом окне считается разрыв в outcome.

Чем шире окно — тем больше данных, но тем дальше мы уходим от точки порога и тем сильнее размывается «локальность». Чем уже окно — тем чище эффект, но меньше статистической мощности. Это компромисс, который называется bandwidth choice.

Важное ограничение: LATE — не средний эффект на популяции. Если у порога эффект +15%, это НЕ значит что у всех пользователей эффект +15%. У пользователей с очень высоким или очень низким score эффект может быть совсем другим, и RDD об этом ничего не говорит.

Что нужно для идентификации

Чтобы RDD давал причинный эффект, нужны три условия:

  1. Плавность outcome у порога. Если бы treatment не было, связь между running variable и outcome была бы плавной. Скачок outcome ровно в точке порога — это эффект treatment, а не «и так бы скакнуло». Формально: E[Y(0)|X=x] и E[Y(1)|X=x] непрерывны в точке порога.
  2. Невозможность манипуляции порогом. Пользователи не могут точно подогнать своё значение под порог. Если менеджеры в банке могут «подкрутить» скоринг — заявители с 651 уже не случайно отличаются от 649: они системно те, кому подкрутили. RDD теряет смысл.
  3. Локальная рандомизация. У самого порога значение running variable можно считать почти случайным. На уровне всей популяции скоринг не случаен (он коррелирует с доходом, возрастом, историей), но у пары 649 vs 651 эта корреляция исчезает — слишком близкие значения.

Эти три условия часто формулируются техническим языком (continuity, no manipulation, local randomization), но суть в одном: у порога рандомизация работает естественно. Дело аналитика — проверить, что она реально работает.

Sharp vs Fuzzy — два варианта порога

Бывает два варианта работы порога: жёсткий (sharp) и размытый (fuzzy).

Sharp RDD: правило соблюдается строго. Все с score ≥ 650 одобрены, все ниже — нет. Никаких исключений. Эффект оценивается просто как разрыв outcome в точке порога.

Fuzzy RDD: порог только меняет вероятность treatment. Заявителю с score 651 одобряют в 80% случаев, с 649 — в 20%. Скачок есть, но не от 0 до 100%. Это часто бывает на практике: банк добавляет ручную проверку, есть исключения по сегментам, скоринг — один из факторов решения.

Для fuzzy RDD используется техника 2SLS (two-stage least squares): порог становится инструментом для предсказания вероятности treatment, эффект оценивается через эту предсказанную вероятность. Это уже метод модуля 6 (IV) — fuzzy RDD по сути частный случай instrumental variables.

ТипЧто происходит у порогаКак считаем
SharpP(D=1) скачет с 0 до 1Разрыв outcome в точке порога
FuzzyP(D=1) скачкообразно растётРазрыв в outcome / разрыв в P(D=1) — 2SLS

Как проверить, что метод работает (диагностика)

RDD требует пять стандартных проверок до того как интерпретировать результат как причинный.

ПроверкаЧто смотримКрасный флагЧто делать
McCrary density testРаспределение running variable вокруг порогаСкачок плотности — пик слева или справа от порогаВозможна манипуляция, RDD неприменим
Баланс ковариатСредние характеристик (доход, возраст, история) слева и справаЗначимый разрыв в ковариатах ровно у порогаГруппы не сравнимы — добавить контролей или сменить метод
Bandwidth robustnessРезультат при разной ширине окна (h/2, h, 2h)Знак или значимость эффекта меняютсяЭффект неустойчив — заявлять причинность нельзя
Placebo cutoffsФиктивные пороги (cutoff − 50, cutoff + 50)Значимый «эффект» там где его быть не должноПроблема в спецификации, не в treatment
Polynomial orderЛинейная vs квадратичная регрессияРезультат сильно зависит от степени полиномаИспользовать local linear (стандарт)

Стандартная практика: показать на графике scatter plot с fitted lines по обе стороны порога. Глазом сразу видно есть разрыв или нет. Все цифры идут после картинки.

Минимальный расчёт

Sharp RDD оценивается локальной линейной регрессией в окне
вокруг порога:

  Y_i = α + τ·D_i + β·(X_i − c) + γ·D_i·(X_i − c) + ε_i

Где:
  X_i — running variable (скоринг, сумма заказа)
  c   — порог (cutoff)
  D_i = 1 если X_i ≥ c, иначе 0
  τ   — оценка эффекта (LATE)
  β и γ — наклоны слева и справа от порога

Fuzzy RDD оценивается через 2SLS:

  Шаг 1: D_i = π₀ + π₁·Z_i + ...   где Z_i = 1{X_i ≥ c}
  Шаг 2: Y_i = α + τ·D̂_i + ...

D̂_i — предсказанная вероятность treatment из первой
ступени. τ интерпретируется как эффект на compliers — тех,
чьё treatment-присвоение действительно зависит от порога.

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

  1. Не проверять manipulation. Если в данных есть bunching у порога — RDD невалиден независимо от того, насколько красивая получилась оценка. McCrary test обязателен.
  2. Использовать слишком высокую степень полинома. Кубический или квадратичный fit может «увидеть» разрыв там, где его нет — фит подгоняется под локальные изгибы данных. Стандарт — local linear, всё что выше нуждается в специальном обосновании.
  3. Экстраполировать LATE на всю выборку. RDD говорит про точку порога. Если в отчёте написано «эффект кредита на retention составляет +15%» без оговорки «у заявителей с скорингом около 650» — это технически неверный вывод.
  4. Брать слишком узкое окно. В окне ±5 баллов наблюдений мало, доверительный интервал широкий, эффект «не виден» — но это не значит что его нет. Нужен компромисс между локальностью и статистической мощностью.
  5. Дискретная running variable. Если переменная меняется скачками (возраст в годах, число лет работы), у порога мало вариации, и стандартный RDD плохо работает. Нужны специальные методы (например, Lee–Card подход).
  6. Donut RDD без обоснования. Иногда исключают пользователей ровно у порога (например, score 648–652) если есть подозрение на manipulation. Это полезный приём, но снижает мощность и должен быть оправдан конкретной историей про manipulation, а не просто «для надёжности».

Что делать дальше

Toy example: одобрение BNPL и расходы клиента

BNPL-сервис одобряет рассрочку при кредитном скоринге ≥ 650. Аналитик хочет оценить, как одобрение влияет на расходы клиента в течение следующих 30 дней.

Для разбора берём 8 заявителей с скорингом от 640 до 660 — узкое окно вокруг порога. Кто из них одобрен, кто нет, и какие расходы получились:

IDScore (X)Одобрен (D)Расходы 30д (Y)
16400520
26450535
36480540
46490545
56501610
66511620
76551630
86601650
Считаем средние слева и справа от порога:

  Y̅_слева  = (520 + 535 + 540 + 545) / 4 = 535.0
  Y̅_справа = (610 + 620 + 630 + 650) / 4 = 627.5

Наивная оценка эффекта:

  τ̂ = Y̅_справа − Y̅_слева = 627.5 − 535.0 = 92.5

То есть одобрение BNPL у порога даёт прирост расходов примерно на 92.5 единиц за 30 дней.

Что важно: это валидно только если у нас выполнены проверки. Конкретно:

Если все три проверки пройдены — мы можем сказать, что у заявителей с скорингом около 650 одобрение BNPL вызывает рост расходов на ~90 единиц за месяц. Распространять этот эффект на заявителей с скорингом 500 или 800 — нельзя.

Что было бы при проблемах: если бы McCrary показал пик заявок при 650-651 — это сигнал, что менеджеры или скоринговая модель «подкручивают» score до порога. Тогда наблюдаемый разрыв расходов отражает не эффект одобрения, а отбор «подкрученных» заявителей. RDD теряет валидность.

Упражнения

Задача 1: RDD или DiD для порога доставки

Компания даёт бесплатную доставку заказам от 3000₽. Нужно оценить, как бесплатная доставка влияет на повторные покупки. Какой метод?

Решение

RDD с порогом 3000₽ (running variable = сумма заказа). Но: покупатели могут манипулировать суммой (добавить товар до 3000₽) → нужен McCrary test. Если bunching сильный — RDD невалиден, рассмотреть donut RDD или DiD по времени введения policy.

Задача 2: bunching у порога скоринга

RDD по скорингу: порог 700. McCrary test показывает, что плотность заявок при score 698–702 в 3 раза выше, чем при 690–695. Что это означает?

Решение

Bunching у порога = manipulation. Скорее всего, менеджеры или алгоритм "подтягивают" score до 700. Юниты у порога не случайны → RDD невалиден. Можно попробовать donut RDD (исключить ±5 от порога) или искать другой дизайн.

Задача 3: экстраполяция за пределы порога

RDD оценивает τ̂ = +15% retention у порога score = 500. Менеджер спрашивает: "Значит, если мы уберём порог и дадим treatment всем, retention вырастет на 15%?" Что ответить?

Решение

Нет. RDD оценивает локальный эффект для юнитов у порога 500. Юниты с score 300 или 800 могут реагировать совершенно иначе. Экстраполяция на всю выборку невалидна. Для оценки глобального эффекта нужен другой дизайн (A/B или DiD).

Глубже: Fuzzy RDD как 2SLS

Sharp RDD предполагает идеальное соблюдение порога: все unit-ы выше получают treatment, все ниже — не получают. На практике порог часто fuzzy — переход через порог только увеличивает вероятность получить treatment. Например, заявителю с скорингом 651 одобряют BNPL в 80% случаев, с 649 — в 20%. Это не разрыв, а скачок вероятности.

В этом случае RDD оценивается как 2SLS:

1) Первая ступень: предсказываем D̂ (получил ли treatment) по running variable X и индикатору «выше порога» (Z = 1 если X ≥ c). Z — инструмент.

2) Вторая ступень: регрессируем Y на D̂ — получаем LATE (см. module 6 IV).

Fuzzy RDD ловит эффект на той части unit-ов, чьё treatment-присвоение зависит от порога — это compliers в терминологии IV. Эффект на них может отличаться от среднего эффекта в популяции.