Всем привет! A/B тестирование уже давно стало стандартом в проверке гипотез и улучшении продуктов в X5. Но, как ни странно, многие из «модных» техник, которые применяются в A/B тестировании, на самом деле, не что иное, как вариации старой доброй линейной регрессии. 

Например, использование таких методов, как t-тест, стратификация, CUPED, CUMPED, по сути, сводятся к построению линейной регрессии и проверке гипотезы в рамках построенной модели. Наши коллеги из команды ad-hoc аналитики Х5 Tech уже писали про стратификацию здесь и про CUPED здесь, а по этой ссылке лежит статья про CUMPED и подобные вариации CUPED.

Основная идея здесь проста: правильное добавление новых переменных в модель помогает лучше контролировать внешние факторы и уменьшать шум в данных. Это позволяет точнее оценить эффект от воздействия и объединить разные статистические подходы, которые обычно рассматриваются отдельно. Но почему это работает? Почему всё сводится к тому, что добавление переменных помогает объединить, казалось бы, разрозненные техники? 

Чтобы разобраться в этом, для начала вспомним основы линейной регрессии, после чего перейдём к различным статистическим методам снижения дисперсии и покажем, как они сводятся к линейной регрессии. Затем объединим все техники вместе и на примере покажем, как они работают на практике.

Парная регрессия

Линейная регрессия моделирует взаимосвязь между независимыми и зависимой переменными, подбирая прямую линию (или гиперплоскость в случае множества переменных), которая лучше всего описывает зависимость между ними. Независимая переменная – это переменная, которую мы считаем влияющей на зависимую переменную. Зависимая переменная – интересующая нас переменная, влияние на которую мы хотим изучить. Независимые переменные объясняют изменения зависимой переменной. Уравнение линейной регрессии для случая с одной независимой переменной  выглядит следующим образом:

y = \beta_0 + \beta_1 x + \epsilon

где y – зависимая переменная;x– независимая переменная;\beta_0– свободный член, значение точки пересечения оси ординат;\beta_1– это коэффициент наклона, показывающий изменениеyпри измененииxна единицу, при условии, что все другие независимые переменные остаются неизменными;ϵ — случайная ошибка, которая учитывает влияние всех других факторов, которые не были включены в модель.

Например, предположим, что мы хотим изучить, как количество дней с активными промоакциями влияет на недельную выручку в магазине. У нас есть данные, собранные из нескольких магазинов. Для каждого магазина в наборе данных есть два значения:x_i– количество дней с активными промоакциями иy_i– недельная выручка. В данном случае количество дней с активными промоакциями будет независимой переменной, а недельная выручка будет зависимой переменной.

Для нахождения наиболее точной модели, описывающей взаимосвязь между переменными, чаще всего используется метод наименьших квадратов, он минимизирует сумму квадратов отклонений между реальными значениямиyи предсказанными. Сумма квадратов отклонений называется RSS (Residual Sum of Squares).

RSS = \sum_{i=1}^{n} (y_i - \hat{y}_i)^2

По сути, метод наименьших квадратов помогает найти такую линию, которая проходит как можно ближе к большинству точек на графике.

Метод наименьших квадратов
Метод наименьших квадратов

Перепишем уравнение RSS:

RSS = \sum_{i=1}^{n} \left( y_i - \beta_0 - \beta_1 x_i \right)^2

Найдём частные производные для\beta_0​и \beta_1и приравняем их к нулю. Решив систему уравнений, получим:

\hat{\beta}_0 = \bar{y} - \hat{\beta}_1 \bar{x}\hat{\beta}_1 = \frac{\sum_{i=1}^{n} (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i=1}^{n} (x_i - \bar{x})^2}

Упростив, получим:

\hat{\beta}_1 = \frac{\widehat{\text{Cov}}(Y, X)}{\widehat{\text{Var}}(X)}

Где\text{Cov}(Y, X) — ковариация междуYиX;\text{Var}(X)— дисперсияX.

Для каждого коэффициента мы можем оценить его статистическую значимость. Это делается с помощью t-статистики и p-значений. Если p-значение меньше определённого уровня значимости (например, 0,05), мы можем сказать, что коэффициент статистически значим. Это означает, что при условии, что на самом деле изменение независимой переменной не оказывает влияния на зависимую переменную, вероятность получения такой t статистики или более экстремального значения (по модулю) крайне мала. Таким образом, мы можем сделать вывод, что изменение независимой переменной, скорее всего, оказывает влияние на зависимую переменную.

При определённых предположениях можно доказать (что выходит за рамки данной статьи), что оценка коэффициента \beta_1сходится по распределению к нормальному распределению, и поэтому мы можем построить доверительный интервал:

\hat{\beta}_1 \pm z_{\alpha/2} \cdot \sqrt{\widehat{\text{Var}}(\hat{\beta}_1)}

Где z_{\alpha/2} – квантиль нормального распределения,\alpha – уровень значимости.

Оценка дисперсии оценки коэффициента равна:

\widehat{\text{Var}}(\hat{\beta}_1) = \frac{\hat{\sigma}^2}{\sum_{i=1}^{n} (x_i - \bar{x})^2}

Где\hat{\sigma}^2— оценка дисперсии ошибок модели (остатков),x_i— значения независимой переменной,\bar{x} — среднее значение независимой переменной.

