Ответ
На последнем проекте (маркетплейс) я отвечал за A/B-тестирование изменений в интерфейсе и алгоритмах рекомендаций. Мой типичный рабочий процесс выглядел так:
1. Формулировка гипотезы и метрик: Перед запуском четко определял, что мы меняем и какой эффект ожидаем. Например: «Добавление блока „Часто покупают вместе“ на страницу товара увеличит средний чек на 3%». Основной метрикой был средний чек, guard-метрикой — конверсия в покупку.
2. Дизайн и запуск эксперимента:
- Использовал встроенный инструмент сплитования трафика (вроде Яндекс.Экспериментов или собственный сервис на основе user_id).
- Делил трафик 50/50, проверял отсутствие SRM (Sample Ratio Mismatch) на первых днях теста.
- Рассчитывал необходимый размер выборки с помощью power analysis (
statsmodels.stats.power) до запуска, чтобы тест не был недоопределен.
3. Анализ результатов: После сбора данных проводил статистическую проверку. Для пропорциональных метрик (CTR) использовал z-тест для долей, для непрерывных (средний чек, время на сайте) — t-тест или U-тест.
# Пример анализа CTR двух версий кнопки
import statsmodels.stats.proportion as proportion
import numpy as np
# Данные: клики и показы
clicks_A, impressions_A = 150, 5000 # Контроль (версия A)
clicks_B, impressions_B = 200, 5000 # Тест (версия B)
# Z-тест для двух пропорций
z_score, p_value = proportion.proportions_ztest(
count=[clicks_A, clicks_B],
nobs=[impressions_A, impressions_B],
alternative='smaller' # Проверяем, что B лучше A
)
ctr_A = clicks_A / impressions_A
ctr_B = clicks_B / impressions_B
print(f"CTR версии A: {ctr_A:.3%}")
print(f"CTR версии B: {ctr_B:.3%}")
print(f"p-value: {p_value:.4f}")
if p_value < 0.05:
print("Улучшение статистически значимо. Версию B можно rollout'ить.")
else:
print("Разница незначима. Гипотеза не подтвердилась.")
4. Выводы и rollout: Если тест показывал статистически и практически значимый положительный эффект без вреда для guard-метрик, мы принимали решение о полном внедрении изменения. Все результаты и выводы документировались в Confluence.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сидишь такой, вдумчиво, как Гамлет, и думаешь: «А что, если мы вот эту кнопку нахуй перекрасим?». И вот тут начинается самое интересное, блядь.
1. Сначала гипотезу надо сформулировать, а то потом нихуя не поймёшь. Типа, не просто «давайте сделаем красиво», а конкретно: «Если мы вот сюда прилепим блок "С этим говном тоже берут", то средний чек подрастёт на 3%». И сразу думаешь: а что может пойти не так? Чтобы конверсия в покупку, как та Офелия, не сказала нам «иди ты нахуй» и не упала ниже плинтуса. Это guard-метрика, страж, блядь, который стоит и смотрит, чтобы мы совсем уже не охренели.
2. Потом начинается ёперный театр с запуском.
Ты там юзеров делишь пополам, как последнюю бутылку с корешами. 50% видят старую версию, 50% — новую, с нашей хитрой жопой. Главное — в первые дни проверить, что трафик разделился ровно, а то будет SRM (Sample Ratio Mismatch). А это, блядь, как прийти на вечеринку, а там на одного мужика десять баб — сразу подозрение ебать чувствую, что-то тут нечисто. И размер выборки надо заранее прикинуть, чтобы не получилось, что ты две недели тест гонял, а статистической силы, как у младенца, — терпения ноль ебать. Используешь statsmodels, считаешь, и только потом запускаешь.
3. Анализ — это святое. Данные собрались, сидишь, как тот самый музыкант, и спрашиваешь: «А ты, сука, на флейте-то играть можешь?». Только флейта у тебя — это Python, а играть надо на p-value.
# Пример анализа CTR двух версий кнопки
import statsmodels.stats.proportion as proportion
import numpy as np
# Данные: клики и показы
clicks_A, impressions_A = 150, 5000 # Контроль (версия A)
clicks_B, impressions_B = 200, 5000 # Тест (версия B)
# Z-тест для двух пропорций
z_score, p_value = proportion.proportions_ztest(
count=[clicks_A, clicks_B],
nobs=[impressions_A, impressions_B],
alternative='smaller' # Проверяем, что B лучше A
)
ctr_A = clicks_A / impressions_A
ctr_B = clicks_B / impressions_B
print(f"CTR версии A: {ctr_A:.3%}")
print(f"CTR версии B: {ctr_B:.3%}")
print(f"p-value: {p_value:.4f}")
if p_value < 0.05:
print("Улучшение статистически значимо. Версию B можно rollout'ить.")
else:
print("Разница незначима. Гипотеза не подтвердилась.")
Смотришь на вывод. P-value меньше 0.05? Ни хуя себе! Значит, новая кнопка и правда огонь. Если больше — ну, да похуй, гипотеза не взлетела, идём думать дальше. Главное — не поддаваться волнению ебать и не интерпретировать хуйню, когда цифры кричат «пошли вы все нахуй».
4. Финальный акт — rollout. Если всё чики-пики, метрики в плюсе, стражи-метрики не в агонии, то можно и на всех пользователей выкатывать. Решение записываешь в Confluence, чтобы потом, когда начальство спросит «а на каком основании?», ты не стоял, как полупидор, а тыкнул пальцем в отчёт. Всё, манда с ушами, можно идти пить чай. А завтра — новая гипотеза, ебушки-воробушки, и всё по новой.