Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛР / ЛР5 / Лабораторная работа5

.pdf
Скачиваний:
14
Добавлен:
25.06.2023
Размер:
493.75 Кб
Скачать

Лабораторная работа №5 Проведение A/B тестирования

Цель работы: изучить алгоритмы для проведения A/B тестирования для принятия решений.

Краткий теоретический материал

A/B-тесты проводят, чтобы точно измерить эффект от внедрения изменения.

Перед A/B- проводят A/A-тест для подтверждения корректности механизма проведения A/B-теста.

При анализе A/B-теста нужно знать про ошибки I и II рода, особенности анализа теста при множественном сравнении.

A/A-тест

Перед тем как начать A/B-тест, убедитесь, что:

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

инструмент «деления» трафика работает безошибочно;

данные отправляются в системы аналитики корректно.

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

Критерии успешного A/A-теста:

Количество пользователей в различных группах различается не более, чем на 1%;

Для всех групп фиксируют и отправляют в системы аналитики данные об одном и том же;

Различие ключевых метрик по группам не превышает 1% и не имеет статистической значимости;

Попавший в одну из групп посетитель остаётся в этой группе до конца теста. Если пользователь видит разные версии исследуемой страницы в ходе одного исследования, неизвестно, какая именно повлияла на его решения. Значит, и результаты такого теста нельзя интерпретировать однозначно.

Ошибки I и II рода при проверке гипотез. Мощность и значимость

Любую гипотезу могут принять или отвергнуть по ошибке. Математическая статистика даёт возможность оценить обе эти вероятности — они зависят от принятого уровня значимости.

Обычно рассматривают систему из двух гипотез (нулевой и альтернативной) и установленного уровня статистической значимости α. У Уровень статистической значимости — это вероятность случайно получить в реальном наблюдении значение, далёкое от предполагаемого в

нулевой гипотезе.

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

Такая ошибка называется ошибкой первого рода, или ложнопозитивным результатом статистического теста. Это означает, что различий между сравниваемыми группами нет, но тест показал p-value меньше уровня значимости. Получается, есть основания отвергнуть H . Так, вероятность ошибки первого рода равна уровню значимости α.

Ошибка второго рода ложнонегативный результат. Он указывает,

что различия между группами есть, но тест показал p-value больше уровня значимости α и нет оснований отвергать H . Если обозначить вероятность ошибки второго рода как β, то параметр 1 - β будет называться мощностью статистического теста. Раз β — вероятность ошибиться, то 1 - β — вероятность не ошибиться, то есть правильно отклонить нулевую гипотезу, когда она неверна.

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

Множественные сравнения: A/B и A/B/n-тесты

Одну гипотезу нередко тестируют в разных вариациях. Например, когда нужно сравнить три версии баннера на лендинге или пять вариантов ценообразования.

Сравнивать несколько групп с контрольной можно. Однако учитывайте увеличение вероятности ошибок.

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

Если всякий раз вероятность ошибиться равна ɑ, то вероятность не ошибиться: 1-ɑ. Так, вероятность не ошибиться ни разу за k сравнений равна:

В итоге вероятность ошибиться хотя бы раз за k сравнений:

Например, вы проверяете гипотезу о трёх возможных цветах кнопки «Купить». Против стандартного красного (группа A) потенциальными цветами выступают жёлтый, зеленый и белый (группы B1, B2, B3). Вы выбрали уровень значимости, равный 0.05.

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

Тогда вероятность того, что хотя бы в одном из трёх попарных сравнений будет зафиксирован ложнопозитивный результат равна:

В случае четырёх групп вероятность хотя бы одного ложнопозитивного результата уже примерно 18.55%. Если групп 10 — около 40%. Впрочем, в целях AB-тестирования такое количество групп применяют редко.

Групповая вероятность ошибки первого рода, или FWER (от англ. family-wise error rate, «групповой коэффициент ошибок»).

FWER = P(V≥1),

