Что такое effect size и почему он важен наряду с p-value?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Effect Size и его роль наряду с P-Value
P-value и effect size — это два разных измерения, которые часто путают. P-value говорит "есть ли эффект", effect size говорит "насколько большой эффект". Понимание обоих критически важно для правильных выводов.
Что такое P-Value
P-value — вероятность увидеть такой результат (или более экстремальный), если нулевая гипотеза верна (нет эффекта).
- P-value = 0.05: 5% вероятность ошибки типа I
- Принимается условно (p < 0.05 = статистически значимо)
- Проблема: зависит от размера выборки
Пример: Конверсия подскочила с 5.0% на 5.1%, n=1,000,000. Это даст p < 0.05, но эффект бесполезен!
Что такое Effect Size
Effect size — величина практического различия между группами. Это измерение абсолютно независимо от размера выборки.
Главная идея: Статистическая значимость ≠ Практическая значимость
Типы effect size:
1. Cohen's d (для непрерывных данных, например средний spending)
import numpy as np
from scipy.stats import ttest_ind
def cohens_d(group1, group2):
"""Рассчитывает Cohen's d effect size"""
n1, n2 = len(group1), len(group2)
var1, var2 = np.var(group1, ddof=1), np.var(group2, ddof=1)
# Pooled standard deviation
pooled_std = np.sqrt(((n1 - 1) * var1 + (n2 - 1) * var2) / (n1 + n2 - 2))
# Cohen's d
d = (np.mean(group1) - np.mean(group2)) / pooled_std
return d
# Пример
control_spending = np.array([50, 55, 48, 60, 52, 49, 51])
variant_spending = np.array([58, 62, 55, 65, 60, 57, 59])
d = cohens_d(control_spending, variant_spending)
print(f"Cohen's d = {d:.3f}")
# Интерпретация Cohen's d:
# |d| < 0.2: маленький эффект
# 0.2 ≤ |d| < 0.5: малый эффект
# 0.5 ≤ |d| < 0.8: средний эффект
# |d| ≥ 0.8: большой эффект
2. Odds Ratio (для бинарных данных, конверсия, retention)
def odds_ratio(conversions_treatment, total_treatment,
conversions_control, total_control):
"""Рассчитывает odds ratio"""
odds_treatment = conversions_treatment / (total_treatment - conversions_treatment)
odds_control = conversions_control / (total_control - conversions_control)
or_value = odds_treatment / odds_control
return or_value
# Пример: новый UI повысил конверсию
converted_new = 520 # из 10,000
converted_old = 500 # из 10,000
or_val = odds_ratio(520, 10000, 500, 10000)
print(f"Odds Ratio = {or_val:.3f}")
# OR = 1.04 означает: шансы конвертиться в 1.04 раза выше (4% увеличение)
3. Relative Lift (самый понятный для бизнеса)
def relative_lift(treatment_rate, control_rate):
"""Процентный прирост"""
return (treatment_rate - control_rate) / control_rate * 100
control_cr = 0.05 # 5%
treatment_cr = 0.0525 # 5.25%
lift = relative_lift(treatment_cr, control_cr)
print(f"Relative Lift = {lift:.1f}%") # +5%
Почему p-value недостаточно
Проблема 1: P-value зависит от размера выборки
from scipy.stats import chi2_contingency
# Сценарий: конверсия выросла на 0.1 процентный пункт (5% → 5.1%)
# Эффект = 0.1 п.п. (практически незначительный)
for n in [1000, 10000, 100000, 1000000]:
# Control: 5% конверсия
control_conversions = int(n * 0.05)
# Treatment: 5.1% конверсия
treatment_conversions = int(n * 0.051)
# Chi-square test
contingency_table = [
[control_conversions, n - control_conversions],
[treatment_conversions, n - treatment_conversions]
]
chi2, p_value, dof, expected = chi2_contingency(contingency_table)
print(f"n={n}: p-value={p_value:.4f}, Effect=0.1% (одинаков везде!)")
# Результат:
# n=1000: p-value=0.9234 ← не значим
# n=10000: p-value=0.2893 ← не значим
# n=100000: p-value=0.0047 ← значим!
# n=1000000: p-value<0.0001 ← очень значим!
Одинаковый эффект (0.1%) становится "значимым" просто потому, что выборка больше!
Проблема 2: Маленький эффект может быть статистически значимым
Сценарий A (маленький эффект, большая выборка):
- Control CR: 5.0%, n=100,000
- Treatment CR: 5.1%, n=100,000
- p-value = 0.002 (статистически значим!)
- Effect size (relative lift) = +2%
- **Вывод:** Статистически значимо, но практически бесполезно
Сценарий B (большой эффект, маленькая выборка):
- Control CR: 5.0%, n=100
- Treatment CR: 10.0%, n=100
- p-value = 0.11 (не значим)
- Effect size (relative lift) = +100%!
- **Вывод:** Практически важно, но статистически не доказано
Как правильно использовать оба метрики
Шаг 1: Рассчитайте Effect Size перед запуском теста
def required_sample_size(baseline_cr, desired_lift, alpha=0.05, power=0.80):
"""Рассчитывает нужный размер выборки"""
from scipy.stats import norm
effect = baseline_cr * desired_lift / 100 # Lift в абсолютных значениях
target_cr = baseline_cr + effect
# Две стороны: контроль и вариант
p_avg = (baseline_cr + target_cr) / 2
z_alpha = norm.ppf(1 - alpha/2)
z_beta = norm.ppf(power)
n = 2 * (z_alpha + z_beta)**2 * (p_avg * (1 - p_avg)) / (effect**2)
return int(n)
# Пример: baseline 5%, хотим +10% lift
n = required_sample_size(baseline_cr=0.05, desired_lift=10)
print(f"Нужно {n} пользователей в каждой группе")
Шаг 2: Сообщайте результаты с обоими показателями
❌ ПЛОХО:
"p-value = 0.03, результат значим!"
✅ ХОРОШО:
"Конверсия выросла с 5.0% до 5.2% (p=0.03, относительный lift +4%, 95% CI: [1%, 7%])
Это статистически значимо, но практический эффект мал для нашей метрики ROI."
Таблица интерпретации
| P-Value | Effect Size | Действие |
|---|---|---|
| < 0.05 | Большой (d > 0.8) | ✅ Деплоить! Статистически значимо + практически важно |
| < 0.05 | Маленький (d < 0.2) | ⚠️ Осторожно. Может быть математическая артефакт |
| > 0.05 | Большой (d > 0.8) | ⚠️ Нужна большая выборка. Effect есть, но недостаточно доказательств |
| > 0.05 | Маленький (d < 0.2) | ❌ Откатить. Нет эффекта |
Практические рекомендации
-
Всегда рассчитывайте effect size перед тестом
- Минимальный приемлемый эффект (MAPE — Minimum Acceptable Practical Effect)
- На основе этого определите размер выборки
-
Не полагайтесь только на p-value
- Используйте доверительные интервалы (confidence intervals)
- Они показывают диапазон вероятных значений эффекта
-
Проверяйте практическую значимость
- Даже если p < 0.05, спросите: "Это достаточно большой эффект для нас?"
- ROI при 2% lift может быть отрицательным
-
Документируйте pre-registration
- Минимальный эффект, который вас интересует
- Это предотвратит p-hacking (поиск любого результата)
-
Используйте sequential testing с бэйесовыми методами
- Вероятность того, что вариант лучше (Probability of Being Best — PBB)
- Более интуитивно, чем p-value
# Бэйесовский подход: какова вероятность, что вариант лучше?
# (вместо "есть ли различие")
from scipy.stats import binom
def bayesian_credible_interval(successes, trials, credibility=0.95):
"""Простой бэйесовский доверительный интервал"""
alpha = (1 - credibility) / 2
from scipy.stats import beta
# Beta distribution (после наблюдения successes из trials)
low = beta.ppf(alpha, successes + 1, trials - successes + 1)
high = beta.ppf(1 - alpha, successes + 1, trials - successes + 1)
return low, high
ci_low, ci_high = bayesian_credible_interval(520, 10000)
print(f"95% вероятность, что истинная конверсия между {ci_low:.3f} и {ci_high:.3f}")
Вывод: p-value отвечает на вопрос "есть ли эффект?" (да/нет). Effect size отвечает на вопрос "насколько большой эффект?" (величина). Для хорошего решения нужны оба ответа.