![](https://habrastorage.org/getpro/habr/upload_files/c62/9a9/b20/c629a9b203243525eb7f633651118e35.png)
Привет! На связи Алексей, Александр и Алиса. В предыдущей статье мы рассмотрели технические аспекты обучения ML-алгоритма по предсказанию отказа пользователей от рекламы.
Модель определяет пользователей, которых сегодня не стоит беспокоить рекламными коммуникациями, это снижает динамику пользовательских отказов от маркетинга при сохранении общего уровня продуктовой активности.
В этой статье мы рассмотрим используемые метрики для мониторинга качества модели и оценки ее точности in production. Поговорим об измерении статистически значимой эффективности решения, полученной с помощью fixed horizon a/b-теста. Рассмотрим последовательное использование статистических критериев на примере ratio-метрики.
Сравнение метрик качества: обучающий датасет VS реальный бизнес-процесс.
Посмотрим на распределение скоров модели, ROC-кривые и кривые Precision-Recall vs Threshold, построенные на сэмплированной выборке обучающего датасета и на реальных данных.
![Оценка производительности алгоритма на обучающем датасете (test data) Оценка производительности алгоритма на обучающем датасете (test data)](https://habrastorage.org/getpro/habr/upload_files/e5b/9fc/435/e5b9fc4358d9e93805b87d8ce9c33106.png)
![Оценка производительности алгоритма на реальных данных (in production) Оценка производительности алгоритма на реальных данных (in production)](https://habrastorage.org/getpro/habr/upload_files/b90/b41/dc5/b90b41dc565ec043940304773d9270a0.png)
Вид гистограммы распределения скоров практически не изменился, но мы видим снижение метрики ROC AUC и сильное падение точности алгоритма — Precision.
Реальные данные сильно отличаются от сэмплированных: на сэмплированных примерах конверсия в отказ от маркетинга была порядка 5%, на реальных же данных, наш bad rate составлял 293 клиента с отказом среди 10 980 642 активных за день, то есть ≈ 2,67e-5.
Абсолютная величина precision крайне мала ввиду большого числа примеров False Positive (FP). Строго говоря, при таком дисбалансе классов метрика ROC_AUC малочувствительна и будет показывать относительно хороший результат.
Приведем показательный пример
Матрица ошибок (confusion-matrix) | |||
Реальные значения классов (y) |
|||
y = 1 |
y = 0 |
||
Предсказания алгоритма (ŷ) |
ŷ = 1 |
True Positive (TP) |
False Positive(FP) |
ŷ = 0 |
False Negative (FN) |
True Negative (TN) |
Предположим, что необходимо найти сто особых примеров среди одного миллиона. Условимся, что данные подготовлены верно, шум и дубли отсутствуют.
Рассмотрим два алгоритма.
Алгоритм 1 |
Алгоритм 2 |
Возвращает 100 ответов, из которых: 90 — верно угаданных True Positive (TP); 10 — неверно False Positive (FP). При этом FN = 10 (всего 100 особых примеров, алгоритм нашел 90, значит, из них 10 — FN). При этом TN = 999 890 (всего 999 900 «0-примеров», 10 примеров алгоритм определил неверно, как особые) |
Возвращает 2000 ответов, из которых: 90 — верно угаданных True Positive (TP); 1910 — неверно False Positive (FP). При этом FN = 10 (всего 100 особых примеров, алгоритм нашел 90, значит, из них 10 — FN). При этом TN = 997 990 (всего 999 900 «0-примеров», 1 910 примеров алгоритм определил неверно, как особые) |
Рассчитаем ROC_AUC для бинарного ответа — «честная точность» в задаче с дисбалансом классов | |
TPR = TP / (TP + FN) = 90 / (90 + 10) = 0,9 FPR = F / (FP + TN) = 10 / (10 + 999 890) ≈ 1e-5 ROC_AUC = (1 + 0,9 − 0,00001) / 2 = 0,949995 |
TPR = TP / (TP + FN) = 90 / (90 + 10) = 0,9 FPR = FP / (FP + TN) = 1910 / (1 910 + 997 990) ≈ 191e-5 ROC_AUC = (1 + 0,9 − 0,00191) / 2 = 0,949045 |
То есть ROC_AUC отличается только четвертым знаком после запятой! Смотрим Recall и Precision.
Алгоритм 1 |
Алгоритм 2 |
Recall = TP / (TP + FN) = 0,9 / (90 + 10) = 0,9 Precision = TP / (TP + FP) = 90 / (90 + 10) = 0,9 |
Recall = TP / (TP + FN) = 0,9 / (90 + 10) = 0,9 Precision = TP / (TP + FP) = 90 / (90 + 1 910) = 0,045 |
Precision заметно просел, поэтому в таких случаях нужно смотреть на Precision в том числе.
Вывод из примера — при сильном дисбалансе необходимо смотреть метрики типа Precision или Precision/Recall AUC (PR_AUC). Но в нашем случае эта величина крайне мала. Значит модель плохо работает? — не совсем так.
В нашем случае метрика Precision и основанные на ней нечувствительны, но с другой стороны, при определенном threshold, value для бизнеса уже есть, но абсолютное значение такой метрики все еще будет крайне мало.
Представим крайний случай, что на планете нам нужно найти одного особого человека среди 8 млрд, какова вероятность при случайном поиске? ⅛ млрд ≈ 1e-9, что если наш алгоритм находит такого человека среди 1 млн? Это уже 1е-6 (как и Precision, он равен 1е-6), но это почти в 1 000 раз лучше, чем случайный поиск!
В таких случаях, используется распределение LIFT curve и в нашей задаче при выборе, например, топ-3% самой негативной по скорам группы определенной моделью, в ней оказывается в 7.26 раз больше реальных клиентов с отказом, чем при рандомизированном отборе пользователей.
Рекомендуемым отсечением в нашем случае будет топ-4% негативных по скорам пользователей, так как при переходе к группе до 5%, такая точность определения падает с 6.73 раз до 5.64 раз лучше по сравнению со случайным отбором.
Выбор топ-n% группы также означает, что мы руководствуемся не выбором детерминированного threshold по скору модели, а точным значением доли пользователей в ранжированном списке по скору ML-модели. Мы можем управлять числом пользователей, которым мы не будем сегодня отправлять маркетинговые коммуникации (в случае фиксации threshold такое число пользователей может изменяться изо дня в день).
Сдвиг данных и мониторинг качества.
Наш алгоритм обучался на конкретном наборе данных, а в реальных сценариях распределение данных со временем может изменяться, что приводит к явлению, известному как сдвиг данных.
Сдвиг данных происходит, когда данные обучения и данные, на которых развертывается модель, имеют разные распределения. Это может существенно повлиять на производительность и надежность моделей машинного обучения.
Существует множество подходов к анализу сдвига данных, и в контексте конкретной задачи они могут существенно отличаться. В нашем случае важна точность модели, которую мы определяем двумя метриками: ROC AUC и значение lift-кривой на уровне отсечения — 4% по результатам анализа lift-кривой выше.
При этом вторая метрика более чувствительна на сильно разреженных данных, а ROC AUC довольно робастна. При существенном снижении качества это станет заметно и на ROC AUC. Также сдвиг может произойти из-за изменений природы самого целевого действия, с этой точки зрения это довольно интересное наблюдение: как долго такой алгоритм будет сохранять надежность? Покажет только практика.
Рассмотрим динамики для метрик ROC AUC и значение lift-кривой на уровне отсечения:
![Графики мониторинга качества предсказательной силы алгоритма Графики мониторинга качества предсказательной силы алгоритма](https://habrastorage.org/getpro/habr/upload_files/5c7/070/61b/5c707061b08f6cfe88316cd6eb8b3fea.png)
Метрики рассчитываются с временным лагом в 3-5 дней от нынешней даты на новых данных: предсказания модели на конкретный день проверяются по факту реальных отказов через 2-3 дня.
При этом поканальное распределение рассчитывается исходя из следующей логики. Алгоритм определяет агрегированный отказ (вне зависимости от конкретного канала или их совокупности), то есть сам факт обращения пользователя на линию с целью отказа от рекламы. Мы можем технически сравнивать эти предсказания с событиями типа «1» — не общими отказами, а считать за «1» отказ в конкретном канале, таким образом, проверяя точность алгоритма в отдельных каналах.
На графиках b и с видно, что качество модели ниже в канале Telesales, это связано с тем, что алгоритм не обучался на отказах Telesales в силу специфики процедуры кроссейл-коммуникации. Тем не менее смысл целевого действия такой же и модель показывает удовлетворительный уровень классификации в данном канале и хорошую различительную способность в остальных.
Понедельный расчет ROC AUC имеет более стабильную динамику со средним значением метрики 0.82. Наш опыт использования модели показывает, что точность алгоритма сохраняется на протяжении 7 месяцев. С точки зрения сохранения причин отказа: основания единообразны и кардинальных изменений в логике отказов на краткосрочном периоде нет.
Со временем может меняться смысл признаков модели обучения, качество и полнота ваших данных, поэтому помимо мониторинга метрик качества предсказаний алгоритма мы отслеживали: изменения в данных и применение технической отсечки пользователей от рекламы.
Через несколько месяцев мы действительно «потеряли» несколько признаков без снижения предсказательной силы модели. Вы можете реализовать такую проверку на имеющемся инструментарии (достаточно любых базовых BI-инструментов) или с помощью систем управления рабочими процессами типа Apache AirFlow.
А/B-тест алгоритма in production
Среди частотных подходов можно выделить две основные методологии проведения ab-тестирования: с фиксированным горизонтом и последовательное тестирование.
Мы выбрали более классический подход фиксированного горизонта. С одной стороны наш тест проходил в марте — где есть сезонность и дополнительные выходные дни, поэтому останавливать тест раньше бизнес-цикла нельзя. С другой — выбор конкретных стратегий проведения последовательного тестирования нетривиальная задача: подходы сильно отличаются друг от друга и в контексте отдельных исследований могут предлагаться частные эмпирические правила для принятия решения об остановке теста.
Формирование гипотез. При проверке гипотез в части метрик влияния на: среднее число активных легких и тяжелых продуктов, а также среднее изменение их числа):
H0 (нулевая гипотеза) |
H1 (альтернативная гипотеза) |
μтест = μконтроль |
μтест ≠ μконтроль |
Легкие и тяжелые продукты — условное разделение целевых действий в различных банковских продуктах по логике его оформления. Например оформить дебетовую карту — это уникальное действие и тяжелый продукт, а оформить доставку продуктов можно многократно — это легкий продукт.
В случае одностороннего теста (при проверке гипотез в части метрик влияния на: конверсии в отказ и среднее число отказов на пользователя)
H0 (нулевая гипотеза) |
H1 (альтернативная гипотеза) |
μтест ≥ μконтроль |
μтест < μконтроль |
Мы выбрали три группы метрик:
целевая — основная метрика для проверки эффективности прямого назначения алгоритма. В качестве такой метрики была выбрана конверсия уникальных пользователей в отказ от рекламы при обращении на линию поддержки за время наблюдения.
прокси метрика — более чувствительная и сильно коррелирующая с целевой: среднее число уникальных отказов на пользователя за время наблюдения.
контрметрики — позволяют учесть риски, с которыми мы можем столкнуться при оптимизации целевой метрики. В данном случае это метрики влияния на бизнес-показатели: среднее число оформлений легких продуктов, среднее число оформления тяжелых продуктов и среднее изменение числа активных продуктов на пользователе.
Определение сегментов. Целевой сегмент — все активные пользователи банка, которые заходили хотя бы раз за месяц в основное банковское приложение или имеют хотя бы один действующий счет.
Деление на тест и контроль составило 1:1 (50%/50%). В тестовой группе происходит ежедневное удержание 4% (из анализа lift-кривой) пользователей с наибольшим скором негатива от рекламных рассылок.
Для проведения а/б-теста с фиксированным горизонтом нужно сначала рассчитать мощность теста по заранее заданным параметрам контроля до теста:
Конверсия контроля в абсолютной величине — для z-конверсионного теста, метрика конверсии уникальных пользователей в отказ от рекламы при обращении на линию поддержки за время наблюдения. Либо среднее квадратическое отклонение метрики в контроле для t-теста, все остальные ratio-метрики соответственно.
Ожидаемый аплифт не в процентах для z-конверсионного теста. В случае t-теста: абсолютная разница в значении метрики.
Мощность критерия. Выбираем по умолчанию 0.8;
Уровень значимости. Выбираем по умолчанию 0.05 + поправка Бонферрони: 0.05/5 = 0.01. Используется наиболее консервативная поправка для контроля уровня ложноположительных результатов (ошибка первого рода - ситуация, когда отвергнута верная нулевая гипотеза). В случае тестирования ML алгоритма, нам важно минимизировать риск ложных положительных выводов;
Вид альтернативной гипотезы. Двусторонняя в случае бизнес-метрик — мы не знаем в какую сторону повлияет удержание таких пользователей на бизнес-показатели, и односторонняя в случае метрик обращаемости — чем меньше отправляем коммуникаций, тем меньше пользователи задают вопросов по ним.
Отношение размера группы теста к контролю 1:1.
Для расчета детектируемого MDE (англ. Minimum Detectable Effect — минимально детектируемый эффект) и необходимого объема выборки можно использовать модуль statsmodels.stats.power из библиотеки statsmodels. Зная величины указанных параметров за n-е время до теста, мы определяем какая выборка нам необходима для соответствующего MDE за аналогичное время. В нашем случае для проведения теста нам было достаточно одного месяца наблюдений.
Результаты метрик через месяц в соответствующих группах теста и контроля:
Группа |
База, млн. ед. |
Конверсия в отказ, % |
Ср. знач. отказов, ед. |
Ср. знач. оформления легких продуктов, ед. |
Ср. знач. оформления тяжелых продуктов, ед. |
Ср. изменение числа активных продуктов на пользователе, ед |
Без изменений (контроль) |
13.95 |
0.052921 |
561*10-6 |
1.303589 |
0.094241 |
0.016507 |
ML model (тест) |
13.95 |
0.050234 |
530*10-6 |
1.304186 |
0.094432 |
0.016319 |
В нашем случае тест — это первая половина случайно отобранной группы пользователей, к которой ежедневно применялось правило удержания маркетинговых коммуникаций топ-4% наиболее склонной к негативу группы. Контрольная группа — вторая часть пользователей, которая не испытывала таких изменений.
Как корректно подвести итоги такого теста с множественным тестированием на ratio-метриках? Давайте разбираться по порядку.
Ratio-метрика: какие статистические критерии применять
Рассмотрим последовательную логику принятия решения о статистической значимости отличий в тестовой группе в сравнении с контрольной на примере бизнес-метрики (контрметрика) среднего числа оформлений легких продуктов. Начнем от обратного, чтобы логика применения тех или иных статистических критериев была прозрачной. Рассмотрим последовательность применения статистических критериев:
-
Анализируется Ration-метрика, значит применяем t-критерией, но какой: Стьюдента или Уэлча?
Это дискуссионный вопрос: с одной стороны, есть исследования, подтверждающие хорошую обобщающую способность критерия Уэлча как в случае равенства дисперсий (целевое использование), так и в случае гетероскедастичности (эквивалентно результатам t-критерия Стьюдента).В пользу применения только критерия Уэлча выступают и исследования, которые критикуют стратегию проведения первоначального анализа на однородность дисперсии, а затем применять либо t-критерий Стьюдента, когда дисперсии равны, либо t-критерий Уэлча неравной дисперсии, когда они соответственно различны. Проблема с этим подходом заключена в комбинации тестов, что ухудшает контроль частоты ошибок 1 рода.
С другой стороны, авторы данных статей, не исключают наличия экспериментов, в которых использование критерия Стьюдента будет более надежным. При выборе стратегии использования нескольких статистических критериев, используем следующие критерии проверки гомоскедастичности: критерий Левена или критерий Бартлета. Первый используется в случае ненормально распределенных данных, второй — для нормальных распределений.
Для проверки «нормальности» данных существует множество подходов: тест Шапиро-Уилка (для наблюдений N < 5000), Андерсона-Дарлинга, общий тест Колмогорова-Смирнова, Q-Q plot и другие. При этом, чем больше критериев мы применяем на одних и тех же данных, тем выше ошибка первого рода.
Конкретная стратегия использования статистических критериев может сильно отличаться. Это нормально, вспомним лестницу доказательных методов — англ. Hierarchy of evidence. Например вы работаете с классическими лабораторными экспериментами в области химии, в которых гарантируется сохранение одинаковых условий для двух вариантов пробирок, а также с заранее детерминированным распределением целевого вещества и известных равных отклонений.
В таком случае использование критерия Стьюдента будет обоснованно без предварительных тестов на нормальность и гомоскедастичность.
Реализуем цепочку рассуждений, то есть в случае, если мы всё же хотим убедиться в отдельных параметрах сравниваемых групп с применением конкретных статистических критериев.
Подход сочетания предварительных тестов. Анализируем тестовую группу в сравнении с контрольной на примере бизнес-метрики среднего числа оформлений легких продуктов.
Проверка на нормальность. Иногда достаточно и визуального анализа для определения распределения, далекого от нормального, как в нашем случае.
![Распределение среднего числа оформлений легких продуктов в тесте и контроле за время теста. Q-Q plot: графическое сравнений распределений с нормальным Распределение среднего числа оформлений легких продуктов в тесте и контроле за время теста. Q-Q plot: графическое сравнений распределений с нормальным](https://habrastorage.org/getpro/habr/upload_files/c6b/73b/374/c6b73b3749eb6ed529ff0eb0397146f1.png)
Код реализации графиков
import plotly.express as px
import pandas as pd
import scipy.stats as stats
#df - данные уже в агрегированном виде! (для px.bar)
fig = px.bar(df, x = 'sum_utilizations', y = 'cnt', color = 'group_nm', barmode = 'group')
fig.update_xaxes(tickfont=dict(size=34)) # Размер шрифта подписей оси Ox
fig.update_yaxes(tickfont=dict(size=34)) # Размер шрифта подписей оси Oy
# Настраиваем масштаб текста
fig.update_layout(
legend=dict(
font=dict(size=42)
, yanchor='top'
, xanchor='center'
, x = 0.9
, title=dict(
text='Группа', # Текст названия легенды
font=dict(
family='Arial', # Шрифт
size=36, # Размер шрифта названия легенды
color='black' # Цвет шрифта
)
)
),
xaxis=dict(
title='Покупки', # Название оси Ox
titlefont=dict(
family='Arial', # Шрифт
size=44, # Размер шрифта
color='black' # Цвет шрифта
)
),
yaxis=dict(
title='Число пользователей', # Название оси Oy
titlefont=dict(
family='Arial', # Шрифт
size=44, # Размер шрифта
color='black' # Цвет шрифта
)) # Размер шрифта легенды
)
fig.update_layout(plot_bgcolor = 'white')
fig.update_xaxes(range = [-0.6, 6.6]) # Для удобной визуальной интерпретации
#QQ-plot
#data - данные в виде одномерного массива или серии чисел
# Подготовка данных
data = df_light_t.sum_utilizations
# Построение QQ-plot с учетом параметров среднего и стандартного отклонения выборки
fig = plt.figure()
ax = fig.add_subplot(111)
res = stats.probplot(data, dist="norm", sparams=(np.mean(data), np.std(data)), plot=ax)
# Настройка стиля
ax.get_lines()[1].set_linestyle('--') # Теоретическая линия - пунктирная
ax.get_lines()[1].set_color('black') # Теоретическая линия - черная
ax.get_lines()[0].set_marker('o') # Точки - окружности
ax.get_lines()[0].set_color('black') # Точки - черные
# Настройка фона
fig.patch.set_facecolor('white') # Белый фон для всей фигуры
ax.set_facecolor('white') # Белый фон для области построения
plt.title('QQ-plot')
plt.xlabel('Theoretical Quantiles')
plt.ylabel('Sample Quantiles')
plt.grid(True)
plt.show()
Квантиль-квантиль график имеет вид, схожий с теоретическим при «скошенных влево» распределениях. «Долгие» горизонтальные линии со значением «0» хорошо демонстрируют смещение распределения влево. Посмотрим статистики: тест Шапиро-Уилка, Андерсона-Дарлинга и общий тест Колмогорова-Смирнова.
Статистики в соответствующих группах теста и контроля (тест нормальности):
Группа теста |
Группа контроля |
|
Среднее значение |
0.97706 |
0.97652 |
Дисперсия |
12.625 |
7.995 |
Shapiro-Wilk statistic |
0.2214 |
0.3518 |
Anderson-Darling statistic |
3539477.3 |
3246371.1 |
Kolmogorov-Smirnov statistic |
0.3916 |
0.3649 |
Код реализации расчета статистик
from scipy.stats import shapiro
from scipy.stats import anderson
from scipy.stats import kstest
import numpy as np
# Данные
# data_t - данные в виде одномерного массива или серии чисел тестовой группы
# data_c - данные в виде одномерного массива или серии чисел группы контроля
# Параметры распределения
print('Среднее, ст.откл. и дисперсия для теста: ',np.mean(data_t), np.std(data_t), data_t.var())
print('Среднее, ст.откл. и дисперсия для контроля: ',np.mean(data_c), np.std(data_c), data_c.var())
# Проведение теста Шапиро-Уилка
stat_sh_t, p_value_sh_t = shapiro(data_t)
stat_sh_c, p_value_sh_c = shapiro(data_c)
print(f"Shapiro-Wilk test statistic: {stat_sh_t}, p-value: {p_value_sh_t}")
print(f"Shapiro-Wilk control statistic: {stat_sh_c}, p-value: {p_value_sh_c}")
# Интерпретация результата
alpha = 0.05
if p_value_sh_t > alpha:
print("Данные нормально распределены (не отвергаем H0)")
else:
print("Данные не нормально распределены (отвергаем H0)")
if p_value_sh_c > alpha:
print("Данные нормально распределены (не отвергаем H0)")
else:
print("Данные не нормально распределены (отвергаем H0)")
# Проведение теста Андерсона-Дарлинга. По умолчанию использует среднее и ст.откл нашей выборки.
result_t = anderson(data_t, dist='norm')
result_c = anderson(data_c, dist='norm')
print(f"Anderson-Darling test statistic: {result_t.statistic}")
print(f"Anderson-Darling control statistic: {result_c.statistic}")
for i in range(len(result_t.critical_values)):
sl, cv = result_t.significance_level[i], result_t.critical_values[i]
if result_t.statistic < cv:
print(f"На уровне значимости {sl}% данные нормально распределены (не отвергаем H0)")
else:
print(f"На уровне значимости {sl}% данные не нормально распределены (отвергаем H0)")
for i in range(len(result_c.critical_values)):
sl, cv = result_c.significance_level[i], result_c.critical_values[i]
if result_c.statistic < cv:
print(f"На уровне значимости {sl}% данные нормально распределены (не отвергаем H0)")
else:
print(f"На уровне значимости {sl}% данные не нормально распределены (отвергаем H0)")
# Проведение теста Колмогорова-Смирнова. Частный случай: сравниваем с нормальным распределением.
stat_ks_t, p_value_ks_t = kstest(data_t, 'norm', args=(np.mean(data_t), np.std(data_t))) # Передаем параметры нормального распределения, такие как среднее и стандартное отклонение, соответствующие данным. (нормальное распределение задается двумя параметрами!)
stat_ks_c, p_value_ks_c = kstest(data_c, 'norm', args=(np.mean(data_c), np.std(data_c)))
print(f"Kolmogorov-Smirnov test statistic: {stat_ks_t}, p-value: {p_value_ks_t}")
print(f"Kolmogorov-Smirnov control statistic: {stat_ks_c}, p-value: {p_value_ks_c}")
# Интерпретация результата
alpha = 0.05
if p_value_ks_t > alpha:
print("Данные нормально распределены (не отвергаем H0)")
else:
print("Данные не нормально распределены (отвергаем H0)")
if p_value_ks_c > alpha:
print("Данные нормально распределены (не отвергаем H0)")
else:
print("Данные не нормально распределены (отвергаем H0)")
Критерий Shapiro-Wilk подходит для небольших выборок N < 5000 и очень чувствителен. В нашем случае он приведен для примера расчета и не используется при заключении выводов). В каждом из случаев мы отвергаем H0 гипотезу о равенстве распределений, что подтверждается и графическим методом выше.
Сравнение дисперсий (тест гомоскедастичности). Критерий Левена для ненормально распределенных данных (наш случай) и критерий Бартлета - для нормальных распределений (приведем для примера расчета). Statistic Leven: 0.07522527250797496, p-value: 0.7838754046799008 (H0 - не отвергается, дисперсии не отличаются значимо). А вот Statistic Bartlet: 911881.6568784608 с p-value стремящемся к 0 (но данную статистику применять нельзя).
Код реализации расчета статистик (Левена и Бартлета)
import numpy as np
from scipy import stats
# Данные
# data_t - данные в виде одномерного массива или серии чисел тестовой группы
# data_c - данные в виде одномерного массива или серии чисел группы контроля
# Проверка на равенство дисперсий (критерий Левена и Бартлета)
stat_leven, p_value_leven = stats.levene(data1, data2, center='trimmed') # median, mean - выбор может сильно влиять на статистику!
stat_bartlet, p_value_bartlet = stats.bartlett(data1, data2)
print(f"Statistic Leven: {stat_leven}, p-value: {p_value_leven}")
print(f"Statistic Bartlet: {stat_bartlet}, p-value: {p_value_bartlet}") # в случае нормального распределения
Сравнение ratio-метрики. Дисперсии не отличаются, поэтому используем t-тест Стьюдента. Но для сравнения приведем результаты обеих статистик (t-критерий Стьюдента и Уэлча).
Статистики в соответствующих группах теста и контроля (t-тест):
Отличия (в случае равенства дисперсий) действительно небольшие: в значении статистики и p-value только в 5 знаке после запятой. Таким образом, между группами теста и контроля нет статзначимой разницы (H0 - не отвергается), но какой тогда бизнес-вывод?
Интерпретация результатов:
Конверсия уникальных пользователей в обращение на линию с отказом хотя бы от одного маркетингового канала.
MDE (минимально детектируемый лифт): 5.08 %;
DOWN LIFT: 5.08 %;
P_VALUE = 0.0008875 < α/n = 0.01;Среднее число отказов на клиента.
MDE (абсолютная разница в значении метрики): 0.0000318;
DELTA: 0.0000310;
P_VALUE = 0.000939 < α/n = 0.01;Ср. знач. оформления легких продуктов, ед.
MDE: 0.0052 - абсолютная разница в значении метрики (двусторонний t-тест);
DELTA: 0.000597;
P_VALUE = 0.6765 > α/n = 0.01;Ср. знач. оформления тяжелых продуктов, ед.
MDE: 0.00053 - абсолютная разница в значении метрики (двусторонний t-тест);
DELTA: 0.000191;
P_VALUE = 0.1548 > α/n = 0.01;Ср. изменение числа активных продуктов на пользователе, ед.
MDE: 0.00071 - абсолютная разница в значении метрики (двусторонний t-тест);
DELTA: 0.000188;
P_VALUE = 0.325 > α/n = 0.01.
Динамики соответствующих метрик, и динамики значений p-values для метрик негатива - в логарифмической шкале:
![](https://habrastorage.org/getpro/habr/upload_files/71c/255/9d0/71c2559d0aa84d58f9dbb863273a2d0d.png)
![](https://habrastorage.org/getpro/habr/upload_files/8a4/dc2/e40/8a4dc2e404f65fbf62b6a7ebcb55ed82.png)
![Динамика показателей метрик со временем, а также значений p-value Динамика показателей метрик со временем, а также значений p-value](https://habrastorage.org/getpro/habr/upload_files/057/bd2/66d/057bd266d814ed42da41b12cb496fb24.png)
Для метрики1 и метрики2 (метрики негатива) мы получили статистически значимый результат в уменьшении числа пользователей, отказавшихся от маркетинга и уменьшении уникального числа отказов.
Для контр.метрик мы не смогли зафиксировать статистически значимых отличий в группах или если формировать бизнес-вывод: «Влияния на бизнес-метрики обнаружить не удалось, технически - мы не знаем, есть ли эффект, но если он есть, то он вероятно ниже MDE». Также мы можем дополнить вывод: «Различий на уровне выше MDE нет, с вероятностью 80% (мощность теста)». Также стоит отметить, что требование преодоления расчетного MDE не является обязательным критерием и приводит к искуственному повышению уровня требований к значимости теста.
Заключение
Основные результаты нашего теста: за месяц мы снизили число обращений с отказом на 2,76%. Мы ограничивали рекламные уведомления на 2.0% пользователей, на которых за время теста приходилось 6,71% от всех рекламных коммуникаций. Фактически мы снизили отправки только на 1,81% за счет ежедневной проверки возможности отправить рекламу клиенту. Все это на фоне отсутствия значимого влияния на бизнес-показатели с учетом низкого абсолютного значения MDE.
Пользователи сохраняют продуктовую активность при «умном снижении» рекламных рассылок и часть оформлений продуктов переходит в естественные каналы привлечения. Такая стратегия помогает экономить на платных каналах привлечения: зачем отправлять смс или звонить клиенту, который не только не захочет предлагаемый продукт, но и в целом откажется от вашей рекламы?
При этом отказ от рекламы — вершина айсберга, снижая явный негатив, мы в действительности улучшаем маркетинговую стратегию для гораздо большего числа пользователей. Для оценки полного масштаба положительного эффекта хорошо использовать составные показатели, такие как: PNL (profit and loss) или LTV (life-time value), но так как показатель LTV составной, модели расчета LTV должны быть чувствительны к признаку отказа от маркетинга.
Важнейшей параллельной задачей с точки зрения unit-экономики любого маркетингового а/б-теста является оценка стоимости недополученной прибыли при отказе пользователя от маркетинга, о которой мы поговорим в следующей статье, до встречи!
Полезные ссылки:
Две основные методологии проведения ab-тестирования
Функции TTestIndPower и proportion_effectsize