где V — число отвергнутых нулевых гипотез из числа верных нулевых гипотез. То есть V — число ложнопозитивных результатов, а FWER — вероятность получить хотя бы один такой результат. При общем числе гипотез m = 1, FWER = ɑ.

Чтобы снизить вероятность ложнопозитивного результата при множественном тестировании гипотез, применяют разные методы корректировки уровня значимости для уменьшения FWER.

Метод Бонферрони (поправка Бонферрони):

Самая грубая и распространённая поправка к требуемым уровням

значимости. Уровни значимости в каждом из m сравнений в m раз меньше, чем

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

Метод Холма

Метод Холма также гарантирует FWER < ɑ, но предъявляет более

мягкие требования к уровню значимости. Метод пошаговый: для первого сравнения требуемый уровень значимости равен отношению ɑ к числу попарных сравнений, для второго — отношению ɑ к (числу сравнений - 1) и так далее. Для последнего сравнения уровень значимости будет равен ɑ:

Метод Шидака

Метод Шидака также обеспечивает FWER < ɑ. Скорректированное значение требуемого уровня значимости рассчитывается по формуле:

Например, при ɑ = 0.05 и при двух сравнениях требуемый уровень значимости рассчитывают так: 1 - (1 - 0.05)^(1/2) = 0.0253, а при 4

сравнениях: 1 - (1 - 0.05)^(1/4) = 0.0127.

Чаще всего применяют поправку Бонферрони — из-за простоты решения. Легко поделить принятый уровень значимости на число сравнений, которые проводят на одних и тех же данных, без сбора новых наблюдений для каждого теста.

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

Изучим применение метода на практике.

Компания в течение месяца тестировала три варианта клиентских форм на лендинге. В датасетах sample_A, sample_B, sample_C ежедневное число пользователей, заполнивших первую, вторую и третью версию формы соответственно. Проверим гипотезу о равенстве среднего количества пользователей в каждой паре датасетов.

from scipy import stats as st import numpy as np

sample_A = [3071, 3636, 3454, 3151, 2185, 3259, 1727, 2263, 2015,

2582, 4815, 633, 3186, 887, 2028, 3589, 2564,

1422, 1785,

 

 

 

 

 

 

3180,

1770,

2716,

2546,

1848,

4644,

3134,

475, 2686,

 

 

 

 

 

 

1838, 3352]

sample_B = [1211, 1228, 2157, 3699, 600, 1898, 1688, 1420, 5048, 3007,

509, 3777, 5583, 3949, 121, 1674, 4300, 1338,

3066,

3562, 1010, 2311, 462, 863, 2021, 528, 1849,

255,

1740, 2596]

sample_C = [1211, 1228, 2157, 3699, 600, 1898, 1688, 1420, 5048, 3007,

509, 3777, 5583, 3949, 121, 1674, 4300, 1338,

3066,

3562, 1010, 2311, 462, 863, 2021, 528, 1849,

255,

1740, 2596]

alpha = 0.05 # критический уровень статистической значимости

results_AB = st.ttest_ind(sample_A, sample_B)

results_BC = st.ttest_ind(sample_B, sample_C)

results_AC = st.ttest_ind(sample_A, sample_C)

bonferroni_alpha = alpha / 3 # произведено три сравнения

print('p-значение для сравнения

групп

А

и

B:

',

results_AB.pvalue)

 

 

 

 

 

print('p-значение для сравнения

групп

B

и

C:

',

results_BC.pvalue)

 

 

 

 

 

print('p-значение для сравнения

групп

А

и

C:

',

results_AC.pvalue)

 

 

 

 

 

