Что такое ratio metrics и как их правильно анализировать в A/B тестах?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ratio Metrics в A/B тестах: определение и анализ
Ratio metrics (метрики-отношения) — это метрики, рассчитываемые как отношение одного значения к другому. Например: средний чек, CTR (Click-Through Rate), конверсия, ARPU. Они основаны на делении числителя на знаменатель и требуют специального подхода при анализе в A/B тестах, так как обладают нелинейным распределением.
Типы ratio metrics
Простые отношения:
- Конверсия (conversions / sessions)
- CTR (clicks / impressions)
- ARPU (revenue / users)
- Средний чек (total_revenue / orders)
Составные отношения:
- Revenue per session = total_revenue / sessions
- LTV / CAC (lifetime value / customer acquisition cost)
- Engagement rate = active_users / total_users
Почему ratio metrics опасны в A/B тестах
Проблема 1: Ненормальное распределение
Обычные метрики (количество кликов) имеют нормальное распределение при большом размере выборки (CLT). Ratio metrics нарушают это предположение.
Конверсия = 320 / 10000 = 0.032 (3.2%)
Среднее значение может быть 3.2%, но распределение НЕ нормально!
Это распределение, ограниченное интервалом [0, 1] для конверсии.
Проблема 2: Различные вариансы при одинаковых значениях
Вариант A: 1000 заказов из 100000 посещений = 1.0% конверсия
Вариант B: 100 заказов из 10000 посещений = 1.0% конверсия
Дисперсия разная! Вариант B более волатилен.
Проблема 3: Корреляция числителя и знаменателя
Если числитель и знаменатель коррелированы, стандартная ошибка занижается.
Методы анализа ratio metrics
Метод 1: Дельта-метод (Delta Method) — классический подход
Использует разложение Тейлора для аппроксимации дисперсии отношения.
Для ratio X/Y:
Var(X/Y) ≈ (1/μ_Y)² * Var(X) + (μ_X/μ_Y²)² * Var(Y) - 2*(μ_X/μ_Y³) * Cov(X,Y)
Когда использовать: когда числитель и знаменатель независимы и распределения близки к нормальным.
Пример в Python:
import numpy as np
from scipy import stats
# Данные варианта A
conversions_a = np.array([1, 0, 1, 0, 1, ...]) # 1 = конверсия
sessions_a = len(conversions_a) # 10000
# Данные варианта B
conversions_b = np.array([1, 1, 0, 1, ...])
sessions_b = len(conversions_b) # 10000
# Конверсии
conv_a = conversions_a.sum() / sessions_a
conv_b = conversions_b.sum() / sessions_b
# Дисперсия конверсии (Bernoulli)
var_a = conv_a * (1 - conv_a) / sessions_a
var_b = conv_b * (1 - conv_b) / sessions_b
# Стандартная ошибка разницы
se_diff = np.sqrt(var_a + var_b)
# t-статистика
t_stat = (conv_a - conv_b) / se_diff
p_value = 2 * (1 - stats.t.cdf(abs(t_stat), df=sessions_a + sessions_b - 2))
Метод 2: Bootstrap (Бутстрэп) — универсальный подход
Пересэмплирование из исходных данных для получения эмпирического распределения ratio.
def bootstrap_ratio_ci(data_a, data_b, n_iterations=10000, ci=0.95):
"""
Вычисляет доверительный интервал для разницы ratio метрик
data_a, data_b: массивы вида [numbers, totals]
"""
ratios_diff = []
for _ in range(n_iterations):
# Случайная выборка с возвращением
sample_a = np.random.choice(len(data_a), size=len(data_a), replace=True)
sample_b = np.random.choice(len(data_b), size=len(data_b), replace=True)
ratio_a = data_a[sample_a].sum() / len(sample_a)
ratio_b = data_b[sample_b].sum() / len(sample_b)
ratios_diff.append(ratio_a - ratio_b)
# Доверительный интервал
lower = np.percentile(ratios_diff, (1 - ci) / 2 * 100)
upper = np.percentile(ratios_diff, (1 + ci) / 2 * 100)
return lower, upper
# Использование
ci_lower, ci_upper = bootstrap_ratio_ci(conversions_a, conversions_b)
print(f"95% CI: [{ci_lower:.4f}, {ci_upper:.4f}]")
Когда использовать: всегда, когда есть сомнения в предположениях дельта-метода. Bootstrap работает для любого распределения.
Метод 3: Линеаризация (Linearization) — для ARPU и сложных метрик
Преобразуем ratio метрику в линейную комбинацию.
ARPU = Revenue / Users
Для каждого пользователя i:
arpu_i = revenue_i / users
Преобразуем:
arpu_i ≈ (revenue_i - μ_revenue/μ_users * users_i) / μ_users
Теперь это линейная комбинация — можно использовать t-тест!
Пример для ARPU:
-- Расчёт ARPU по пользователю
WITH user_stats AS (
SELECT
user_id,
SUM(purchase_amount) as total_revenue,
COUNT(DISTINCT session_id) as sessions,
@global_mean_revenue / @global_mean_sessions as arpu_ratio
FROM transactions
WHERE variant IN ('A', 'B')
GROUP BY user_id
)
SELECT
variant,
AVG(total_revenue - arpu_ratio * sessions) as linearized_arpu,
STDDEV(total_revenue - arpu_ratio * sessions) / SQRT(COUNT(*)) as se
FROM user_stats
GROUP BY variant;
Правильный анализ в SQL
-- Данные для A/B теста на ratio metrics
WITH variant_data AS (
SELECT
variant,
COUNT(DISTINCT user_id) as users,
COUNT(CASE WHEN purchase_made = 1 THEN 1 END) as purchases,
SUM(revenue) as total_revenue,
COUNT(CASE WHEN purchase_made = 1 THEN 1 END)::FLOAT /
COUNT(DISTINCT user_id) as conversion_rate,
SUM(revenue)::FLOAT / COUNT(DISTINCT user_id) as arpu
FROM events
WHERE test_id = @test_id
GROUP BY variant
),
variance_calc AS (
SELECT
variant,
users,
purchases,
conversion_rate,
arpu,
-- Дисперсия конверсии (Bernoulli)
conversion_rate * (1 - conversion_rate) / users as conv_variance,
-- Дисперсия ARPU
variance(revenue) / users as arpu_variance
FROM variant_data
)
SELECT
*,
-- Стандартная ошибка
SQRT(2 * conv_variance) as conv_se,
SQRT(2 * arpu_variance) as arpu_se
FROM variance_calc;
Критические ошибки при анализе ratio metrics
❌ Ошибка 1: Использовать обычный t-тест на конверсию
Конверсия имеет биномиальное распределение, не нормальное. Нужен точный Fisher test или chi-square.
-- Неправильно
SELECT
conversion_a,
conversion_b,
(conversion_a - conversion_b) / SQRT(var_a + var_b) as t_stat;
-- Правильно
-- Использовать chi-square для таблицы сопряженности 2x2
❌ Ошибка 2: Игнорировать корреляцию числителя и знаменателя
Если числитель и знаменатель сильно коррелированы, стандартная ошибка будет занижена, и you получите ложные положительные результаты.
❌ Ошибка 3: Анализировать ratio до достижения minimum sample size
Для ratio metrics нужен БОЛЬШИЙ размер выборки, чем для обычных метрик, потому что дисперсия выше.
# Минимальный размер выборки для ratio metrics примерно в 1.5-2 раза больше
# чем для обычных метрик с тем же эффектом
min_sample_size_ratio = min_sample_size_linear * 1.5
❌ Ошибка 4: Анализировать ratio в наивной стратификации
Если у вас есть стратификация по устройству, странам и т.д., нужно анализировать ratio для каждой страты отдельно или использовать CUPED/CUPAC.
Best practices для Product Analysts
1. Используйте инструменты, которые "знают" о ratio metrics
- Statsig, Split.io, LaunchDarkly — встроенная поддержка
- Mixpanel, Amplitude — встроенная статистика
- Python: statsmodels, scipy, bootstrapped
2. Визуализируйте распределение, не только среднее
import matplotlib.pyplot as plt
plt.hist([ratio_a], bins=50, alpha=0.5, label='Variant A')
plt.hist([ratio_b], bins=50, alpha=0.5, label='Variant B')
plt.xlabel('Конверсия')
plt.legend()
plt.show()
# Убедитесь, что хвосты не слишком тяжелые
# и нет экстремальных выбросов
3. Предоставляйте отчет в формате:
- Точечная оценка разницы
- 95% доверительный интервал
- Относительный эффект (%)
- P-value
- Статистическая мощность (1 - β)
- Размер выборки
VARIANT A: Conversion 3.2% [3.0% - 3.4%]
VARIANT B: Conversion 3.5% [3.3% - 3.7%]
Difference: +0.3% (+9.4% relative lift)
95% CI: [0.1%, 0.5%]
p-value: 0.012 ✓ (significant at α=0.05)
Power: 88%
n_a = 50000, n_b = 50000
Итог
Ratio metrics требуют более аккуратного анализа, чем обычные метрики. Главное правило: используйте bootstrap или дельта-метод вместо наивного t-теста. Для ARPU и сложных ratio используйте линеаризацию. И всегда проверяйте предположения дельта-метода перед его применением. В современных A/B тестирования инструментах эти методы уже встроены, но Product Analyst должен понимать, что происходит под капотом.