Собесов

Сценарий: propensity score matching — оценка эффекта без RCT

Статистика и теорверCausal inferenceСложнаяSenior

Условие

Нельзя сделать RCT (политическое ограничение). Хотим оценить эффект новой фичи — те, кто её use, и те, кто нет. PSM?

Решение

Идея

Подобрать каждой treated юзеру «похожих» по характеристикам control юзеров. Сравнить outcomes на matched парах. Если matching хороший — confounding устранён.

Шаги PSM

1. Считаем propensity score: P(treat | covariates)

from sklearn.linear_model import LogisticRegression
 
ps_model = LogisticRegression().fit(X_covariates, treated)
df['ps'] = ps_model.predict_proba(X_covariates)[:, 1]

Covariates: всё, что влияет и на treatment, и на outcome (возраст, tenure, активность до treatment, geo).

2. Проверяем overlap (common support)

import matplotlib.pyplot as plt
plt.hist(df[df.treated]['ps'], alpha=0.5, label='treated')
plt.hist(df[~df.treated]['ps'], alpha=0.5, label='control')

Если distributions сильно расходятся — matching невозможен (no common support).

3. Матчим

# 1:1 nearest neighbor matching
from sklearn.neighbors import NearestNeighbors
 
treated = df[df.treated]
control = df[~df.treated]
 
nn = NearestNeighbors(n_neighbors=1).fit(control[['ps']])
_, idx = nn.kneighbors(treated[['ps']])
matched_control = control.iloc[idx.flatten()]
 
matched = pd.concat([treated.reset_index(drop=True),
                      matched_control.reset_index(drop=True)],
                     keys=['t', 'c'])

4. Проверяем balance

Для каждой ковариаты — Standardised Mean Difference:

SMD = (mean_t - mean_c) / sqrt((var_t + var_c) / 2)

После matching должно быть |SMD| < 0.1.

5. Оцениваем ATE / ATT

# ATT: average treatment effect on the treated
att = (treated['outcome'].values - matched_control['outcome'].values).mean()

Альтернативы matching

  1. IPTW (inverse probability of treatment weighting):
weight = treat / ps + (1 - treat) / (1 - ps)
  1. Doubly robust: combine outcome model + propensity model. Consistent если либо правильный.

  2. Subclassification: разбить на квантили ps, сравнить внутри.

Sensitivity analysis

Rosenbaum bounds — насколько чувствителен ATE к unobserved confounders. Полезно для defense estimates.

Подводные камни

  1. Unobserved confounder убивает PSM. Если treatment selection основан на что-то ненаблюдаемое — оценка смещена.
  2. No common support — нельзя сравнить, как бы вы ни матчили.
  3. Overmatching: covariate, который и causal pathway — не включать.
  4. PSM убирает observable confounders, IV/DiD/RCT нужны для unobserved.
  5. Sample size: после matching выборка может сильно уменьшиться (есть unmatched).

Эталонный ответ

1) Logistic для P(treat|covariates) → propensity score. 2) Match nearest neighbor по PS. 3) Balance check (SMD < 0.1). 4) Compare outcomes. Работает только если все confounders observed; иначе IV/DiD/RCT.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти