Разницы не нашли: как проверить практическую эквивалентность вариантов
Команда хочет заменить дорогой способ обработки более дешёвым. В тесте среднее время выполнения почти одинаковое, p-value обычной проверки равно 0,4. Возникает соблазн сказать: варианты равны, можно переключаться. Но отсутствие найденной разницы бывает и при слишком маленькой выборке. Для решения нужен другой вопрос: достаточно ли точны данные, чтобы исключить ухудшение, которое бизнес считает существенным?
Сначала назвать допустимое различие
Пусть сравниваем среднее время в секундах, B минус A. До запуска согласовали границы от минус одной до плюс одной секунды: различия внутри этого диапазона практически приемлемы для обеих сторон. Границы должны опираться на требования пользователя, стоимость или процесс. Подбирать их после просмотра интервала означает объявить допустимым уже полученный результат, а не проверить заранее сформулированное решение.
Если интересует только отсутствие ухудшения, задача обычно односторонняя — не меньшая эффективность с соответствующей границей. Практическая эквивалентность задаёт две границы и исключает как существенное ухудшение, так и существенное улучшение по выбранной метрике. Это полезно, когда нужна взаимозаменяемость процесса в согласованном смысле. Для остальных метрик, например доли ошибок, требования проверяются отдельно.
Два односторонних теста вместо одного вопроса о нуле
Процедура TOST проверяет две гипотезы: эффект не выше нижней границы и эффект не ниже верхней. Эквивалентность признаётся, когда обе отвергнуты на уровне 0,05. Для соответствующего непрерывного t-подхода это равносильно тому, что двусторонний 90-процентный доверительный интервал целиком находится внутри согласованного диапазона. Обычный 95-процентный интервал отвечает другому вопросу; смешивать уровни между расчётом и объяснением нельзя.
В примере используем две независимые выборки по 200 наблюдений. Разница средних — 0,1 секунды, а данные достаточно точны, чтобы интервал поместился внутри ±1. В statsmodels аргументы передаём в порядке B, A, чтобы знак результата совпадал с формулировкой. usevar="unequal" выбирает вариант с неравными дисперсиями. Для каждой группы нужна независимость наблюдений на единице назначения.
import numpy as np
from statsmodels.stats.weightstats import ttost_ind, DescrStatsW, CompareMeans
base = np.tile(np.array([-2.,-1.,0.,1.,2.]),40)
A = 10 + base
B = 10.1 + base[::-1]
low, high = -1.0, 1.0
pvalue, lower_test, upper_test = ttost_ind(B,A,low,high,usevar='unequal')
ci = CompareMeans(DescrStatsW(B),DescrStatsW(A)).tconfint_diff(alpha=0.10,usevar='unequal')
equivalent = pvalue < 0.05
print({'difference':round(float(B.mean()-A.mean()),3),
'ci90':tuple(round(float(x),3) for x in ci),
'tost_pvalue':round(float(pvalue),6), 'equivalent':bool(equivalent)})
assert low < ci[0] < ci[1] < high
assert equivalentОтличить три возможных вывода
Интервал целиком внутри границ поддерживает эквивалентность в пределах выбранного допуска. Интервал выходит за одну из границ — данных для такого вывода недостаточно, даже если он содержит ноль. Наконец, интервал может лежать внутри допуска и при этом не содержать ноль: статистически заметная разница остаётся практически небольшой. Поэтому «есть разница» и «разница достаточно мала» не являются взаимоисключающими фразами.
Для долей, отношений и связанных измерений нужен соответствующий метод эквивалентности; готовую процедуру для независимых средних нельзя просто перенести на проценты из двух агрегатов. Если время сильно асимметрично, заранее обсудите, подходит ли среднее или важнее хвост распределения. Выбор метрики должен отражать качество услуги: одинаковое среднее может соседствовать с разным числом очень долгих запросов.
Записать решение в единицах бизнеса
Итог формулируется конкретно: по среднему времени различие укладывается в согласованный допуск одной секунды на выбранном уровне проверки; новый способ дешевле по отдельному расчёту. Укажите сами границы, интервал и размер выборки. Для внедрения добавьте заранее выбранные ограничения на ошибки и редкие задержки. Тогда команда переключает процесс потому, что проверила допустимую потерю качества, а не потому, что обычный тест не заметил различия.
Продолжить работу с данными
Для подготовки такого эксперимента нужны понятная гипотеза и заранее выбранная точность. В «A/B тесты и анализ данных на Python» вы отработаете дизайн теста, размер выборки, доверительные интервалы и ошибки статистических решений. Эти навыки помогут связать расчёт с допуском, который согласовала продуктовая команда. Откройте программу платного курса «A/B тесты и анализ данных на Python».
Продолжить на практике
- A/B тесты и анализ данных на Python ↗
Практический курс по A/B-тестированию и продуктовым метрикам: формулируем гипотезы, считаем размер выборки, запускаем эксперименты и анализируем результаты. От первой идеи до внедрения изменений в продукт — без «воды» и лишней теории.