\hat{\sigma}^2 = \frac{1}{n - 2} \sum (y_i - \hat{y}_i)^2

 Множественная регрессия

Модель линейной регрессии с несколькими переменными записывается следующим образом:

y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \cdots + \beta_k x_k + \epsilon

Гдеy — зависимая переменная;\beta_0​— свободный член,\beta_1, \beta_2​,…,\beta_k​ — коэффициенты при независимых переменных;x_1, x_2,…,x_k— независимые переменные;ϵ — ошибка модели.

Оценка коэффициента будет равна:

\hat{\beta}_i = \frac{\widehat{\text{Cov}}(\tilde{Y},\, x_i)}{\widehat{\text{Var}}(x_i)}

Где\tilde{Y}— это разница между фактическим значением Yи тем значением, которое мы получили, построив множественную регрессию Y на независимые переменные, кромеx_i, и константу​.\tilde{Y}нельзя предсказать с помощью переменных​, которые мы использовали для предсказанияY, а это значит, что\tilde{Y}– это часть результата, которая не объясняется этими переменными. 

Аналогично для этого коэффициента мы можем построить доверительный интервал:

\hat{\beta}_i \pm z_{\alpha/2} \cdot \sqrt{\widehat{\text{Var}}(\hat{\beta}_i)}

Оценка дисперсии оценки интересующего коэффициента будет равна:

\widehat{\text{Var}}(\hat{\beta}_i) = \frac{\hat{\sigma}^2}{\sum (x_j - \bar{x})^2 \cdot (1 - R^2)}

R^2 — коэффициент детерминации, квадрат коэффициента корреляции между переменной x и оставшимися независимыми переменными, присутствующими в модели.

ATE – Average Treatment Effect

Прежде чем углубляться в анализ результатов регрессии, рассмотрим, что такое Average Treatment Effect (ATE), и почему он играет ключевую роль в нашей оценке. ATE — это средний эффект от воздействия. Он оценивается как разница в средних значениях интересующей метрики между двумя группами: тестовой и контрольной. Тестовая группа подвергается воздействию или какому-то изменению, а контрольная группа остается без изменений, чтобы мы могли сравнить результаты в этих группах. Следует отметить, что далее мы рассматриваем исключительно случай рандомизированного эксперимента, где попадание в тестовую и контрольную группы происходит случайным образом. Например, мы тестируем новую выкладку товаров в сети офлайн-магазинов и хотим понять, как это повлияет на объем продаж. В тестовой группе магазинов товары размещаются по-новому, в то время как в контрольной группе выкладка остается прежней. ATE в этом случае покажет, насколько средний объем продаж отличается между магазинами с новой и старой выкладкой.

Формально, ATE можно записать как\text{ATE} = \mathbb{E}[Y \mid D=1] - \mathbb{E}[Y \mid D=0], гдеD – статус принадлежности к тестовой или контрольной группе (тритмент), а Y - интересующая метрика. Фактически, в t-тесте мы тоже оцениваем ATE – разность средних значений метрики между двумя группами.

Когда мы оцениваем коэффициенты модели линейной регрессии, в которой переменная, обозначающая принадлежность к тестовой или контрольной группе, представлена бинарной переменной (0 для контрольной группы и 1 для тестовой), оценка коэффициента при этой переменной фактически является оценкой ATE.

y = \beta_0 + \beta_1 D + \epsilon

Взяв математическое ожидание от этого уравнения в двух случаях (D=0, D=1), при определённых предположениях, о которых поговорим позже, получим:

\mathbb{E}[Y \mid D = 0] = \beta_0  \mathbb{E}[Y \mid D = 1] = \beta_0 + \beta_1

То есть \mathbb{E}[Y \mid D=0] = \beta_0 (математическое ожидание метрики в контрольной группе) и\mathbb{E}[Y \mid D=1] = \beta_0 + \beta_1(математическое ожидание метрики в тестовой группе). Тогда \mathbb{E}[Y \mid D=1] - \mathbb{E}[Y \mid D=0] = \beta_1 = \text{ATE}.

Хорошие переменные

Точно так же, как и в парной регрессии, мы можем получить ATE, используя множественную линейную регрессию.

y = \beta_0 + \kappa D + \beta_1 X_1 + \beta_2 X_2 + \cdots + \beta_k X_k + \epsilon

гдеy – зависимая переменнаяX_1,X_2​,…,X_k​ – независимые переменные;\beta_0 – свободный член;κ — коэффициент воздействия приD, как раз отражающий ATE;D – статус принадлежности к тестовой или контрольной группе​,\beta_1,…,\beta_k​ — коэффициенты регрессии, показывающие, насколько изменится Y при изменении соответствующей переменнойX_iна одну единицу, если остальные переменные остаются неизменными;ϵ — случайная ошибка, которая учитывает влияние всех других факторов, которые не были включены в модель.

Основное преимущество использования нескольких переменных заключается в возможности контролировать различные факторы, влияющие на интересующую метрику, что позволяет уменьшить дисперсию оценки коэффициента.

