Модуль 5. Matching

TL;DR

Matching — для случаев, когда есть наблюдаемые данные о пользователях, которые получили intervention (treated), и тех, кто не получил (control), но без рандомизации. Группы изначально разные — те, кто записался в программу, отличаются от тех, кто не записался. Идея matching: для каждого treated-пользователя найти «двойника» в control с похожими характеристиками. Сравнить пары — получить причинный эффект. Главное допущение: если мы учли все важные ковариаты, то внутри пар пользователи реагируют одинаково. Это допущение называется CIA — conditional independence assumption — и его нельзя доказать, можно только обосновать.

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

Matching строится на простой идее: если рандомизация невозможна, попробуем восстановить её «вручную». В RCT две группы похожи в среднем — рандомизатор это гарантирует. В наблюдательных данных группы разные: те, кто записался в программу обучения, не такие же как те, кто не записался. У них другой опыт, другая мотивация, другой стартовый капитал. Прямое сравнение даст смесь «эффект программы + эффект исходных различий».

Matching пытается убрать вторую часть. Для каждого treated-пользователя ищется один или несколько похожих в control — с теми же ключевыми ковариатами (категория товаров, регион, дата регистрации, опыт продаж). Пары сравниваются попарно: разность Y в паре считается за оценку эффекта. Усреднение по всем парам даёт ATT.

Что мы измеряем: эффект на тех, кому intervention фактически применилась, при условии что мы правильно подобрали ковариаты. «Правильно» здесь — это все факторы, которые одновременно влияют и на решение войти в программу, и на outcome. Если такие факторы есть, но мы их не наблюдаем — matching не работает. Это центральное ограничение метода.

Что важно понимать: matching не создаёт рандомизацию, он её имитирует. Имитация хороша настолько, насколько полны и точны наблюдаемые ковариаты. Скрытые confounders matching не лечит — для этого нужны другие методы (IV, DiD при выполнении parallel trends, RDD при наличии порога).

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

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

Если эти условия выполнены — matching очень удобен. Не нужно ждать недели на эксперимент, не нужно строить синтетический контроль, не нужно искать инструмент. Просто подобрать пары и посчитать.

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

Matching оценивает ATT — Average Treatment Effect on the Treated — средний эффект intervention на тех, кому она фактически применилась. Иногда — ATE (Average Treatment Effect on the population), но это требует более сильных допущений и большего overlap групп.

Главное допущение: CIA — conditional independence assumption. Формально:

  (Y₀, Y₁) ⊥ D | X

В переводе: при условии что мы знаем ковариаты X, решение получить intervention (D) не зависит от того, какой outcome был бы при обеих treatment-альтернативах. Иными словами: если две группы выровнены по X, разница в Y объясняется только intervention, а не отбором.

Что значит CIA на практике: у двух пользователей с идентичными ковариатами один попал в treated, другой нет — это «как лотерея». Если так — сравнение по парам даёт причинный эффект. Если же есть скрытая переменная (мотивация, финансовое положение, доступ к информации), которая влияет и на решение, и на outcome — CIA нарушена, matching смещён.

CIA нельзя проверить статистически. Можно только обосновать содержательно: «вот ковариаты, которые мы учли — и кажется, что других важных confounders нет». Аналитик должен явно перечислить, чего matching не учитывает, и почему думает, что это не критично. Эта часть аргумента — самая уязвимая в matching, и её часто пропускают. Зря.

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

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

  1. CIA — conditional independence. При учёте ковариат X решение получить intervention становится «как рандомизированным». Все важные confounders — те, что одновременно влияют на treatment и на outcome — должны быть наблюдаемы и включены в matching.
  2. Common support (overlap). Для каждого treated-юнита существует хотя бы один control с похожими ковариатами. Если в treated есть пользователи, для которых в control нет никого похожего — matching на этих юнитах не работает. Их либо исключают, либо признают, что эффект на них неоценим.
  3. SUTVA — stable unit treatment value assumption. Эффект на одного пользователя не зависит от того, кто ещё получил intervention. На двусторонних платформах это часто нарушается через рынок и аукционы. Если эффект программы поддержки на одного продавца зависит от того, сколько ещё продавцов в программе — SUTVA нарушена.