if results_AB.pvalue < bonferroni_alpha: print('Отвергаем нулевую гипотезу для сравнения

групп А и B') else:

print(

'Не получилось отвергнуть нулевую гипотезу для сравнения групп А и B'

)

if results_BC.pvalue < bonferroni_alpha: print('Отвергаем нулевую гипотезу для сравнения

групп B и C') else:

print(

'Не получилось отвергнуть нулевую гипотезу для сравнения групп B и C'

)

if results_AC.pvalue < bonferroni_alpha: print('Отвергаем нулевую гипотезу для сравнения

групп А и C') else:

print(

'Не получилось отвергнуть нулевую гипотезу для сравнения групп А и C'

)

Результат

p-значение для сравнения групп А и B: 0.1912450522572209 p-значение для сравнения групп B и C: 1.0

p-значение для сравнения групп А и C: 0.1912450522572209 Не получилось отвергнуть нулевую гипотезу для сравнения групп А и B

Не получилось отвергнуть нулевую гипотезу для сравнения групп B и C

Не получилось отвергнуть нулевую гипотезу для сравнения групп А и C

Дополнительные материалы - https://gopractice.ru/data/how-not-to- analyze-abtests/

Проверка гипотезы о равенстве долей

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

Напомним, что при оценке среднего значения генеральной совокупности выборочные средние нормально распределены вокруг среднего всей совокупности независимо от того, как распределена сама генеральная совокупность. Это одна из формулировок центральной предельной теоремы.

Решим задачу сравнения пропорций двух генеральных совокупностей по выборкам из них.

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

Величина Z — стандартная для критерия со стандартным нормальным распределением: со средним, равным нулю, и стандартным отклонением, равным единице. Это указано в правой части формулы после знака, который говорит, что выражение распределено как N(0,1).

Вформуле n и n — размеры двух сравниваемых выборок, то есть количества наблюдений в них; P , P — пропорции, наблюдаемые в выборках; P — пропорция в выборке, скомбинированной из двух наблюдаемых; π , π — настоящие пропорции в сравниваемых генеральных совокупностях.

ВA/B-тестировании чаще всего проверяют гипотезу о равенстве π и π . Тогда при верной нулевой гипотезе выражение (π - π ) в числителе будет равно нулю, и критерий можно рассчитывать только по выборочным данным.

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

Например, сравним доли клиентов, сделавших заказ. Из 830 зарегистрировавшихся пользователей, пришедших через первый рекламный канал, заказ сделало 78 человек; а из 909, пришедших через второй канал —

120.

Можно ли сделать вывод о разнице в конверсии регистраций в заказ для этих каналов?

from scipy import stats as st

import numpy as np import math as mth

alpha = .05 # критический уровень статистической значимости

successes = np.array([78, 120]) trials = np.array([830, 909])

#пропорция успехов в первой группе: p1 = successes[0]/trials[0]

#пропорция успехов во второй группе: p2 = successes[1]/trials[1]

#пропорция успехов в комбинированном датасете:

p_combined = (successes[0] + successes[1]) / (trials[0] + trials[1])

# разница пропорций в датасетах difference = p1 - p2

Считаем статистику в стандартных отклонениях стандартного нормального распределения:

#считаем статистику в ст.отклонениях стандартного нормального распределения

z_value = difference / mth.sqrt(p_combined * (1 - p_combined) * (1/trials[0] + 1/trials[1]))

#задаем стандартное нормальное распределение (среднее 0, ст.отклонение 1)

distr = st.norm(0, 1)

Если бы пропорции были равны, разница между ними была бы равна нулю. Посчитаем, как далеко статистика от нуля. Какова вероятность получить такое отличие или больше? Так как распределение статистики нормальное, вызовем метод cdf(). Саму статистику возьмём по модулю методом abs() — чтобы получить правильный результат независимо от её знака. Это возможно, потому что тест двусторонний. По этой же причине удваиваем результат:

# считаем статистику в ст.отклонениях стандартного нормального распределения

z_value = difference / mth.sqrt(

p_combined * (1 - p_combined) * (1 / trials[0] + 1 / trials[1])

)

# задаем стандартное нормальное распределение (среднее 0, ст.отклонение 1)

distr = st.norm(0, 1)

p_value = (1 - distr.cdf(abs(z_value))) * 2

print('p-значение: ', p_value)

if p_value < alpha:

print('Отвергаем нулевую гипотезу: между долями есть значимая разница')

else:

print(

'Не получилось отвергнуть нулевую гипотезу, нет оснований считать доли разными'

)

Результат

Такая разница в пропорциях при указанных размерах выборок достаточна, чтобы говорить о статистически значимом различии. Хотя на первый взгляд, различие 9% и 13% кажется небольшим.

Основные ошибки при анализе А/B-тестов

Некорректное деление трафика теста

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

Например, нельзя считать корректным делением трафика A/B-тест, в котором пользователи группы A — посетители мобильной версии сайта, а пользователи группы B — десктопной.

Разные доли также искажают результаты. Например, если группы теста делятся не 50 на 50, а 49 на 51, относительное различие количества пользователей будет равно 1-49/51=0.0392 — почти 4%. Если из-за этого вы обнаружите ухудшение выручки на 4%, скорее всего, прервёте тест и забудете про гипотезу.

Игнорирование статистической значимости

Часто решение о различии в результатах теста принимают только на основе относительного изменения.

«Один сегмент лучше другого на 5%» — неизвестно, действительно он лучше или это статистическая флуктуация. Все неверные решения в долгосрочной перспективе ведут к потере или недополучению денег бизнесом.

Слишком маленькая выборка

Довореять результатам теста на 10-20 пользователей нельзя. Ни значимости, ни точности — слишком велико влияние каждого отдельного наблюдения.

Слишком быстрый тест или слишком долгий тест

Необходимо принимать решение, когда уверены в результатах.

Отсутствие анализа аномалий

Помните об аномалиях и анализируйте результаты только с их учётом.

Пренебрежение поправками к статистической значимости при множественном сравнении

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

Порядок выполнения

1 часть задания (выполнить только эту часть – максимальная оценка – хорошо)

1. Получите исходные данные для решения поставленной задачи. Набор данных у всех один, варианты заданий разные.

2.Прочитайте данные из файлов с помощью pandas.

3.Проверьте данные на наличие пропусков, дубликатов и других

аномалий.

4.Преобразуйте данные к нужному формату, если это необходимо.

5.Посмотрите, есть ли пересекающие пользователи и удалите их.

6.Создайте массив уникальных пар значений дат и групп теста - datesGroups = orders[['date','group']].drop_duplicates()

7.Получите агрегированные кумулятивные данные по дням о

заказах

datesGroups.apply(lambda x: orders[np.logical_and(orders['date'] <= x['date'], orders['group'] == x['group'])]\

.agg({'date' : 'max', 'group' : 'max', 'transactionid' : 'nunique', 'visitorid' : 'nunique', 'revenue' : 'sum'}), axis=1).sort_values(by=['date','group'])

8. Получите агрегированные кумулятивные данные по дням о посетителях

datesGroups.apply(lambda x: visitors[np.logical_and(visitors['date'] <= x['date'], visitors['group'] == x['group'])].agg({'date' : 'max', 'group' : 'max', 'visitors' : 'sum'}), axis=1).sort_values(by=['date','group'])

visitorsAggregated.head()

9. Объедините данные в одной таблице, чтобы получилось так

cumulativeData.columns = ['date', 'group', 'orders', 'buyers', 'revenue',

'visitors']

10. Выполните задание по вариантам. Используйте cumulativeData. Разделите cumulativeData на cumulativeRevenueA и cumulativeRevenueB – для группы А и B.

1вариант – Изобразить график выручки по группам А и B. По оси y

revenue, по оси x - date

2вариант – Изобразить график среднего чека по группам А и В. По оси х – date, по оси y – revenue/ orders

3вариант – Изобразить график конверсии по группам А и B. По оси x – date, по оси y – конверсия.

Соседние файлы в папке ЛР5