Представим, что у нас есть ковариатаX(например, размер магазина), которая хорошо предсказывает зависимую переменнуюY(например, объём продаж), но независима от тритментаD(например, новая рекламная кампания, которую мы хотим запустить), что будет достигаться в нашем случае, так как мы говорим о рандомизированном эксперименте, то есть магазины выбираются случайным образом в тестовую и контрольную группы. Когда мы добавляем ковариатуXв модель, она помогает объяснить часть вариации вY, которая раньше считалась случайной ошибкойϵ, как бы очищая взаимосвязь междуDиy. Это приводит к снижению дисперсии\sigma^2, которая стоит в формуле дисперсии оценки коэффициента. Из-за этого дисперсия оценки коэффициента становится меньше.

\widehat{\text{Var}}(\hat{\kappa}) = \frac{\hat{\sigma}^2}{\sum (D_i - \bar{D})^2 (1 - R^2)}

Чем меньше дисперсия, тем меньше и стандартная ошибка оценки коэффициента

\widehat{\text{SE}}(\hat{\kappa}) = \sqrt{\widehat{\text{Var}}(\hat{\kappa})}

Наши доверительные интервалы становятся уже, что даёт нам возможность обнаруживать более мелкие по размеру эффекты

\hat{\kappa} \pm z_{\alpha/2} \cdot \sqrt{\widehat{\text{Var}}(\hat{\kappa})}

Гдеz_{\alpha/2} – квантиль нормального распределения,\alpha – уровень значимости.

Таким образом, стоит включать переменные, которые являются хорошими предикторами интересующей метрики.

Предпосылки применения линейной регрессии для получения несмещённой и состоятельной оценки эффекта в случае рандомизированного эксперимента.

В контексте машинного обучения при использовании линейной регрессии нам важнее всего наиболее точно спрогнозироватьyи в целом нам не очень важны коэффициенты модели и их статистические свойства. Однако в контексте A/B тестирования нас интересует лишь коэффициент при переменнойD, которая обозначает статус принадлежности к тестовой или контрольной группе (тритмент), так как именно этот коэффициент и показывает эффект от воздействия. Соответственно, нам важно получить качественную оценку коэффициента, то есть оценку несмещённую и состоятельную. Как этого достичь? 

Для начала скажем, что в нашей статье мы предполагаем гомоскедантичность случайных ошибок, то есть постоянство дисперсии случайных ошибок для всех наблюдений. Однако это предположение является не обязательным условием, оно лишь упростит наши формулы для линейной регрессии, которые мы будем использовать далее. А теперь перейдём к предпосылкам:

1. Чтобы у нас была возможность получить оценку интересующего коэффициента, нам необходимо отсутствие строгой мультиколлинеарности. Когда в модели возникает строгая мультиколлинеарность, одна или несколько независимых переменных являются точными линейными комбинациями других. Это означает, что столбцы матрицы признаков Xлинейно зависимы. При наличии такой зависимости матрицаX'X, которую мы используем для вычисления коэффициентов регрессии, становится вырожденной. В результате такая матрица не может быть обращена, что необходимо для нахождения коэффициентов регрессии методом наименьших квадратов (формула для оценки коэффициента линейной регрессии методом наименьших квадратов в матричной форме):

