Собесов

Ostrovok B2B — A/B-тест нового алгоритма сортировки SERP

Кейсы и метрикиAB analysisСредняяMiddle

Условие

Вы анализируете распределённые данные A/B-теста смены алгоритма сортировки гостиниц на b2b.ostrovok.ru. SERP-страницу значительно переработали — цель: приоритизировать сегменты отелей, более доступные для партнёров.

Поля датасета: Index, group, brand, landing_step, is_new, channel, uuid, main_page_hit, serp_hit, hotelpage_hit, booking_form_hit, voucher_hit, comission.

Вопросы:

  1. Какие success-метрики для A/B вы бы предложили?
  2. Получили ли мы полезные результаты?
  3. Какие рекомендации для будущих исследований?

Решение

1. Метрики

Воронка SERP → hotel_page → booking_form → voucher (= оплата). На каждом шаге — метрика hit / unique uuid.

Primary (основные):

  • CR серп → ваучер = voucher_hit / serp_hit (на пользователя). Это конечная конверсия в бронь.
  • GMV (комиссия) на пользователя = Σ comission / unique users (uuid). Это ключевой бизнес-результат.

Secondary (диагностика воронки):

  • CR serp → hotelpage (CTR на отель).
  • CR hotelpage → booking_form (намерение).
  • CR booking_form → voucher (завершение оплаты).

Guard-метрики:

  • main_page_hit per uuid (объём трафика — sanity).
  • Среднее comission per booking (AOV) — не упал ли средний чек.
  • Сегментная стабильность: % new (is_new) и % by channel — не сместилась ли популяция.

2. Анализ результатов

import pandas as pd
from scipy.stats import ttest_ind, chi2_contingency
from statsmodels.stats.proportion import proportions_ztest
 
df = pd.read_csv('product_test_data.csv')
 
# 0. Sanity: SRM
group_counts = df.groupby('group')['uuid'].nunique()
chi2, p = chi2_contingency([group_counts.values])
 
# 1. Per user metrics
user_lvl = (df.groupby(['uuid', 'group'])
              .agg(serp=('serp_hit', 'max'),
                   hotel=('hotelpage_hit', 'max'),
                   booking=('booking_form_hit', 'max'),
                   voucher=('voucher_hit', 'max'),
                   gmv=('comission', 'sum'))
              .reset_index())
 
# 2. CR voucher / serp
sub = user_lvl[user_lvl['serp'] == 1]
n0, n1 = sub.groupby('group').size()
x0, x1 = sub.groupby('group')['voucher'].sum()
z, p_cr = proportions_ztest([x1, x0], [n1, n0])
 
# 3. GMV: сравнение средних с bootstrap
g0 = user_lvl[user_lvl['group'] == 'control']['gmv']
g1 = user_lvl[user_lvl['group'] == 'test']['gmv']
t, p_gmv = ttest_ind(g1, g0, equal_var=False)

Сегментный анализ:

  • По brand — изменение порядка отелей могло выгоднее одним брендам.
  • По is_new — новые партнёры могут быть чувствительнее к UI.
  • По channel — разные каналы привлечения.

Cross-tab metrics × segments — с поправкой на multiple testing (Holm/BH).

3. Рекомендации для будущих исследований

  1. Сделать guard-набор стандартом: SRM + мониторинг падения главной страницы.
  2. Сегментировать по brand до выкатки — возможно, нужны разные алгоритмы.
  3. Long-term retention: изменение алгоритма SERP может работать первые 2 недели (novelty), а потом — спадать или расти. Тест 30+ дней.
  4. Учесть network effects: B2B-партнёры могут «договариваться» — поведение зависит от конкурентов.
  5. CUPED: использовать pre-period commission на user как ковариату — снижает дисперсию GMV в 2–3 раза.
  6. Stratified randomization по brand и channel — ускоряет сходимость.
  7. Проверка стационарности — не было ли структурного сдвига в трафике (праздники, конкуренты).

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

  1. serp_hit — флаг или счётчик? В описании markers — значит binary 0/1. Но 1 пользователь может сделать много SERP-сессий — учитывайте, что метрики надо строить per-user, а не per-row.
  2. Атрибуция: пользователь, попавший один раз в SERP в test и один раз в control — где он? Нужен sticky split на уровне uuid.
  3. comission > 0 бывает только при voucher_hit = 1 — иначе ошибка. Проверьте.
  4. Нулевая comission: NaN или 0? Влияет на расчёт средних.
  5. Multiple testing: при 4 шагах × 5 сегментов × 2 метрики = 40 проверок → много false positives.
  6. is_new definition: новый = первый раз попал на платформу в день теста? Это разные понятия.

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

(1) Primary — CR serp → voucher per uuid и GMV (commission) per uuid; secondary — поэтапные конверсии; guards — main_page traffic, средний чек, sample composition.

(2) Z-тест пропорций для CR, t-test/bootstrap для GMV, sanity SRM. Если p < α и эффект ≥ MDE → выкатка.

(3) Дальше: разделить по brand/channel, использовать CUPED, удлинить срок до 30+ дней, добавить retention-метрику.

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

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

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