Попап сработал. Но какой ценой?
// Условие
Тест агрессивного попапа подписки на рассылку: контроль A — без попапа, тест B — попап на входе. Целевая метрика — конверсия в подписку. Но у теста есть guardrail-метрика — конверсия в покупку: попап не должен мешать покупать.
result — dict с ключами diff_sub, p_value_sub, diff_purchase, p_value_purchase (diff — в долях, B минус A).// Данные
user_id, group (A/B), subscribed (0/1), purchased (0/1)// Решение
Подсказка
Считай каждую метрику независимо тем же z-тестом двух долей: сначала по subscribed, потом по purchased.
Удобно завести функцию ab_test(df, metric_col), возвращающую (diff, p_value), и вызвать её дважды.
Смотри на знак diff_purchase: подписки выросли, а покупки?
Сначала попробуй сам → Показать решение
df = load_data()
from scipy import stats
def ab_test(df, col):
s = df.groupby('group')[col].agg(['sum', 'count'])
pa = s.loc['A', 'sum'] / s.loc['A', 'count']
pb = s.loc['B', 'sum'] / s.loc['B', 'count']
p_pool = df[col].mean()
se = (p_pool * (1 - p_pool) * (1 / s.loc['A', 'count'] + 1 / s.loc['B', 'count'])) ** 0.5
z = (pb - pa) / se
return pb - pa, 2 * (1 - stats.norm.cdf(abs(z)))
diff_sub, p_sub = ab_test(df, 'subscribed')
diff_pur, p_pur = ab_test(df, 'purchased')
result = {'diff_sub': diff_sub, 'p_value_sub': p_sub,
'diff_purchase': diff_pur, 'p_value_purchase': p_pur}
print(result)
Целевая метрика выросла. Раскатываем попап?
Тест «успешен» только если смотреть на одну метрику. Попап купил +200 подписчиков ценой −200 покупателей (на 20 000 юзеров). Решение — экономика: LTV подписки против маржи покупки, и почти наверняка выгоднее менее агрессивный формат (после покупки, по скроллу). «Показать только новым» — новая гипотеза, её тоже тестировать. Вывод про «рассылки не нужны» из этих данных не следует вовсе.