Как автоматизировать подведение результатов A/B-экспериментов
Ольга Силютина
Представим себе продуктовую компанию, в которой уже есть базовый алгоритм рандомизации и сплитования пользователей на экспериментальные группы, и запускается он бэкендером в коде для каждого нового эксперимента. При этом у менеджеров и аналитиков нет интерфейса к результатам эксперимента кроме логов с разметкой пользователей по их принадлежности к экспериментальным группам.
Процесс проведения эксперимента в таком случае может выглядеть примерно так:

В этой ситуации каждый эксперимент требует большого количества времени для систематизации полученных знаний. Необходимо собрать данные об экспериментальных группах, применить статистические критерии, сделать выводы и не потерять результаты эксперимента в потоке задач.
Для анализа одного эксперимента аналитику в среднем нужно потратить пару часов. С увеличением объёма данных и числа фич количество проводимых экспериментов возрастает, они начинают запускаться параллельно и требовать всё больше времени аналитиков. Кроме того, до момента закрытия задачи аналитиком никто из команды не знает, насколько случайно и ожидаемо группы заполняются наблюдениями на старте эксперимента и насколько корректно работает фича.
Все эти проблемы приводят нас к вопросу о том, как же можно быстро автоматизировать процесс анализа A/B-экспериментов, экономить ресурсы аналитиков и не терять в общем потоке результаты каждого эксперимента.
Первая мысль, которая приходит в голову, — найти готовое решение. Действительно, есть много различных аналитических инструментов для автоматизации процесса подведения результатов экспериментов. Но, работая в реалиях стартапа, аналитики часто сталкиваются с ограничениями в ресурсах либо с требованиями к конфиденциальности данных в более крупных компаниях. Из-за этого многие облачные решения могут быть недоступны. В этой статье мы расскажем, как реализовать нужный нам инструмент своими руками и структурировать процесс проведения экспериментов.
Наше решение будет состоять из 4-х частей:
● Интерфейс для описания дизайна эксперимента
● ETL для агрегации необходимых метрик
● Автоматизация статистического анализа
● Визуализация результатов
Интерфейс для описания дизайна эксперимента
Интерфейс для описания дизайна эксперимента мы можем реализовать при помощи сложных инструментов: RShiny, Streamlit или Django. А можем воспользоваться Google таблицами и их API на Python. Разберем подробнее последний вариант.
Что из себя представляет базовая админка для заведения эксперимента? В нашем случае это будет таблица со списком экспериментов, датами включения и выключения экспериментов, их описаниями и соответсвующими ссылками на задачи.
Для этого отлично подходит Google таблица: в ней менеджер или аналитик может записать все необходимые данные об эксперименте и получить подобный результат:

