Как работать с Ratio-метриками – Delta-method
В посте с видами метрик в A/B-тестах я рассказал о трех видах метрик: долях, непрерывных и метриках отношения (ratio-метриках).
Больше всего интереса вызывает именно последний вид, поскольку к ratio-метрикам нельзя просто взять и применить привычные стат. критерии.
Проблема заключается в том, что в ratio-метриках числитель (num) и знаменатель (denom) зависимы. А тот же t-test, как и многие другие тесты, предполагают независимость данных. Как итог – мы неправильно оцениваем дисперсию метрики.
Один из вариантов решения проблемы – применение delta-method’а. Суть метода проста. В нем мы корректируем нашу дисперсию на корреляцию. Для это нам понадобится следующая функция оценки дисперсии:
def est_ratio_var(num, denom):
mean_num, mean_denom = np.mean(num), np.mean(denom) var_num, var_denom = np.var(num), np.var(denom)
cov = np.cov(num, denom)[0, 1]
ratio_var = ( (var_num / mean_denom ** 2) (2 * (mean_num / mean_denom ** 3) * cov) + ((mean_num 2 / mean_denom 4) * var_denom) )
return ratio_var
Рассмотрим работу метода на примере метрики CTR. Т. е. у нас будут колонки 'clicks' и 'views' на каждого user_id. Тогда можно выделить 2 ключевых момента работы с ней:
1. Расчет размера выборки.
В коде ниже, rel_mde – относительный MDE, cohen_d – стандартизированный MDE. Пользователей делим 90 на 10.
rel_mde = 0.1
var = est_ratio_var(df['clicks'], df['views']) control_std = var**0.5
control_mean = df['clicks'].sum() / df['views'].sum() test_mean = control_mean * (1 + rel_mde)
cohen_d = (test_mean - control_mean) / control_std
n1 = tt_ind_solve_power( effect_size=cohen_d, alpha=0.05, power=0.8, ratio=9, # n2/n1 alternative="two-sided" )
print(f"Размер выборки delta-method: " f"n1 = {round(n1)}, " f"n2 = {round(9 * n1)}" )
2. Оценка статистической значимости изменений:
def delta_method(group_A, group_B):
ratio_A = group_A['clicks'].sum() / group_A['views'].sum() ratio_B = group_B['clicks'].sum() / group_B['views'].sum()
var_A = est_ratio_var(group_A['clicks'], group_A['views']) var_B = est_ratio_var(group_B['clicks'], group_B['views'])
uplift = ratio_B - ratio_A se = np.sqrt(var_B / len(group_B) + var_A / len(group_A))
t = uplift / se p_val = (1 - stats.norm.cdf(abs(t))) * 2
return p_val
Я нахожу Delta-method самым простым в интерпретации для бизнеса. Но существуют и другие методы работы с ratio-метриками – линеризация, бутстреп, бакетизация. Все они имеют свои плюсы и минусы, а также нюансы применения.
Хочешь глубже разобраться в аналитике?
Посмотри программу курса по продуктовой аналитике и экспериментам.