Вы запускаете A/B-тест на маркетплейсе. Новая рекомендательная система показывает +15% к кликам в тестовой группе. Кажется, победа. Выкатываете на всех — и получаете падение выручки на 3%. Что пошло не так? Вы столкнулись с классическим провалом A/B-теста в среде с сетевыми эффектами.
В маркетплейсах, такси-агрегаторах и доставке пользователи влияют друг на друга. Продавец из тестовой группы конкурирует с продавцом из контрольной. Водитель из теста переманивает заказы у водителя из контроля. Классическая рандомизация по пользователям ломается.
Почему ваши A/B-тесты врут (и вы этого не замечаете)
Представьте: вы тестируете новый алгоритм повышения товаров в поиске. В тестовой группе продавцы получают больше просмотров — их конверсия растет. Но эти просмотры уводят трафик у продавцов из контрольной группы. В итоге вы измеряете локальный эффект, но не видите глобального перераспределения.
Это называется интерференцией (interference) или спилловер-эффектом. Лечение в контрольной группе влияет на результаты тестовой группы, и наоборот. В статистике это нарушает фундаментальное предположение SUTVA (Stable Unit Treatment Value Assumption).
Три типа провалов, которые я видел лично
- Провал перераспределения: Новый алгоритм рекомендаций увеличил продажи книг в тестовой группе на 20%. Отлично! Но при полном запуске общие продажи книг не изменились. Оказалось, алгоритм просто лучше перераспределял существующий спрос между книгами, не создавая нового.
- Провал истощения: В такси-сервисе тестировали бонусы для водителей в определенном районе. Водители из теста стали чаще принимать заказы в этом районе. Но водители из контроля (которые тоже работали там) получили меньше заказов и уехали в другие районы. Метрика «процент принятых заказов» в тесте выросла, но общая доступность машин в городе упала.
- Провал двустороннего рынка: На маркетплейсе для фрилансеров тестировали упрощенную регистрацию для заказчиков. Количество заказчиков в тесте выросло. Но фрилансеры (которые были в обеих группах) не справлялись с возросшим потоком заказов — качество выполнения упало. В итоге отток заказчиков через месяц перекрыл первоначальный прирост.
Кластерный A/B-тест: когда делить нужно не пользователей, а города
Самый рабочий способ бороться с интерференцией — кластерная рандомизация. Вместо того чтобы рандомизировать отдельных пользователей, вы рандомизируете целые кластеры, внутри которых происходит взаимодействие.
1 Определите единицу взаимодействия
Спросите себя: между кем происходит конкуренция или влияние? Ответ станет вашим кластером.
| Тип платформы | Естественный кластер | Почему работает |
|---|---|---|
| Маркетплейс товаров | Город или регион | Покупатели ищут товары в своем городе, продавцы конкурируют локально |
| Такси-агрегатор | Город + временной слот | Водители конкурируют за заказы в одной географической зоне в одно время |
| Фуд-доставка | Район + ресторанная категория | Рестораны конкурируют внутри категории (пицца vs пицца), курьеры — внутри района |
| B2B-платформа | Вертикаль (строительство, IT) | Поставщики конкурируют внутри одной индустрии, покупатели ищут в своей нише |
2 Спроектируйте кластеры так, чтобы минимизировать spillover
Кластеры должны быть максимально независимыми. Если вы делите по городам, но у вас есть продавцы, которые доставляют по всей стране — это плохой кластер. Они будут присутствовать и в тесте, и в контроле.
Решение: выделите отдельный кластер для «межрегиональных» продавцов или исключите их из теста. Да, мощность теста уменьшится. Но лучше честный нулевой результат, чем ложноположительный.
Размер кластера — это компромисс. Маленькие кластеры (районы) дают больше единиц для рандомизации, но в них сильнее spillover между кластерами. Большие кластеры (города) уменьшают spillover, но их меньше — ниже статистическая мощность. Обычно начинают с самых крупных естественных единиц.
3 Рассчитайте мощность для кластерного дизайна
Здесь вас ждет неприятный сюрприз. Кластерные тесты требуют намного больше наблюдений, чем user-level тесты. Почему? Потому что вариация между кластерами обычно выше, чем вариация между пользователями внутри кластера.
Формула для оценки необходимого количества кластеров:
# Упрощенная оценка для кластерного A/B-теста
# n_per_cluster - пользователей в кластере
# icc - intraclass correlation coefficient (межкластерная корреляция)
# обычно 0.01-0.05 для маркетплейсов
def clusters_needed(mde, power, alpha, n_per_cluster, icc):
# MDE - минимальный детектируемый эффект
# power - мощность (обычно 0.8)
# alpha - уровень значимости (обычно 0.05)
# Формула упрощена, на практике используйте simulation
variance_inflation = 1 + (n_per_cluster - 1) * icc
# Далее стандартный расчет с поправкой на дизайн-эффект
return ceil(variance_inflation * standard_sample_size(mde, power, alpha))
Если icc=0.02 и в кластере 10 000 пользователей, вам потребуется в 200 раз больше пользователей для достижения той же мощности, что и в идеальном user-level тесте. Это убийственный факт для многих продуктов.
Метрики, которые не врут (или врут меньше)
Проблема не только в дизайне теста, но и в метриках. CTR (click-through rate) на маркетплейсе — опасная метрика. Вы можете увеличить CTR, показывая более «кликабельные» товары, но если эти товары имеют низкую конверсию в покупку или низкий средний чек — вы проиграли.
- Избегайте zero-sum метрик: CTR, позиция в выдаче, количество показов. Они легко перераспределяются между группами.
- Используйте метрики общего пирога: Общая выручка платформы (GMV), общее количество уникальных покупателей, общая частота покупок.
- Смотрите на обе стороны платформы: Если тестируете изменение для покупателей — смотрите метрики продавцов (отток, удовлетворенность). И наоборот.
- Вводите платформенные метрики: «Процент покупателей, нашедших нужный товар за 1 поиск», «Время от заказа до получения для 95-го перцентиля».
Когда кластерный тест невозможен (и что делать)
Бывают ситуации, когда кластерную рандомизацию применить нельзя. У вас один город. Или изменение глобальное (новая система поиска по всему каталогу). Или кластеры слишком проницаемые.
Тогда на помощь приходят квазиэкспериментальные методы:
Difference-in-Differences (Diff-in-Diff)
Вы находите естественную контрольную группу — например, пользователей из другого региона, где изменение не вводилось. Сравниваете не абсолютные значения, а изменения трендов до и после вмешательства.
Опасность: требуется строгое предположение о параллельных трендах (parallel trends). Если контрольная группа по своей природе отличалась динамикой — оценка будет смещенной.
Синтетический контроль
Создаете «виртуальную» контрольную группу как взвешенную комбинацию сегментов, которые похожи на тестовый до вмешательства. Более гибкий метод, чем Diff-in-Diff, но требует больше данных и аккуратной настройки.
Инструментальные переменные (IV)
Если у вас есть естественный эксперимент — например, изменение затронуло только пользователей определенного браузера из-за технической особенности. Этот браузер становится инструментом для оценки эффекта.
Редко применимо на практике, но если повезет — дает чистую оценку.
Чеклист перед запуском A/B-теста на маркетплейсе
- Проверка на интерференцию: Могут ли пользователи тестовой группы повлиять на контрольную? Через конкуренцию, ограниченные ресурсы, социальные взаимодействия?
- Выбор единицы рандомизации: Если есть риск интерференции — переходите на кластерный дизайн. Города, регионы, временные периоды.
- Расчет мощности для кластеров: Используйте симуляции, а не стандартные калькуляторы. Учтите ICC (intraclass correlation).
- Выбор метрик: Минимум одна «общеплатформенная» метрика (GMV, общее количество транзакций). Метрики для обеих сторон платформы.
- План анализа spillover: Как вы будете измерять перераспределительные эффекты? Сравнивайте общие метрики по всей платформе до/после, даже если тест локальный.
- Симуляция на исторических данных: Запустите A/A-тест в кластерном дизайне. Убедитесь, что метрики не показывают ложных эффектов из-за дизайна.
Самый опасный исход — это не ложноположительный результат (выкатили плохое изменение), а ложноотрицательный (отказались от хорошего изменения потому что тест не увидел эффекта из-за spillover). Вы теряете возможности роста, которых не видите.
Будущее: от A/B-тестов к симуляциям рынков
Передовой край — это агентные симуляции. Вы создаете упрощенную модель вашего маркетплейса с тысячами синтетических покупателей и продавцов, которые ведут себя по историческим паттернам. Запускаете изменение в симуляции и смотрите на системные эффекты.
Это дорого. Сложно. Но для крупных изменений (новая система комиссий, изменение ранжирования) — это может быть дешевле, чем натурный эксперимент с непредсказуемыми последствиями.
Кстати, если вы работаете с AI-системами в реальном времени, вам может быть интересен наш открытый репозиторий по Real-Time Bidding для AI — там тоже много проблем с оценкой в конкурентной среде.
И помните: проблема A/B-тестов на маркетплейсах — это не статистическая проблема. Это проблема моделирования реальности. Если ваша модель эксперимента не отражает того, как пользователи взаимодействуют в реальном мире, вы получите красивый, статистически значимый, абсолютно ложный результат.
Последний совет: если вы делаете A/B-тест на платформе с сетевыми эффектами и видите огромный позитивный эффект — сначала усомнитесь. Скорее всего, вы просто перераспределили ресурсы, а не создали новую ценность. Истинный рост в таких системах приходит медленно и скромно.