Здесь мы также можем подумать о синхронизации этой таблицы и заведения эксперимента на бекенде, но для простоты будем использовать её только для систематизации проводимых экспериментов. Разработчики будут заводить эксперимент вручную по описанию из этой таблицы. Это пригодится нам для удобной визуализации и документации проводимых экспериментов.
При помощи библиотеки requests достанем данные из таблицы и сохраним в Pandas формате. Мы подробно изучаем работу с библиотекой requests в модуле Python, а здесь приведем пример кода, с которого можно начать:
from io import BytesIO import requests req = requests.get(your_link) data = req.content df = pd.read_csv(BytesIO(data))
Далее вы можете настроить расписание в Airflow, по которому раз в сутки будут считываться данные в таблице и заливаться в ClickHouse или любую другую базу данных, которую вы используете для аналитики (примечание: обратите внимание на наш блок на курсе Аналитик данных, в котором даются основы автоматизации и инструмента Airflow). Или можно попросить помощи у команды инженеров данных: у вас будет достаточно аргументов о пользе задачи :)
ETL для агрегации необходимых метрик
После того, как мы получили таблицу с описанием эксперимента, можем заняться агрегацией наших метрик. Допустим, в нашем продукте мы чаще всего смотрим на вовлечённость пользователей в рекламу и для этого замеряем количество кликов и показов. Такие метрики можно считать автоматически.
Примером запроса может быть, например, такой запрос в ClickHouse таблицу с сырыми данными действий пользователей в эксперименте (их мы будем различать по experiment_id, который нам передадут разработчики):
select dt, user_id, experiment_id, experimental_group, [‘clicks’, ‘views’] as metrics_names, [clicks, views] as metrics_values from (select dt, user_id, experiment_id, experimental_group, countIf(event = ‘click’) as clicks, countIf(event = ‘view’) as views from ads_data where dt >= ‘2023-02-02’ and experiment_id = 1 group by user_id, experiment_id, experimental_group, dt);
Результатом этого запроса станет статистика по каждому пользователю за весь период эксперимента. На её основе мы сможем посчитать статистическую значимость в следующем шаге.
Схема таблицы будет выглядеть таким образом:
CREATE TABLE ads_metrics
(
dt DateTime,
user_id Int64,
experiment_id Int32,
experimental_group String,
metrics_names Array(String),
metrics_values Array(UInt64)
) ENGINE = MergeTree()
ORDER BY (user_id, experiment_id);
Это значит, что, если мы захотим добавить новую метрику помимо кликов и показов, нам не нужно будет менять схему таблицы. Достаточно будет переписать запрос и добавить в базовом подзапросе countIf(event = ‘like’) as likes, а в верхнем подзапросе внести новую метрику в список названий метрик и колонку с ее расчётом в массив metrics_values.
Чтобы мы могли перейти к следующему шагу с подсчётом статистической значимости, необходимо настроить расписание, по которому Airflow или другой менеджер задач сможет кумулятивно собирать данные с даты старта эксперимента (которую мы можем взять из таблицы, основанной на данных из Google таблиц) до сегодняшнего дня (без фильтра на конкретную дату как в запросе выше).
Таким образом в последний день эксперимента мы получим полные данные, а до его наступления сможем наблюдать за динамикой p-value, MDE, размером экспериментальных групп и значениями метрик в тесте и в контроле.
Автоматизация статистического анализа
Эту часть будет сложнее автоматизировать для всех тестов, но для простейшей системы можем воспользоваться тестом t-test или bootstrap (о которых мы также подробно рассказываем на курсе). Но не стоит забывать, что вся описываемая в статье система лишь ускоряет сбор и систематизацию данных, но не может полностью заменить экспертизу аналитика в каждом отдельном эксперименте.
Итак, для того чтобы внедрить простейшие тесты, нам нужно написать скрипт на Python внутри Airflow, который будет считать статистическую значимость для каждого эксперимента на накопившихся к текущему дню данных, которые мы будем получать при помощи запроса из предыдущего шага.
Результаты подсчета p-value, MDE и разницы средних (uplift) будем записывать в третью таблицу — ads_results.
В итоге получим три новые таблицы, помимо сырых данных: ads_description (описание экспериментов из Google таблицы), ads_metrics (накопительные метрики по каждому дню), ads_results (результат статистического анализа). Далее будем использовать получившиеся таблицы в визуализации.
Визуализация результатов
Для визуализации будем использовать BI-систему Superset, но возможно использование любой другой. Важными графиками для визуализации будут:
● Графики с динамикой p-value и MDE (чем ближе эксперимент подкрадывается к расчитанному концу, тем более стабильными будут становить линии этих статистических метрик);
● Графики с динамикой метрик (контроль vs тест);
● Таблица со значениями разницы средний значений в тестовой и контрольной группе (uplift). Отрицательные значения лучше раскрасить в красный, а положительные — в зелёный. Так вы быстро сможете обнаружить проблемы;
● Графики с объёмом экспериментальных групп (важно следить за тем, чтобы группы наполнялись равномерно);
● Таблица с описанием экспериментов;
● Фильтр со значениями id эксперимента, датами и метриками, которые вам интересны.
Схематичный пример структуры дашборда с результатами экспериментов:

Итак, мы набросали драфт системы анализа A/B-экспериментов, которая поможет иметь результаты и описание всех экспериментов в одном ETL-процессе. Использовали инструменты: Python, Airflow, Superset, которые вы можете подробно изучить на курсе «Аналитик данных», а также затронули тему статистического анализа (ему тоже посвящён отдельный содержательный блок на курсе!).
Надеемся, что статья стала для вас вдохновением как для рабочего проекта, который принесет быстрые положительные результаты вашей команде, так и для pet-проекта, который покажет ваше понимание всего процесса проведения эксперимента от дизайна до его анализа. С данным инструментом важно оставаться ответственным за результаты и не переставать давать подробную интерпретацию и критический взгляд для заказчиков: так вы сможете предоставить не только быстрый, но и правдивый и качественный результат.
__________________________________________________________________________
Присоединиться к курсу «Аналитик данных»