\hat{\beta} = (X'X)^{-1} X'Y

2.\boldsymbol{x_i}и\boldsymbol{y_i}имеют ненулевые конечные четвертые моменты распределения.

\mathbb{E}(x_i^4) < \infty, \quad \mathbb{E}(y_i^4) < \infty

По существу, это значит, что вероятность появления экстремально больших выбросов в данных крайне мала. Это предположение считается достаточно слабым, поэтому предполагается, что обычно оно выполнимо на практике. 

3. Экзогенность тритмента. Также в контексте нашего анализа важно, чтобы переменная тритментаDоставалась экзогенной, то есть условная ковариация переменнойDи ошибки моделиϵ, при фиксированных переменныхX, равна нулю:

\text{cov}(D, \epsilon \mid X) = 0

Докажем несмещённость и состоятельность нашей оценки коэффициента при экзогенности тритмента: 

воспользуемся утверждением без доказательства, что если наблюдения (x_i, y_i) независимы и одинаково распределены, то

\widehat{\text{var}}(x) \xrightarrow{p} \text{var}(x)\widehat{\text{cov}}(x, y) \xrightarrow{p} \text{cov}(x, y)

Тогда:

\hat{\beta}_2 = \frac{\widehat{\text{cov}}(x, y)}{\widehat{\text{var}}(x)} \xrightarrow{p} \frac{\text{cov}(x_i, y_i)}{\text{var}(x_i)} = \frac{\text{cov}(x_i, \beta_1 + \beta_2 \cdot x_i + \epsilon_i)}{\text{var}(x_i)} =\frac{\text{cov}(x_i, \beta_2 \cdot x_i + \epsilon_i)}{\text{var}(x_i)} = \frac{\beta_2 \cdot \text{cov}(x_i, x_i) + \text{cov}(x_i, \epsilon_i)}{\text{var}(x_i)} = \beta_2 + \frac{\text{cov}(x_i, \epsilon_i)}{\text{var}(x_i)}

Таким образом получаем:

\hat{\beta}_2 \xrightarrow{p} \beta_2 + \frac{\text{cov}(x_i, \epsilon_i)}{\text{var}(x_i)}

Учитывая, что наша переменная экзогенна, а значит ковариация x и ошибки модели равна 0, мы получим состоятельную и несмещённую оценку.

\hat{\beta}_2 \xrightarrow{p} \beta_2\mathbb{E}[\hat{\beta}_2] = \beta_2

Нарушение предпосылки об экзогенности переменной – одна из самых важных проблем. Давайте рассмотрим возможные причины её возникновения в контексте оценки экспериментов.

Причина 1. Пропуск существенной переменной.

Предположим, мы изучаем эффект новой программы лояльности на продажи магазинов, но не учитываем маркетинговую активность, которая также влияет на продажи. Если магазины с более высокой маркетинговой активностью попали в тестовую группу, а с более низкой – в контрольную, это приведёт к тому, что влияние программы лояльности будет переоценено, так как рост продаж может быть связан не только с новой программой, но и с маркетингом. В таком случае маркетинговая активность является пропущенной переменной, которая вызывает эндогенность интересующей нас переменной.

Однако в случае рандомизированного эксперимента, где магазины случайным образом распределены в тестовую и контрольную группы, пропуск переменной не создаст никакого смещения. Это связано с тем, что влияние маркетинговой активности распределено случайно между тестовой и контрольной группами. Благодаря этому её влияние на интересующую метрику будет одинаковым как в тестовой, так и в контрольной группе, и она не приведёт к возникновению эндогенности. 

Причина 2. Влияние зависимой переменной на ковариаты во время эксперимента.

Предположим, мы изучаем эффект рекламной кампании (тритмент) на количество продаж (зависимая переменная). Одновременно мы добавляем в модель ковариату — количество положительных отзывов о продукте, собранных во время эксперимента, — с целью снижения дисперсии оценки эффекта.

Проблема возникает, если наша зависимая переменная может оказывать влияние на ковариату во время эксперимента. Например, успешная рекламная кампания может увеличить количество продаж, что приведёт к большему числу положительных отзывов.

Тут есть два приемлемых варианта – если мы выбираем использовать ковариату, собранную во время эксперимента, то зависимая переменная никак не должна влиять на эту ковариату. Это может быть пол, возраст и тому подобное. Второй вариант – использовать ковариату, собранную до проведения эксперимента. Таким образом наша зависимая переменная во время эксперимента никак не повлияет на эту ковариату.

Ключевая задача в этом случае — корректно подбирать ковариаты таким образом, чтобы они не подвергались влиянию зависимой переменной во время эксперимента.

Техники A/B тестирования и линейная регрессия

T-Test

Тест Стьюдента — это статистический тест, используемый для сравнения средних значений интересующей метрики между двумя группами. Он помогает определить, значима ли разница между средними значениями тестовой и контрольной групп. Более подробную информацию о t-тесте можно найти здесь

Как было показано ранее, коэффициент\beta_1при переменной тритмента в линейной регрессии представляет собой разницу средних между тестовой и контрольной группами, которая также является оценкой эффекта (ATE). В формулировке t-теста это выражается как:

\hat{\beta}_1 = \bar{Y}_{\text{test}} - \bar{Y}_{\text{control}}

t-статистика в t-тесте, оценивающая разницу между средними, имеет вид:

t = \frac{\bar{Y}_{\text{test}} - \bar{Y}_{\text{control}}}{\widehat{\text{SE}}(\bar{Y}_{\text{test}} - \bar{Y}_{\text{control}})}

В данном контексте t-test применяется при допущении, что дисперсии между группами равны. Если же это допущение не выполняется, тогда стоит использовать, например, t-тест Уэлча, который не требует равенства дисперсий между группами. В контексте линейной регрессии в этом случае применяются робастные стандартные ошибки, о них можно подробнее прочитать по этой ссылке

Продолжим. Оба метода оценивают одну и ту же величину — разницу между средними.

t = \frac{\hat{\beta}_1}{\widehat{\text{SE}}(\hat{\beta}_1)}

Доверительный интервал в таком случае имеет вид:

\left( \overline{Y}_{\text{test}} - \overline{Y}_{\text{control}} \right) \pm t_{\alpha / 2} \cdot \widehat{SE}\left( \overline{Y}_{\text{test}} - \overline{Y}_{\text{control}} \right)

Аналогичный доверительный интервал для коэффициента\beta_1​в линейной регрессии:

\hat{\beta}_1 \pm z_{\alpha / 2} \cdot \widehat{SE}(\hat{\beta}_1)

Отметим, что поскольку мы работаем с большими данными, t-распределение будет совпадать с нормальным распределением. При достаточно больших выборках оба метода будут давать одинаковые результаты.

Получается, что t-тест эквивалентен построению линейной регрессии, где зависимой переменной является интересующая метрика, а независимой переменной — принадлежность объекта к тестовой группе. В случае линейной регрессии уравнение имеет вид:

y = \beta_0 + \beta_1 D + \epsilon

гдеD— статус присвоения к тестовой группе (1 для тестовой группы и 0 для контрольной группы),\beta_0— среднее значениеyв контрольной группе,\beta_1— коэффициент, который показывает разницу между средними значениями в тестовой и контрольной группах (ATE),ϵ— случайная ошибка.

Таким образом, мы можем сравнить группы в рамках эксперимента как напрямую с помощью t-test, так и путем построения линейной регрессии и проверки данной гипотезы в рамках построенной модели. 

Однако на этом наши возможности не заканчиваются, мы можем улучшить нашу оценку путём добавления новых переменных в регрессию. Поскольку мы рассматриваем случай честного рандомизированного эксперимента, при добавлении переменных в модель речь идёт прежде всего о ковариатах. Как мы показали ранее, добавление ковариат помогает объяснить часть вариации в зависимой переменной, тем самым уменьшая остаточную ошибку модели. А это приводит к уменьшению дисперсии оценок эффекта воздействия, снижению стандартных ошибок и, как следствие, увеличению мощности теста.

Разберём методы, которые помогут нам реализовать этот подход и покажем, что все эти техники можно свести к линейной регрессии.

Стратификация

Наши коллеги уже писали про стратификацию здесь. Если кратко, то стратификация — это метод, который используется для уменьшения дисперсии оценок путём учёта принадлежности объектов эксперимента к определённым стратам, предположительно влияющих на зависимую переменную. Например, это может быть пол, возраст, география и тому подобное. В зависимости от способа формирования выборок и получения оценок стратификация может быть нескольких видов. В контексте линейной регрессии применяется постстратификация, которая используется для коррекции оценок после того, как эксперимент был уже проведён. 

Представим, что мы провели эксперимент, в котором хотели изучить влияние нового продукта. У нас есть данные о возрасте участников эксперимента, и мы хотим учесть этот фактор для уменьшения дисперсии оценок. Для этого мы делим участников на три возрастные группы: молодые, среднего возраста и старшие.

Постстратификация реализуется путём добавления фиктивных переменных в уравнение линейной регрессии. Эти переменные указывают принадлежность наблюдения к одной из возрастных страт и принимают значения 0 или 1. Например, фиктивная переменная young, равная 1, будет означать принадлежность объекта к молодой возрастной группе.

 Тогда уравнение линейной регрессии для стратификации будет выглядеть так:

Y = \beta_0 + \beta_1 D + \beta_2 \text{young} + \beta_3 \text{old} + \epsilon

гдеY— зависимая переменная,D— статус присвоения к тестовой группе (1 для тестовой группы и 0 для контрольной группы),young— фиктивная переменная, обозначающая принадлежность к молодой возрастной группе,old— фиктивная переменная, обозначающая принадлежность к старшей возрастной группе,ϵ— случайная ошибка.

Важно отметить, что добавляются только две фиктивные переменные (youngи old), чтобы избежать ловушки дамми-переменных, которая может привести к строгой мультиколлинеарности, если добавить переменные для всех возрастных групп.

Докажем, что значение коэффициента при тритменте в линейной регрессии действительно равно оценке эффекта АТЕ, полученному с помощью постстратификации. 

Имеем:

Y = \beta_0 + \beta_1 D + \sum_{k=1}^{K} \gamma_k S_k + \epsilon

ГдеY— интересующая метрика,D— переменная тритмента (0 или 1),S_k​— фиктивная переменная, которая указывает принадлежность к стратеk,\gamma_k— коэффициенты для стратыk,ϵ​ — ошибка модели.

Для каждой страты k можно записать математическое ожидание результата y для контрольной(D=0)и тестовой(D=1)групп:

E[Y \mid D = 0, S_k = 1] = \beta_0 + \gamma_kE[Y \mid D = 1, S_k = 1] = \beta_0 + \beta_1 + \gamma_k

Разность средних в каждой страте k между тестом и контролем будет:

\Delta Y_k = \left( \beta_0 + \beta_1 + \gamma_k \right) - \left( \beta_0 + \gamma_k \right) = \beta_1

Для вычисления общего эффекта тритмента по всем стратам, используется взвешенная разность средних, где вес каждой страты w_k​ пропорционален размеру страты:

\Delta Y_{\text{strat}} = \sum_{k=1}^{K} w_k \Delta Y_k

Так как \Delta Y_k = \beta_1 для каждой страты, то взвешенная разность средних равна:

\Delta Y_{\text{strat}} = \sum_{k=1}^{K} w_k \beta_1 = \beta_1

CUPED (Controlled-experiment Using Pre-Existing Data)

CUPED — это метод, который помогает снизить дисперсию оценок, используя дополнительную информацию, доступную до проведения эксперимента. Основная идея заключается в том, чтобы скорректировать целевую метрику, учитывая предэкспериментальные данные, и затем применить к ней статистический критерий (например, t-test). Таким образом, CUPED устраняет часть вариабельности этой метрики, которую можно объяснить историческими данными, что позволяет более точно оценить эффект от воздействия. Обычно в качестве таких данных используют значения той же метрики, измеренные до начала эксперимента. 

Для расчёта метрики методом CUPED используется следующее уравнение:

\hat{Y}^{\text{cuped}} = \overline{Y} - \theta \overline{X} + \theta \mathbb{E}[X]

гдеY– Среднее значение целевой метрики,X– среднее значение ковариаты (метрики до проведения эксперимента), а\theta– коэффициент приX, скалярная величина. 

Важно отметить, что принцип CUPED можно обобщить на другие похожие методы, например, CUPAC (Control Using Predictions As Covariate), где ковариата — это наша метрика, предсказанная ML моделью, или CUMPED – Multi CUPED, в котором мы используем не одну, а сразу несколько ковариат. Независимо от метода, добавление качественных ковариат способствует снижению дисперсии оценки. 

Дисперсия\hat{Y}^{\text{cuped}}равна:

\text{Var}\left( \hat{Y}^{\text{cuped}} \right) = \text{Var} \left( \overline{Y} - \theta \overline{X} + \theta \mathbb{E}[X] \right) = \\ = \text{Var} \left( \overline{Y} - \theta \overline{X} \right) / n = \\ = \left( \text{Var}(Y) + \theta^2 \text{Var}(X) - 2\theta \text{Cov}(X, Y) \right) / n

Дисперсия\hat{Y}^{\text{cuped}}минимизируется при:

\theta^* = \frac{\text{Cov}(X, Y)}{\text{Var}(X)}

Эта формула уже встречалась нам ранее как коэффициент линейной регрессии. Подставив\theta^*в формулу дисперсии\hat{Y}^{\text{cuped}}, мы получаем

\text{Var}\left( \hat{Y}^{\text{cuped}} \right) = \text{Var}(Y) \left( 1 - \rho^2 \right)

гдеp— это корреляция междуYиX.

Таким образом, чем выше корреляция междуYиX, тем большее уменьшение дисперсии с помощью CUPED.

Покажем, что оценка ATE методом CUPED равна оценке коэффициента линейной регрессии при тритменте beta. Уравнение линейной регрессии будет выглядеть следующим образом:

Y = \beta_0 + \beta_1 \cdot D + \beta_2 \cdot Y_{\text{до_пилота}} + \epsilon

Оценка ATE методом CUPED:

\Delta \hat{Y}^{\text{cuped}}=\left( \overline{Y}_T - \theta \overline{Y}_{\text{до_пилота}, T} + \theta \mathbb{E}[Y_{\text{до_пилота}}] \right) - \left( \overline{Y}_C - \theta \overline{Y}_{\text{до_пилота}, C} + \theta \mathbb{E}[Y_{\text{до_пилота}}] \right)

Где T и C обозначают принадлежность к тестовой или контрольной группе. Математические ожидания Y_{\text{до_пилота}} сокращаются, ведь они рассчитываются для всей популяции. 

Раскроем скобки:

\Delta \hat{Y}^{\text{cuped}} = \overline{Y}_T - \theta \overline{Y}_{\text{до_пилота}, T} - \overline{Y}_C + \theta \overline{Y}_{\text{до_пилота}, C}

Найдём разницу между средними значениями метрики в тестовой и контрольной группах в линейной регрессии:

\mathbb{E}[Y \mid D = 1] = \beta_0 + \beta_1 + \beta_2 \cdot \mathbb{E}[Y_{\text{до_пилота}} \mid D = 1]\mathbb{E}[Y \mid D = 0] = \beta_0 + \beta_2 \cdot \mathbb{E}[Y_{\text{до_пилота}} \mid D = 0]\mathbb{E}[Y \mid D = 1] - \mathbb{E}[Y \mid D = 0] = \beta_1 + \beta_2 \cdot \left( \mathbb{E}[Y_{\text{до_пилота}} \mid D = 1] - \mathbb{E}[Y_{\text{до_пилота}} \mid D = 0] \right)\beta_1 = \mathbb{E}[Y \mid D = 1] - \mathbb{E}[Y \mid D = 0] - \beta_2 \cdot \left( \mathbb{E}[Y_{\text{до_пилота}} \mid D = 1] - \mathbb{E}[Y_{\text{до_пилота}} \mid D = 0] \right)

Учитывая, что коэффициент\beta_2равен\theta, мы получили равенство оценки ATE методом CUPED и оценке коэффициента линейной регрессии.

А если мы сможем найти больше переменных, которые удовлетворяют требованиям экзогенности тритмента, которые были описаны выше? Тогда используем модель линейной регрессии со всеми ковариатами – в нашем случае это будет Multi CUPED (при этом стандартная ошибка оценки коэффициента станет ещё ниже):

Y = \beta_0 + \beta_1 \cdot D + \beta_2 \cdot Y_{\text{до_пилота}} + \beta_3 \cdot \text{covariate}_1 + \beta_4 \cdot \text{covariate}_2 + \beta_5 \cdot \text{covariate}_3 + \epsilon

Подробнее про то, какие переменные стоит добавлять в модель, а какие не стоит, можно прочитать в этой статье.

Все методы в одном уравнении

Мы рассмотрели несколько методов для снижения дисперсии. Каждый из этих подходов, снижая дисперсию, давал нам возможность получить более точные оценки. Но что, если объединить все эти методы в единое уравнение линейной регрессии? 

Предположим, что мы захотели провести эксперимент, и у нас есть данные о возрасте участников, значении метрики до эксперимента и значения других ковариат, влияющих на интересующую нас метрику. Мы уже рассмотрели, как каждый метод по отдельности, используя различные ковариаты, помогает снижать дисперсию оценки коэффициента, и теперь пришло время объединить их все в одно уравнение:

Y = \beta_0 + \beta_1 \cdot D + \beta_2 \cdot Y_{\text{до_пилота}} + \beta_3 \cdot \text{covariate}_1 + \beta_4 \cdot \text{covariate}_2 + \beta_5 \cdot \text{covariate}_3 + \beta_6 \cdot \text{young} + \beta_7 \cdot \text{old} + \epsilon

Объединяя все методы в одном уравнении линейной регрессии, мы одновременно используем все доступные нам ковариаты, таким образом минимизируя дисперсию оценки эффекта на сколько это возможно в нашем случае. 

Получается, что вместо того, чтобы применять методы поодиночке, мы можем интегрировать их в одно общее уравнение линейной регрессии, получив таким образом множественную линейную регрессию с переменной тритмента и всеми возможными ковариатами. 

В итоге уравнение регрессии на случай с множеством ковариат сводится к общему виду:

Y = \beta_0 + \beta_1 \cdot D + \sum_{k=1}^{n} \beta_k \cdot X_k + \epsilon

Y— зависимая переменная (интересующая метрика),\beta_0​— свободный член,D — тритмент (0 — контрольная группа, 1 — экспериментальная группа),X_k​— ковариаты, \beta_k— коэффициенты при ковариатах,ϵ— случайная ошибка модели.

Применение линейной регрессии на практике

Теперь продемонстрируем это всё на практике и посмотрим на стандартные ошибки оценки коэффициента при тритментеD. Для начала сгенерируем данные:

Код
def generate_experiment_data(
    n_samples: int = 30_000,
    mean1: int = 30,
    mean2: int = 30,
    std_dev1: int = 4,
    std_dev2: int = 4,
    seed: int = 2003,
) -> pd.DataFrame:
    """Создает экспериментальные данные для контрольной
    и пилотной групп с учетом нескольких ковариат.

    n_samples - количество наблюдений в каждой группе
    mean1, mean2 - средние значения метрик для контрольной и пилотной групп
    std_dev1, std_dev2 - стандартные отклонения метрик для групп

    return - DataFrame с данными эксперимента
    """
    np.random.seed(seed)
    
    # Генерация данных для контрольной и пилотной групп
    group1 = np.random.normal(loc=mean1, scale=std_dev1, size=n_samples)
    group2 = np.random.normal(loc=mean2, scale=std_dev2, size=n_samples)

    # Стратификация
    strata = np.random.choice(["young", "middle", "old"],
                              size=n_samples * 2, p=[0.3, 0.5, 0.2])

    # Дополнительные ковариаты
    covariate1 = np.random.normal(5, 1, size=n_samples * 2)  
    covariate2 = np.random.normal(10, 2, size=n_samples * 2) 
    covariate3 = np.random.normal(20, 5, size=n_samples * 2)  

    #  baseline_metric
    baseline_metric = np.concatenate([group1, group2])

    # пост-метрика
    y_post_metric = (
        baseline_metric * 1.7
        + np.concatenate([np.zeros(n_samples), np.ones(n_samples)]) * 5
        + covariate1 * 0.1  
        + covariate2 * 0.3  
        + covariate3 * 0.5
        + np.random.normal(0, 1.5, size=n_samples * 2)
    )
    y_post_metric += np.where(
        strata == "young", 1,
        np.where(strata == "middle", 5, 10)
    )

    data = pd.DataFrame({
        "baseline_metric": baseline_metric,
        "D": np.concatenate([np.zeros(n_samples), np.ones(n_samples)]),
        "strata": strata,
        "covariate1": covariate1,
        "covariate2": covariate2,
        "covariate3": covariate3,
     "y_post_metric": y_post_metric
    })

    return data


def analyze_experiment(data: pd.DataFrame) -> float:
    """построение графиков плотностей двух групп
    и вычисление разницы средних значений метрик

    data - DataFrame с данными эксперимента

    return - разница средних y_post_metric
    между пилотной и контрольной группами.
    """
    mean_difference = (
        data.loc[data["D"]== 1, "y_post_metric"].mean()
        - data.loc[data["D"] == 0, "y_post_metric"].mean()
    )

    plt.figure(figsize=(10, 6))
    sns.kdeplot(data=data, x="y_post_metric", hue="D", fill=True)
    plt.title("График плотностей")
    plt.xlabel("Metric")
    plt.ylabel("Density")
    plt.show()

    return mean_difference


data = generate_experiment_data()

mean_diff = analyze_experiment(data)
print("Разница средних: ", mean_diff)

График плотностей целевой метрики для тестовой и контрольной групп
График плотностей целевой метрики для тестовой и контрольной групп

Разница средних:  5.0461

Построим линейную регрессию, чтобы проверить гипотезу о равенстве средних с помощью t-test в рамках построенной модели, и посмотрим на стандартное отклонение оценки коэффициента приD– нашем эффекте воздействия: 

Код
def perform_ols_regression(data: pd.DataFrame):
    """выполняет OLS регрессию метрики y_post_metric на переменную D
    и возвращает информацию о коэффициентах модели

    data - DataFrame с данными эксперимента

    return - таблица коэффициентов для модели
    """
    model = smf.ols("y_post_metric ~ D", data=data).fit()

    coefficients_table = model.summary().tables[1]

    return coefficients_table

ols_result = perform_ols_regression(data)
print(ols_result)

результаты линейной регрессии (т-тест)
результаты линейной регрессии (т-тест)

В таком случае мы получили стандартную ошибку оценки коэффициента при D равную 0.066.

Воспользуемся методом постстратификации с помощью линейной регрессии и посмотрим на результат:

Код
def perform_stratified_regression(data: pd.DataFrame):
    """выполняет регрессию с учетом страт на переменную D
     и возвращает информацию по коэффициентам

    data - DataFrame с данными эксперимента

    return - таблица коэффициентов о модели
    """
    strata_dummies = pd.get_dummies(data["strata"], drop_first=True)
    data_with_dummies = pd.concat([data, strata_dummies], axis=1)
    
    X_strat = sm.add_constant(
        data_with_dummies[["D"] + list(strata_dummies.columns)]
    ).astype(float)

    model_strat = sm.OLS(data["y_post_metric"], X_strat).fit()

    return model_strat.summary().tables[1]


stratified_regression_result = perform_stratified_regression(data)
print(stratified_regression_result)

Результаты линейной регрессии (постстратификация)
Результаты линейной регрессии (постстратификация)

Стандартное отклонение оценки коэффициента при D уменьшилось до 0.060!

Теперь, используя предэкспериментальную ковариату, реализуем метод CUPED с помощью линейной регрессии:

Код
def perform_ols_regression_cuped(data: pd.DataFrame):
    """Выполняет регрессию, включая ковариату baseline_metric в модель
    и возвращает информацию по модели.

    data - DataFrame с данными эксперимента

    return - таблица коэффициентов модели.
    """
    simple_model = smf.ols("y_post_metric ~ D + baseline_metric", 
                           data=data).fit()

    return simple_model.summary().tables[1]

simple_result = perform_ols_regression_cuped(data)
print(simple_result)

Результаты регрессии (CUPED)
Результаты регрессии (CUPED)

Стандартная ошибка стала ещё ниже, теперь она равна 0.035.

Используя все имеющиеся ковариаты, задействуем метод CUMPED через линейную регрессию:

Код
def perform_ols_regression_multi_cuped(data: pd.DataFrame):
    """Выполняет Multi-CUPED с несколькими
    ковариатами (baseline_metric, covariate1, covariate2, covariate3).
    """
    multi_model = smf.ols(
        "y_post_metric ~ D + baseline_metric + covariate1 \
         + covariate2 + covariate3",
        data=data
    ).fit()

    return multi_model.summary().tables[1]

multi_result = perform_ols_regression_multi_cuped(data)
print(multi_result)

результаты регрессии (CUMPED)
результаты регрессии (CUMPED)

Получили стандартную ошибку, равную 0.028, что ещё меньше, чем в предыдущих примерах.

Наконец объединим все методы вместе:

Код
def perform_ols_all_methods(data: pd.DataFrame):
    """Выполняет ргерессию со
    всеми ковариатами (baseline_metric, strata,
    covariate1, covariate2, covariate3)."""
    multi_model = smf.ols(
        "y_post_metric ~ D + baseline_metric + strata \
      + covariate1 + covariate2 + covariate3",
        data=data
    ).fit()

    return multi_model.summary().tables[1]

all_result = perform_ols_all_methods(data)
print(all_result)

результаты регрессии (объединение методов)
результаты регрессии (объединение методов)

Как мы видим, таким образом, мы получили минимальное значение стандартной ошибки оценки коэффициента при D (0.012) по сравнению с другими методами по отдельности.

Распределение оценок коэффициентов
Распределение оценок коэффициентов

Общий вывод

Итак, линейная регрессия, как оказывается, является гораздо более универсальным инструментом, чем может показаться на первый взгляд. В этой статье мы продемонстрировали, что результаты многих статистических методов, применяемые в A/B тестировании, такие как t-тест, стратификация, CUPED, CUMPED в случае рандомизированного эксперимента можно получить путем построения линейной регрессии и проверки гипотезы в рамках построенной модели.

Получается, что все эти «новые» методы снижения дисперсии не такие уж и новые. Их всех можно представить через построение линейной регрессии, где главный подход сводится к довольно простой идее: добавление «хороших» переменных помогает уменьшить остаточную вариацию и улучшить точность оценки эффектов.

Для более глубокого понимания этих методов и их теоретической основы рекомендуем обратиться к книге Causal Inference for The Brave and True и учебнику Ф. С. Картаева.

Над статьёй работали члены команды Ad‑Hoc X5 Tech: Данила Яблочников и Денис Лавров.

Если эта статья заинтересовала вас, и вы хотели бы присоединиться к нашей команде, то мы с радостью приглашаем вас к нам! Отправьте своё резюме в Telegram @amSakhnov с пометкой «Статья». Мы будем рады познакомиться с вами и обсудить возможности сотрудничества.

Комментарии (3)


  1. DinkyPinky
    28.09.2024 12:18

    Похоже у вас ошибка в формуле после этого текста

    Получается, что t-тест эквивалентен построению линейной регрессии, где зависимой переменной является интересующая метрика, а независимой переменной — принадлежность объекта к тестовой группе. В случае линейной регрессии уравнение имеет вид:

    <формула>

    Скорее всего в ней вместо x должно быть D


    1. Tishiwii Автор
      28.09.2024 12:18

      спасибо, поправил)


  1. 0rchidus
    28.09.2024 12:18

    Спасибо за статью! Можно ли применять описанные техники для оценки эффектов на Ratio-метрики (CR, CTR) и требуются ли какие-то модификации для этого?