Ответ
Чтобы оценить неопределённость в оценке конверсии (например, доля кликнувших) и разницы между группами, мы используем либо аналитические распределения, либо бутстреп. Это позволяет строить доверительные интервалы и визуализировать overlap.
1. Бета-распределение (Аналитический подход)
Если в группе было k конверсий из n пользователей, то апостериорное распределение конверсии p (при uniform prior) описывается Бета-распределением: Beta(α = k + 1, β = n - k + 1). Это стандартный байесовский подход.
import numpy as np
from scipy.stats import beta
import matplotlib.pyplot as plt
# Данные теста: группа A
conversions_A, visitors_A = 120, 1000
conversions_B, visitors_B = 150, 1000
# Параметры бета-распределений
alpha_A, beta_A = conversions_A + 1, visitors_A - conversions_A + 1
alpha_B, beta_B = conversions_B + 1, visitors_B - conversions_B + 1
# Генерация выборок из распределений
dist_A = beta(alpha_A, beta_A)
dist_B = beta(alpha_B, beta_B)
samples_A = dist_A.rvs(10000)
samples_B = dist_B.rvs(10000)
# Разница в конверсии
diff_samples = samples_B - samples_A
prob_B_better = (diff_samples > 0).mean()
print(f"Вероятность, что группа B лучше: {prob_B_better:.2%}")
# Визуализация
plt.hist(samples_A, bins=50, alpha=0.5, label='Group A', density=True)
plt.hist(samples_B, bins=50, alpha=0.5, label='Group B', density=True)
plt.legend()
plt.xlabel('Conversion Rate')
plt.show()
2. Бутстреп (Непараметрический подход) Полезен, когда предположения аналитической модели сомнительны, или для более сложных метрик (например, средний чек).
def bootstrap_mean(data, n_bootstrap=10000):
"""data - бинарный массив (0/1)."""
boot_means = []
n = len(data)
for _ in range(n_bootstrap):
sample = np.random.choice(data, size=n, replace=True)
boot_means.append(sample.mean())
return np.array(boot_means)
# Пример с реальными данными (бинарные клики)
clicks_A = np.array([1,0,0,1, ...]) # массив длины visitors_A
boot_means_A = bootstrap_mean(clicks_A)
# 95% доверительный интервал через процентили
ci_lower, ci_upper = np.percentile(boot_means_A, [2.5, 97.5])
Выбор метода:
- Бета-распределение — быстрее, элегантнее, стандарт для бинарных конверсий.
- Бутстреп — более универсален, не делает предположений о форме распределения, но требует больше вычислений.
Ответ 18+ 🔞
Давай разберём эту тему, а то я вижу, у многих тут в головах каша, как будто они не статистику изучали, а хуй с горой.
Вот представь: у тебя есть две версии сайта. На одной конверсия 12%, на другой 15%. И ты такой сидишь и думаешь: «Ёпта, это реальный прирост или просто так, случайно, повезло?» Вот чтобы не гадать на кофейной гуще, как последний распиздяй, есть два рабочих подхода. Один — красивый и математический, второй — тупой, как валенок, но безотказный.
1. Бета-распределение (Красиво и по науке)
Если в группе А было k конверсий из n юзеров, то наше представление о её истинной конверсии p — это Бета-распределение: Beta(α = k + 1, β = n - k + 1). Это не я придумал, это байесовская статистика, ей-богу. Берём, генерируем из этих распределений кучу возможных значений конверсии и смотрим, насколько они накладываются друг на друга.
import numpy as np
from scipy.stats import beta
import matplotlib.pyplot as plt
# Данные теста
conversions_A, visitors_A = 120, 1000
conversions_B, visitors_B = 150, 1000
# Параметры для наших бет
alpha_A, beta_A = conversions_A + 1, visitors_A - conversions_A + 1
alpha_B, beta_B = conversions_B + 1, visitors_B - conversions_B + 1
# Генерируем возможные сценарии
dist_A = beta(alpha_A, beta_A)
dist_B = beta(alpha_B, beta_B)
samples_A = dist_A.rvs(10000) # 10 тысяч возможных конверсий для А
samples_B = dist_B.rvs(10000) # 10 тысяч возможных конверсий для Б
# Считаем разницу
diff_samples = samples_B - samples_A
prob_B_better = (diff_samples > 0).mean()
print(f"Вероятность, что группа B лучше: {prob_B_better:.2%}")
# Картинку для начальства
plt.hist(samples_A, bins=50, alpha=0.5, label='Group A', density=True)
plt.hist(samples_B, bins=50, alpha=0.5, label='Group B', density=True)
plt.legend()
plt.xlabel('Conversion Rate')
plt.show()
Смотришь на вероятность prob_B_better. Если она под 95% — можно уже расслабиться и начинать бздеть от радости. Если около 50% — это полная хуйня, разницы никакой.
2. Бутстреп (Тупой, но мощный) А что, если метрика у тебя не конверсия, а, например, средний чек? Или там распределение какое-то пиздопроебибное, не похожее ни на что нормальное? Вот тут на сцену выходит бутстреп. Суть проще пареной репы: берём наши сырые данные и начинаем из них с возвращением тырить куски, строить новые выборки и считать на них нашу метрику. Повторяем это овердохуища раз. Получаем эмпирическое распределение — вот тебе и неопределённость.
def bootstrap_mean(data, n_bootstrap=10000):
"""data - бинарный массив (0/1)."""
boot_means = []
n = len(data)
for _ in range(n_bootstrap):
sample = np.random.choice(data, size=n, replace=True) # Вот он, главный трюк!
boot_means.append(sample.mean())
return np.array(boot_means)
# Допустим, у тебя массив кликов
clicks_A = np.array([1,0,0,1, ...]) # 1 - конверсия, 0 - мимо
boot_means_A = bootstrap_mean(clicks_A)
# 95% доверительный интервал через процентили
ci_lower, ci_upper = np.percentile(boot_means_A, [2.5, 97.5])
Так что же выбрать, ёпта?
- Бета-распределение — это как швейцарские часы. Быстро, элегантно, специально заточено под бинарные исходы (конверсия/не конверсия). Если условия подходят — юзай его и не выёбывайся.
- Бутстреп — это как кувалда. Универсальная, грубая, но прошибёт любую, даже самую хитрожопую метрику. Вычислительно тяжёлая, зато никаких допущений о нормальности. Когда сомневаешься — бутстреп в руки.
Вот и вся магия. Главное — не делай выводы, глядя только на разницу в процентах. Посмотри на overlap, на вероятность, на интервалы. А то будет тебе хиросима, а не успешный A/B-тест.