Из этих трёх (1) — самое сильное и непроверяемое. (2) проверяется по балансу ковариат после matching. (3) нужно осмыслить из устройства задачи.

Виды matching

Существует несколько техник matching, и они применимы в разных ситуациях. Основная разница — как именно определяется «похожесть» двух пользователей.

ТипЧто делаетКогда подходит
Exact matchingИщет пользователей с в точности теми же значениями всех ковариатМало ковариат, все дискретные (категория, регион). Не работает при множестве непрерывных ковариат — curse of dimensionality (с ростом числа ковариат идеальных двойников всё меньше)
Propensity Score Matching (PSM)Считает оценку вероятности попасть в treated (propensity score) для каждого пользователя, матчит по этой одной величинеМного ковариат, в том числе непрерывных. Самый частый метод на практике
Coarsened Exact Matching (CEM)Разбивает непрерывные ковариаты на корзины и матчит по корзинамХочется простоты exact matching, но с непрерывными переменными
Nearest Neighbor (NN)Матчит по Mahalanobis distance — расстоянию между пользователями с учётом корреляций ковариатМалое число ковариат, нужно учесть их совместное распределение

Выбор метода зависит от природы данных. На практике большинство случаев — PSM, плюс отдельная проверка устойчивости через CEM или NN.

Как проверить, что метод работает

Matching требует пять стандартных проверок до того как интерпретировать оценку как причинный эффект.

ПроверкаЧто смотримКрасный флагЧто делать
Balance test (SMD)Standardized mean difference по каждой ковариате до и после matchingSMD > 0.1 после matchingBalance не достигнут — пересмотреть ковариаты или метод
Common supportРаспределение propensity score у treated и controlБольшие хвосты, где нет overlapTrim — исключить юниты вне общего диапазона
Sensitivity analysisRosenbaum bounds — Γ, при котором эффект ломаетсяΓ < 1.3 (эффект ломается при слабом скрытом confounder)Эффект хрупкий — заявлять причинность нельзя
Robustness к выбору методаПовторить с PSM, CEM, NN — сравнить ATTЭффект сильно меняется между методамиРезультат зависит от метода — ненадёжен
Placebo outcomeПрименить matching к outcome, на который intervention не должна влиятьЭффект значим там, где не должен бытьДизайн ловит общую динамику, не эффект

Стандартная практика — показать balance table до и после matching. SMD < 0.1 по всем ключевым ковариатам — рабочий порог. Без этой таблицы matching не имеет смысла обсуждать дальше.

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

Простейший вариант — Propensity Score Matching:

Шаг 1: оценить propensity score для каждого юнита

  PS_i = P(D=1 | X_i) ≈ logit(X_i)

  Логистическая регрессия: D на X (ковариаты).
  Для каждого юнита получаем оценочную вероятность
  попасть в treated при его наблюдаемых характеристиках.

Шаг 2: для каждого treated юнита найти ближайший control
по PS

  Для i в treated, найти j в control такой, что
  |PS_i − PS_j| → минимум

  Можно с заменой (один control может быть двойником
  нескольких treated) или без (каждый control используется
  один раз).

Шаг 3: вычислить ATT

  τ̂_ATT = (1/N_treated) · Σ_i (Y_i − Y_j(i))

  Среднее по всем treated-юнитам разности с их matched
  control.

Шаг 4: оценить SE через bootstrap

  Пересчитать matching и ATT на bootstrap-выборках —
  получить эмпирическое распределение, посчитать SE.

  Стандартные формулы SE для matching некорректны,
  потому что веса matched-пар не учитывают
  неопределённость оценки propensity score.

