Короткий ответ, который закрывает 90% случаев: сравниваешь средние — средний чек, время в приложении, выручку на пользователя — бери t-тест. Сравниваешь доли — конверсию в оплату, CTR, долю вернувшихся — бери z-тест для двух пропорций. Причина одна: t-тест не требует, чтобы ты знал настоящий разброс данных в генеральной совокупности, а ты его почти никогда не знаешь. Дальше разберём, почему это так, где правило ломается и как посчитать оба теста руками на scipy.
В чём вообще разница между z-тестом и t-тестом?
Оба теста отвечают на один вопрос: отличается ли наблюдаемое среднее (или доля) от какого-то значения настолько, что случайностью это уже не объяснить. И статистика у них считается почти одинаково: берёшь разницу, делишь на стандартную ошибку. Отличие — в одном месте формулы и в том, с каким распределением ты потом сравниваешь результат.
z-тест предполагает, что стандартное отклонение генеральной совокупности σ тебе известно. Ты подставляешь его в стандартную ошибку σ / sqrt(n) и сравниваешь z-статистику со стандартным нормальным распределением.
t-тест честно признаёт: настоящую σ ты не знаешь, у тебя есть только оценка по выборке — выборочное стандартное отклонение s. Ты подставляешь s вместо σ, а сравниваешь уже не с нормальным распределением, а с распределением Стьюдента (t-распределением) с n - 1 степенями свободы.
Разница в формуле — одна буква. Разница по смыслу — большая. Когда ты оцениваешь разброс по выборке, ты добавляешь ещё один источник неопределённости: s само по себе шумит, особенно на маленьких выборках. t-распределение это учитывает — у него тяжелее хвосты, чем у нормального. «Тяжёлые хвосты» на практике значат, что критическое значение больше, доверительный интервал шире, а тест труднее убедить, что разница реальна. Это плата за то, что ты не знал σ заранее.
Почему для средних почти всегда берут t-тест?
Простой встречный вопрос: а когда ты вообще знаешь настоящую σ, но при этом не знаешь среднее μ? На практике — почти никогда. Если бы ты знал точный разброс генеральной совокупности, ты, скорее всего, знал бы про неё и всё остальное. Реальность аналитика другая: есть выборка из orders за последний месяц, по ней ты считаешь и среднее, и разброс. Оба — оценки.
Отсюда вывод, который стоит запомнить: для среднего честный дефолт — t-тест. И у него есть приятное свойство. С ростом n t-распределение сходится к нормальному: на тридцати наблюдениях разница между критическими значениями уже небольшая, на сотнях — исчезающе мала. То есть если выборка большая, t-тест даёт практически тот же ответ, что и z. А если выборка маленькая, только t-тест посчитает неопределённость правильно.
Получается асимметрия рисков. Взял t на большой выборке — ничего не потерял, он совпал с z. Взял z на маленькой выборке, подставив туда s вместо неизвестной σ — занизил неопределённость, хвосты у нормального распределения легче, и ты словил лишние ложноположительные результаты. Поэтому t — безопасный выбор всегда, а z для среднего — частный случай, который срабатывает только на больших n, и то потому, что там он совпадает с t.
Одна оговорка: t-тест на маленькой выборке предполагает, что сами данные распределены примерно нормально. Для среднего чека или выручки — а они обычно скошены вправо, с длинным хвостом дорогих заказов — это допущение на двадцати наблюдениях может подвести. Спасает либо большая выборка (тогда включается ЦПТ, о ней ниже), либо логарифмирование, либо непараметрика вроде критерия Манна–Уитни, либо бутстрап.
При чём тут центральная предельная теорема?
ЦПТ — это фундамент, на котором вообще держатся оба теста. Она говорит: если взять среднее большого числа независимых одинаково распределённых величин с конечной дисперсией, то распределение этого среднего стремится к нормальному — независимо от того, как распределены сами данные. Средний чек может быть скошен как угодно, но среднее по достаточно большой выборке ведёт себя как нормальная величина.
Именно это делает z- и t-тесты рабочими. z-тест опирается на ЦПТ напрямую: он просто предполагает, что твоя статистика нормальна. t-тест добавляет поправку на то, что дисперсию ты оценил, а не знал, — но при больших n эта поправка сходит на нет, потому что s становится точной оценкой σ, и t превращается в z.
Практический смысл: не нужно молиться на нормальность исходных данных, когда выборка большая. Люди часто гоняют тесты Шапиро–Уилка на 50 000 наблюдений и паникуют, что «данные не нормальные». Для среднего это неважно — ЦПТ уже сделала работу. Нормальность исходных данных критична только на маленьких выборках, где ЦПТ ещё не успела включиться.
Почему в A/B-тестах на конверсию используют z-тест?
Тут интересный поворот. Конверсия — это ведь тоже среднее: доля единиц среди нулей и единиц (заплатил / не заплатил). Логика выше вроде бы велит брать t. Почему тогда стандарт для A/B на конверсию — двухвыборочный z-тест для пропорций?
Ответ — в природе бинарной величины. Для распределения Бернулли дисперсия жёстко привязана к среднему: если доля равна p, то дисперсия равна p * (1 - p). Отдельного, независимого параметра разброса, который надо было бы оценивать, просто нет. Когда ты проверяешь гипотезу «конверсии в группах равны», ты под нулевой гипотезой фиксируешь общую долю p (объединённую по обеим группам) — и вместе с ней автоматически получаешь дисперсию. Она известна. А раз дисперсия известна — это ситуация ровно для z-теста.
Сравни с непрерывной метрикой вроде среднего чека: там среднее и дисперсия — два независимых параметра. Средний чек 1200 рублей может идти и с маленьким разбросом, и с огромным. Дисперсию приходится оценивать отдельно по выборке — и это возвращает нас к t.
Второй аргумент за z в A/B чисто практический: выборки в A/B-тестах большие, тысячи и десятки тысяч пользователей. При таких n разница между t и z стирается в любом случае, а нормальное приближение к биномиальному распределению отлично работает. Так что z для пропорций — это и принципиально верно (дисперсия известна через p), и практично (большие выборки).
Оговорка для редких событий: если конверсия крошечная — доли процента — и абсолютное число событий мало, нормальное приближение ломается. Ориентир: нужно хотя бы n*p >= 10 и n*(1-p) >= 10 в каждой группе. Не выполняется — берёшь точный тест: точный биномиальный или критерий Фишера.
Насколько сильно расходятся z и t на практике?
Давай приземлим. Для двустороннего теста на уровне 0.05 критическое значение z — это 1.96. У t-распределения оно зависит от степеней свободы:
- 5 степеней свободы — около 2.57;
- 10 — около 2.23;
- 30 — около 2.04;
- 100 — около 1.98;
- 1000 — практически 1.96.
Вывод читается сразу. На горстке наблюдений разница между t и z по порогу — процентов двадцать, это принципиально. На тридцати — уже мелочь. На сотнях и тысячах — считай, их нет. Поэтому в A/B с большими группами спор «z или t для среднего» академический: ответ совпадёт до третьего знака. А вот на маленьких выборках — офлайн-эксперимент на 15 магазинах, опрос на 40 респондентов — разница реальная, и правильный выбор именно t.
Как посчитать оба теста в Python
Для средних — t-тест из scipy. По умолчанию бери версию Уэлча (equal_var=False): она не требует, чтобы дисперсии в группах были равны, а это допущение в жизни почти всегда нарушается. Ничего не теряешь, а риск получить кривой результат из-за разного разброса убираешь.
import numpy as np
from scipy import stats
# средний чек в двух группах A/B-теста, рубли
control = np.array([1200, 980, 1500, 1100, 1350, 890, 1600, 1250, 1050, 1420])
variant = np.array([1310, 1180, 1620, 1240, 1490, 1010, 1720, 1390, 1150, 1550])
t_stat, p_value = stats.ttest_ind(control, variant, equal_var=False)
print(f"t = {t_stat:.3f}, p-value = {p_value:.4f}")
Для долей — z-тест для двух пропорций. Удобнее всего через statsmodels, но полезно один раз собрать его руками на scipy, чтобы видеть, откуда что берётся:
import numpy as np
from scipy import stats
conversions = np.array([480, 540]) # оплатили
users = np.array([12000, 11850]) # всего в группе
p = conversions / users
p_pool = conversions.sum() / users.sum() # объединённая доля под H0
se = np.sqrt(p_pool * (1 - p_pool) * (1/users[0] + 1/users[1]))
z = (p[1] - p[0]) / se
p_value = 2 * stats.norm.sf(abs(z)) # двусторонний
print(f"z = {z:.3f}, p-value = {p_value:.4f}")
Тут видно ту самую механику: дисперсию я не оценивал отдельно — она вылезла из объединённой доли p_pool через p_pool * (1 - p_pool). Сравниваю с нормальным распределением (stats.norm.sf — это правый хвост), удваиваю на двусторонний вариант. На этих числах получишь z около 2.1 и p-value примерно 0.03 — разница значима на уровне 5%.
То же самое одной строкой, если не хочешь возиться с формулой:
from statsmodels.stats.proportion import proportions_ztest
z, p_value = proportions_ztest([480, 540], [12000, 11850])
Оба сниппета можно прогнать прямо в Python-тренажёре — там scipy и numpy уже подключены, ставить ничего не надо.
Частые ошибки, из-за которых тест врёт
- t-тест поверх нулей и единиц на маленьких счётчиках. Формально среднее от 0/1 посчитается, но для редкой конверсии бери z для пропорций или точный тест — иначе приближение врёт.
- z для среднего с подстановкой
sвместоσна маленькой выборке. Ты называешь это z-тестом, а неопределённость занижаешь. На двадцати наблюдениях это лишние ложные срабатывания. Бери t. - Объединённый (pooled) t-тест (
equal_var=True) при разных дисперсиях в группах. Классика, когда вариант «раскачал» пользователей и разброс вырос. Уэлч (equal_var=False) страхует по умолчанию. - Одна метрика, а сравнений много. Гоняешь пять метрик и радуешься одной значимой на уровне 0.05 — это почти гарантированный ложный результат. Нужна поправка на множественные сравнения (Бонферрони, Бенджамини–Хохберг).
- Проверка нормальности на большой выборке. Шапиро на 50 000 строк всегда скажет «не нормально», и это ни о чём — для среднего работает ЦПТ. Смотри лучше на размер выборки и выбросы.
Что отвечать про это на собеседовании?
Разницу z и t на аналитических собеседованиях спрашивают постоянно — это база, на которой проверяют, понимаешь ли ты, откуда берётся неопределённость. Хороший ответ звучит примерно так: «t — когда дисперсию оцениваю по выборке, а это почти всегда; z — когда дисперсия известна, что на практике встречается для пропорций, потому что там разброс задаётся самой долей. На больших выборках оба сходятся благодаря ЦПТ, так что для средних я по умолчанию беру t, а для конверсии в A/B — z для двух пропорций». Дальше обычно копают в A/B: как считать размер выборки, что с множественными сравнениями, почему Уэлч.
Такие вопросы встречаются и в Яндексе, Ozon, Т-Банке и других компаниях — статистика и A/B у аналитика идут в паре с SQL. Если готовишься системно, посмотри план подготовки к собеседованию и реальные вопросы с интервью, а разбор A/B на живых задачах — в практических кейсах. Понимание, где z, а где t, напрямую конвертируется в грейд и зарплату аналитика: джуна от мидла на статистике отличают именно такие детали.
Отрабатывать всё это лучше руками. Оба теста из статьи, плюс расчёт размера выборки и проверку гипотез, можно прогнать в Python-тренажёре на реальных датасетах и посмотреть, как меняется p-value от размера выборки. В Pro открыты все задачи и безлимитный AI-разбор твоих решений — удобно, когда хочешь не просто получить ответ, а понять, почему тест дал именно такой результат.
Связанная тема — t-критерий Стьюдента простыми словами и пример.