Собесов

Яндекс.Еда: Атрибуция эффекта промокодов и оценка инкрементальности

Кейсы и метрикиPricing / PromoСложнаяMiddle

Условие

Маркетинг рассылает промокод «−300 ₽ при заказе от 1500 ₽». Половина заказов с промокодом приходит от пользователей, которые в любом случае заказали бы (взяли купон «попутно»). Как оценить инкрементальный эффект промокода (выручка / прибыль)?

Решение

Простое сравнение не работает

«Заказы с промокодом vs без» сильно смещено: пользователи с промокодом — это активные / лояльные → systematic bias.

Дизайн 1: A/B holdout

Случайно разделить аудиторию рассылки на 75% target / 25% holdout (не получают промокод). Сравнить GMV / прибыль через 2 недели.

incremental_GMV = GMV_target - GMV_holdout · (n_target / n_holdout)
incremental_profit = GMV_inc - promo_cost - cost_of_extra_orders

Это самый чистый дизайн, но дорогой (теряем потенциальную выручку с holdout).

Дизайн 2: stratified holdout

Стратификация по cohort × city × past 30d activity → меньше variance, тот же дизайн.

Дизайн 3: PSM (если A/B сделать нельзя)

Подобрать «парную» неэкспонированную группу по характеристикам:

  • past 30d orders, AOV, last order date, city, segment.
from sklearn.linear_model import LogisticRegression
 
# 1) Модель propensity: получил ли пользователь промокод
X = features
y = received_promo  # 0/1
ps = LogisticRegression().fit(X, y).predict_proba(X)[:, 1]
 
# 2) Nearest neighbour matching
from sklearn.neighbors import NearestNeighbors
nn = NearestNeighbors(n_neighbors=1).fit(ps[y==0].reshape(-1, 1))
_, idx = nn.kneighbors(ps[y==1].reshape(-1, 1))
 
paired_control = df.loc[y==0].iloc[idx.flatten()]
paired_treat   = df.loc[y==1]
incremental_gmv = paired_treat.gmv.mean() - paired_control.gmv.mean()

Дизайн 4: Difference-in-Differences

Если промокод выкатили в одном городе, в соседнем — нет:

DiD = (GMV_city1_after - GMV_city1_before) - (GMV_city2_after - GMV_city2_before)

Предположение: parallel trends — до промокода метрики двух городов росли одинаково.

Дизайн 5: Uplift модель

Для каждого пользователя предсказать «инкрементальный заказ» с промокодом:

Uplift(user) = P(order | treatment=1) - P(order | treatment=0)

Обучается на A/B-данных (target + holdout). Дальше — таргетировать только пользователей с положительным uplift.

# Two-Model (T-learner)
from xgboost import XGBClassifier
m1 = XGBClassifier().fit(X[treatment==1], y[treatment==1])
m0 = XGBClassifier().fit(X[treatment==0], y[treatment==0])
 
uplift = m1.predict_proba(X)[:,1] - m0.predict_proba(X)[:,1]

Метрики

  • Incremental GMV = (GMV target − GMV holdout × n_t/n_h)
  • Incremental orders — то же по orders.
  • iROI = incremental revenue / promo cost.
  • iROAS = incremental GMV / promo spend.
  • Cannibalization rate = доля «free-rider» заказов в total promo orders.

Cannibalization напрямую

Зная inc orders и total promo orders:

cannibalization_rate = 1 - (incremental_orders / total_promo_orders)

Если 50% заказов с промокодом «freerider» → каннибализация 50%.

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

  1. Не делать holdout = вечная неопределённость с эффектом. Каждый промо-кэйс — без honest baseline.
  2. Холдаут < 10% — низкая power; нужна неделя+ при большом N.
  3. PSM ловит только наблюдаемые confounders. Ненаблюдаемые (мотивация заказать сегодня) — нет.
  4. DiD ломается при шоках, специфичных для одной группы (например, ливень в city1).
  5. Uplift на маленькой A/B: ошибка модели часто больше эффекта; нужно ≥ 100K в каждой ветке.
  6. Promo cost ≠ GMV − 300 ₽: есть ещё subsidies, влияние на retention.
  7. Promo на новых vs существующих: ROI разный, агрегировать опасно.
  8. Sequential promos: один и тот же пользователь получает 5 промо в месяц → assignment не iid, классический A/B-анализ не работает.

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

Чистый инкремент = A/B holdout (target vs control с одинаковыми правилами таргетинга, кроме промокода). Без holdout — propensity score matching или Difference-in-Differences (если есть гео-вариация).

Метрики: incremental GMV/orders, iROI = inc_revenue / promo_cost, cannibalization rate = 1 − inc_orders / total_promo_orders. Для долгосрочного отбора пользователей — uplift-модель (T-learner или Causal Forest).

Главное: «GMV с промокодом» — vanity-метрика; бизнесу нужен инкрементальный эффект, а он измеряется только через holdout / quasi-эксперимент.

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

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

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