Что matching НЕ решает

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

  1. Не проверять balance после matching. Если после matching SMD по какой-то ковариате осталась 0.3 — balance не достигнут. Сравнение пар фактически сравнивает разные группы по этой ковариате. Заявлять эффект нельзя.
  2. Игнорировать common support. Если в treated есть юниты, для которых в control нет похожих — алгоритм найдёт «двойника», но он не настоящий двойник, а ближайший далёкий. Эффект на этих юнитах не идентифицирован. Trim обязателен.
  3. Не учитывать ключевые confounders. Matching работает только если мы учли всё важное. Если на решение получить intervention влияет переменная, которой нет в данных (мотивация, доступ к информации) — CIA нарушена, эффект смещён. Это главное ограничение метода, и обойти его нельзя статистически.
  4. Включать в matching post-treatment переменные. Если ковариата сама зависит от treatment (например, число купленных товаров после регистрации в программе) — она «съедает» часть эффекта. Это bad controls. Включать в matching только то, что определено ДО intervention.
  5. Использовать стандартные SE без bootstrap. Стандартные формулы недооценивают неопределённость, потому что не учитывают, что propensity score сам — оценочный. Bootstrap-SE обязательны.
  6. Не делать sensitivity analysis. Rosenbaum Γ показывает, насколько силён должен быть скрытый confounder, чтобы обнулить эффект. Без этой проверки matching выглядит увереннее, чем он есть на самом деле.

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

Toy example: программа поддержки новых продавцов

Маркетплейс запустил программу поддержки для новых продавцов: бесплатные курсы по фото, описаниям, ценообразованию. Запись добровольная. Аналитик хочет оценить эффект программы на GMV в первые 90 дней после регистрации.

Treated: продавцы, записавшиеся в программу (N = 500). Control: продавцы, не записавшиеся (N = 4500). Запись добровольная → группы изначально разные.

Ковариаты для matching: категория товаров (Одежда, Электроника, Дом, ...), регион регистрации, месяц регистрации (контроль на сезонность), опыт онлайн-продаж (был ли аккаунт на других площадках).

Balance до matching:

КовариатаTreated (mean)Control (mean)SMD
Доля в «Одежде»0.420.310.23
Доля в Москва+СПб0.650.480.34
Месяц регистрации (avg)7.25.80.41
Опыт онлайн-продаж0.550.320.47

Дисбаланс по всем 4 ковариатам — те, кто записался в программу, систематически отличаются. Прямое сравнение GMV даст смесь эффекта программы и эффекта отбора.

Шаг 1 — propensity score. Логистическая регрессия D на 4 ковариаты. Получаем PS_i для каждого продавца.

Шаг 2 — Nearest neighbor matching без замены. Для каждого treated находим ближайшего по PS control. 500 пар.

Balance после matching:

КовариатаTreated (mean)Matched controlSMD
Доля в «Одежде»0.420.410.02
Доля в Москва+СПб0.650.630.04
Месяц регистрации (avg)7.27.10.03
Опыт онлайн-продаж0.550.530.04

Все SMD < 0.1 — balance достигнут. Пары сопоставимы по наблюдаемым характеристикам.

Шаг 3 — ATT. Для каждой из 500 пар считаем разность GMV
за 90 дней. Усредняем.

  Y̅_treated  = 145 000 ₽
  Y̅_matched  = 118 000 ₽

  τ̂_ATT = 145 000 − 118 000 = 27 000 ₽ за 90 дней

Шаг 4 — bootstrap-SE. 1000 пересчётов на bootstrap-выборках.

  SE_bootstrap ≈ 4 200 ₽
  95% CI:  [18 800, 35 200] ₽

Шаг 5 — sensitivity analysis. Rosenbaum bounds. Эффект
сохраняет значимость до Γ = 1.8. Это значит: скрытый
confounder должен почти в 2 раза менять шансы записаться
в программу, чтобы обнулить эффект. Слабый скрытый
confounder не критичен.

Вывод: программа увеличивает GMV новых продавцов на ~27 000 ₽ за первые 90 дней (95% CI 18.8–35.2 тыс. ₽). Эффект устойчив к умеренно сильному скрытому confounder.

Что было бы при провале balance: если после matching по ковариате «опыт онлайн-продаж» SMD осталась 0.25 — matching не достиг balance, и сравнение пар не интерпретируется. Возможные действия: добавить ковариату в propensity score, перейти на caliper matching (отбрасывая пары с большой разницей PS), или признать что метод не работает на этих данных.

Упражнения

Задача 1: bad controls

Маркетплейс отправляет push-уведомления о новых коллекциях. Аналитик хочет оценить эффект push на повторные покупки. Treated — пользователи, получившие push. Control — те, кому push не отправлялся. Группы изначально разные — push приходят активным пользователям. Аналитик делает matching по ковариатам: возраст аккаунта, история покупок за прошлый месяц, число открытых push-уведомлений за последнюю неделю. Что не так с этим набором ковариат?

Решение

Проблема — bad controls. Число открытых push-уведомлений за последнюю неделю — post-treatment переменная. Она сама зависит от того, получил ли пользователь push, и от того, как он отреагировал. Включать её в matching — значит сравнивать пользователей с одинаковой реакцией на push и измерять эффект push на покупки. Это два смешанных эффекта, а не чистый эффект push. ATT окажется существенно меньше реального — часть эффекта «съел» bad control. Правило: ковариаты для matching — только то, что определено до treatment. Post-treatment переменные — никогда.

Задача 2: Rosenbaum Γ

Финтех-сервис подключает клиентам BNPL по запросу. Аналитик матчит подключивших с не-подключившими и получает ATT = +8% retention за 6 месяцев. Sensitivity analysis показывает Rosenbaum Γ = 1.15. Что значит Γ = 1.15? Можно ли заявить эффект подключения BNPL на retention?

Решение

Γ = 1.15 значит: эффект +8% retention обнулится, если существует скрытый confounder, который меняет шансы подключить BNPL примерно в 1.15 раза (на 15%). Это очень слабое возмущение. Любая ненаблюдаемая переменная — финансовая дисциплина клиента, доход выше среднего, опыт онлайн-покупок — может легко давать такой эффект. Заявить «BNPL повышает retention на 8%» — нельзя. Эффект не идентифицирован достаточно надёжно. Что делать: (1) расширить набор ковариат, добавить переменные, которые могут быть скрытыми confounders, пересчитать Γ; (2) перейти на квазиэксперимент с явной exogenous variation — например, DiD относительно даты автоматической выдачи BNPL новым клиентам; (3) запустить RCT на части клиентов. Правило: Γ < 1.3 — эффект хрупкий, для policy-решений небезопасен. Γ > 2 — эффект устойчив.

Задача 3: выбор метода

Аналитик хочет оценить эффект новой рекомендательной системы на retention. Есть данные за 6 месяцев до и после внедрения, выкат был на всех пользователях одновременно (не было постепенного rollout). Pre-trend retention за 6 месяцев был неровным — несколько раз менялись смежные продуктовые фичи. Что выбрать: DiD, matching+DiD, matching alone?

Решение

Ни один из трёх не подходит полностью. DiD: нет control-группы (выкат на всех). Сравнивать «до и после» без контроля — это before/after, не DiD. Matching+DiD: нет treated и control групп для matching — выкат был на всех. Matching alone: возможен, если найти «псевдо-control» — пользователей, на которых система почему-то не сработала (технические сбои, отдельный A/B-сегмент). Но риск selection bias высокий. Что реально подходит: synthetic control (модуль 4) — если можно построить синтетический контроль из других платформ или регионов. Или ITS (interrupted time series) — анализ временного ряда с структурным сдвигом в момент выката. Или признать, что причинный вывод невозможен с этими данными. Правило: matching работает только когда есть treated и control в один и тот же период. «Все получили intervention» — это не matching-задача.

Глубже: double robustness (AIPW)

Doubly robust estimator комбинирует weighting с outcome regression. Консистентен, если хотя бы одна из двух моделей правильно специфицирована. AIPW (augmented inverse probability weighting) — стандартная реализация. Не решает unobserved confounding, но повышает робастность к misspecification.