Все материалы
Продуктовая аналитикаматериалстарт

Ошибка выжившего: что это, примеры и как она искажает анализ

Ошибка выжившего простыми словами: вывод по тем, кто остался. История Вальда без легенд и четыре примера из аналитики продукта с SQL и Python: выручка, удержание, опрос, A/B-тест.

КейсПрактика2 октября 2026 г.17 мин

Ошибка выжившего — это вывод, сделанный только по тем, кто дошёл до момента наблюдения: выбывшие в данные не попали. В метрике она сидит в знаменателе. Пример — квартальный отчёт с тремя числами. Клиент с активной подпиской принёс в среднем 37,57 доллара. На восьмой неделе люди заходят в продукт почти так же часто, как на четвёртой. Опрос о продукте разослали тем, кто выгружал отчёты, а это в основном органика и рекомендации. Арифметика везде верная, но все три числа посчитаны по тем, кто остался: ушедшие в выборку не попали. Ниже — история с самолётами Абрахама Вальда, сверенная с источниками, и четыре места, где ошибка живёт в продуктовой аналитике. Каждое разобрано на учебной базе симулятора SQL-аналитика: запросы работают в PostgreSQL и DuckDB, рядом расчёт на Python.

Что такое ошибка выжившего простыми словами

Те, кто выбыл по дороге, в данные не попали, и их отсутствия никто не заметил — в этом вся ошибка. По-английски — survivorship bias, в русских текстах встречается ещё «систематическая ошибка выжившего».

Бытовой пример: старые дома кажутся крепче новых, «раньше строили на века». Но до нас дошли только те дома, что простояли сто лет. Те, что развалились или были снесены, в сравнении не участвуют.

Рабочий пример из учебной базы: средняя выручка на клиента с активной подпиской — 37,57 доллара, а на любого, кто хоть раз платил, — 33,60. Разница в 11,8% взялась не из продукта: фильтр «активные» убрал из расчёта 397 клиентов из 912.

Одна метрика, два знаменателя
по выжившим = сумма по оставшимся / число оставшихся; по когорте = сумма по всем вошедшим / число всех вошедших

Пересчёт вручную. Пять клиентов: трое ушли, заплатив по 19, двое остались и заплатили по 57. По оставшимся — 57. По всем пятерым — (3 · 19 + 2 · 57) / 5 = 34,2.

  • Ошибка сидит не в арифметике, а в знаменателе: в него попали только дошедшие.
  • Признак в запросе — фильтр по текущему статусу, по факту действия или JOIN с таблицей событий.
  • Лекарство — считать от входа в когорту, то есть группу людей, начавших в один период, и оставлять выбывших в расчёте с их нулями.
  • Смотреть только на выживших можно, когда вопрос задан про них самих, а не про всех пришедших.

Что на самом деле известно про самолёты и Абрахама Вальда

Популярная версия такая. Военные изучили пробоины на вернувшихся бомбардировщиках и собирались усилить броню там, где их больше. Вальд возразил: бронировать надо места без пробоин, потому что самолёты с попаданиями туда не вернулись. К рассказу прикладывают схему самолёта в красных точках.

Документально подтверждается меньше. Математик Абрахам Вальд работал в Statistical Research Group при Колумбийском университете и около 1943 года написал восемь меморандумов о том, как оценивать уязвимость частей самолёта по повреждениям вернувшихся машин. В 1980 году Center for Naval Analyses переиздал их под названием «A Method of Estimating Plane Vulnerability Based on Damage of Survivors». Подробный разбор метода — статья Марка Мангеля и Франсиско Саманиего «Abraham Wald's Work on Aircraft Survivability» в Journal of the American Statistical Association (1984, т. 79, № 386).

Саму идею коротко пересказал У. Аллен Уоллис, руководивший исследованиями группы, — в том же журнале в 1980 году, по памяти, через 37 лет. По его словам, военные были склонны защищать части, на которых у вернувшихся самолётов больше попаданий, а Вальд исходил из того, что попадания распределяются по самолёту равномерно, и у него были на то основания. Других свидетельств о позиции военных, кроме этих нескольких фраз, нет. Тогда попадания в уязвимые части должны реже встречаться у вернувшихся: такие самолёты чаще не возвращаются. Из этого он вывел способ оценить вероятность того, что попадание в конкретную часть сбивает самолёт.

Остальное — пересказ. Математик Билл Кассельман в колонке Американского математического общества «The Legend of Abraham Wald» (2016) сверил легенду с меморандумами. В них — вероятностный расчёт по числу вылетевших и вернувшихся самолётов и числу попаданий. Спора с офицерами, реплик Вальда и совета, куда ставить броню, там нет: группа отвечала на заданный вопрос и рекомендаций военным не давала. Схема с точками в англоязычной Википедии подписана как гипотетическая. Вывод Кассельмана осторожный: история может быть правдой, но свидетельств в пользу её самых эффектных деталей почти нет. Метод Вальда — факт, цитаты «от Вальда» — нет.

Насколько фильтр «активные» завышает выручку на клиента?

Менеджер спрашивает, сколько приносит один клиент. В таблице subscriptions одна строка на каждого, кто платил, и статус: active, past_due или churned. Первое, что хочется сделать, — оставить status = 'active': зачем считать тех, кто ушёл. Выгрузка заканчивается 30 августа 2026 года, от этой даты запрос считает дни.

По активным выходит 37,57, по всем платившим — 33,60. Если же вопрос был «сколько приносит одна регистрация», знаменатель — все 4 613 зарегистрированных, и ответ — 6,64. Три знаменателя дают три разных числа, и в план продаж нельзя подставлять первое. Третье тоже не готово для плана: в нём зарегистрированные неделю назад стоят рядом с теми, кто в продукте три месяца. К этому вернёмся в разделе о когортах.

Последний столбец показывает механизм. У активных с первой оплаты прошло в среднем 45 дней, у ушедших — 16. В учебной базе статус выводится из поведения: active получает тот, у кого набралось не меньше семи дней с заходом, а на это нужно время. Фильтр по статусу оказался скрытым фильтром по стажу: в active попали те, у кого было время и набрать семь дней с заходом, и дойти до продления. А churned здесь в основном новички: у 97 из 169 первая оплата была в последние две недели выгрузки.

Выручка на клиента за всё время по текущему статусу подписки
СтатусКлиентовВыручка на клиента, $Дней с первой оплаты
все платившие91233,6035,2
active51537,5745,3
past_due22829,5126,3
churned16926,9816,4
Выручка на клиента по статусу подписки; ROLLUP добавляет строку итога по всем платившим
WITH paid AS (
  SELECT user_id, SUM(amount) AS revenue
  FROM payments
  GROUP BY user_id
)
SELECT
  COALESCE(s.status, 'все платившие') AS status,
  COUNT(*) AS clients,
  SUM(p.revenue) AS revenue,
  ROUND(AVG(p.revenue), 2) AS revenue_per_client,
  ROUND(AVG(DATE '2026-08-30' - s.started_at), 1) AS days_since_first_payment
FROM subscriptions s
JOIN paid p ON p.user_id = s.user_id
GROUP BY ROLLUP (s.status)
ORDER BY clients DESC;
pythonPython: те же три знаменателя в pandas
import pandas as pd

# строки из запроса выше: статус, клиентов, выручка за всё время
subs = pd.DataFrame({
    'status':  ['active', 'past_due', 'churned'],
    'clients': [515, 228, 169],
    'revenue': [19350, 6729, 4560],
})
registered = 4613  # строк в users

survivors = subs[subs.status == 'active']
per_active = survivors.revenue.sum() / survivors.clients.sum()
per_payer = subs.revenue.sum() / subs.clients.sum()
per_registered = subs.revenue.sum() / registered
dropped = subs.clients.sum() - survivors.clients.sum()

print(f'на активную подписку:   {per_active:.2f}')
print(f'на любого платившего:   {per_payer:.2f}')
print(f'на зарегистрированного: {per_registered:.2f}')
print(f'завышение к платившим:  {per_active / per_payer - 1:+.1%}')
print(f'фильтр отбросил:        {dropped} из {subs.clients.sum()} ({dropped / subs.clients.sum():.1%})')

Почему активность «на активного» почти не падает к восьмой неделе?

Та же болезнь у метрики «активность на активного пользователя». Возьмём 1 042 человека, зарегистрировавшихся в июне, и для каждой недели жизни посчитаем дни с заходом в продукт двумя способами: на того, кто заходил на этой неделе, и на каждого человека из когорты.

На активного пользователя приходится 1,71 дня на второй неделе и 1,25 на восьмой — снижение примерно на четверть. На человека из когорты — 1,28 и 0,56: падение больше чем вдвое. С четвёртой недели по восьмую первая линия почти стоит: 1,39 против 1,25. Ниже единицы она опуститься не может: чтобы попасть в знаменатель, нужен хотя бы один день с заходом. До этого пола осталось 0,25 дня, оттого линия и выглядит устойчивой.

Обе линии посчитаны верно, но отвечают на разные вопросы: как ведут себя оставшиеся и что стало с теми, кого привлекли. За пологой первой линией не видно, что на восьмой неделе в продукт заходили 467 человек из 1 042. Остальные 575 в знаменатель этой недели не попали, и их нули в среднее не вошли. Это не значит, что они ушли навсегда: 263 из них заходили неделей раньше, 141 вернулся в следующие четыре дня. Метрика «на активного» каждую неделю собирает знаменатель заново — из тех, кто пришёл сам.

Отсюда типичный ложный вывод: «пользователи со стажем вовлечены не хуже новых, значит, с удержанием порядок». Удержание восьмой недели — доля когорты, заходившая на этой неделе, здесь 44,8%, и метрика «на активного» её не показывает.

Столбцы по неделям после регистрации: заходивших в продукт 1 042 на первой неделе и 467 на восьмой, остальная часть когорты в расчёт недели не попала
Июньская когорта учебной базы. Метрика «на активного» делит только на закрашенную часть столбца, метрика «на когорту» — на весь столбец.
Дней с заходом за неделю: на активного пользователя и на человека из когорты

Учебная база симулятора SQL-аналитика, 1 042 регистрации июня 2026. На первой неделе линии совпадают: в день регистрации заходил каждый.

На активного на этой неделеНа человека из когорты
Активность июньской когорты по неделям жизни: два знаменателя
WITH cohort AS (
  SELECT user_id, signup_date
  FROM users
  WHERE signup_date >= DATE '2026-06-01' AND signup_date < DATE '2026-07-01'
),
active_days AS (
  SELECT DISTINCT c.user_id, CAST(e.event_time AS DATE) - c.signup_date AS day_no
  FROM cohort c
  JOIN events e ON e.user_id = c.user_id
  WHERE e.event_name = 'app_open'
),
weekly AS (
  SELECT
    user_id,
    CAST(FLOOR(day_no / 7.0) AS INTEGER) + 1 AS week_no,
    COUNT(*) AS days_active
  FROM active_days
  WHERE day_no < 56
  GROUP BY user_id, CAST(FLOOR(day_no / 7.0) AS INTEGER) + 1
)
SELECT
  week_no,
  COUNT(*) AS active_users,
  SUM(days_active) AS active_days,
  ROUND(1.0 * SUM(days_active) / COUNT(*), 2) AS days_per_active,
  ROUND(1.0 * SUM(days_active) / (SELECT COUNT(*) FROM cohort), 2) AS days_per_cohort
FROM weekly
GROUP BY week_no
ORDER BY week_no;

Чьё мнение вы слышите, когда опрашиваете дошедших до конца воронки?

Команда хочет понять, что мешает людям пользоваться продуктом, и рассылает опрос тем, кто выгрузил отчёт: с ними проще связаться, и им есть что сказать. В учебной базе экспорт сделали 988 человек из 4 613, то есть 21,4%. Остальных 3 625 не спросили.

Из платного поиска пришли 22,0% зарегистрированных, а среди сделавших экспорт таких 13,1%. Из 1 015 человек этого канала до экспорта дошли 129, или 12,7%, — вдвое реже, чем пришедшие по рекомендации (26,7%). Две оговорки. Платный поиск запущен 1 июля; на регистрациях с этой даты его доля — 28,4% зарегистрированных и 17,9% сделавших экспорт. И 126 человек, пришедших 28–29 августа, сделать экспорт ещё не успели: до него в базе проходит два дня.

Опрос ответит на вопрос «что думают те, у кого получилось». О том, почему 886 человек из платного поиска до экспорта не добрались, он не скажет ничего: этих людей в выборке нет вовсе, а от всего канала в ней 129 человек из 988. Так же устроены отзывы и обращения в поддержку — пишут те, кто ещё пользуется продуктом.

Таблицы отзывов в учебной базе нет, поэтому показан только состав выборки. Что ответили бы недошедшие, данные не знают.

Кто зарегистрировался и кто дошёл до экспорта, по каналам
КаналЗарегистрировалисьДоля, %Сделали экспортДоля среди них, %Дошли до экспорта, %
organic1 74737,941542,023,8
referral1 03722,527728,026,7
paid_search1 01522,012913,112,7
partner81417,616716,920,5
Состав по каналам: все зарегистрированные и те, кто сделал экспорт
WITH exporters AS (
  SELECT DISTINCT user_id
  FROM events
  WHERE event_name = 'export_completed'
)
SELECT
  u.channel,
  COUNT(*) AS registered,
  ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS share_registered,
  COUNT(x.user_id) AS exporters,
  ROUND(100.0 * COUNT(x.user_id) / SUM(COUNT(x.user_id)) OVER (), 1) AS share_exporters,
  ROUND(100.0 * COUNT(x.user_id) / COUNT(*), 1) AS export_rate
FROM users u
LEFT JOIN exporters x ON x.user_id = u.user_id
GROUP BY u.channel
ORDER BY registered DESC;

Что будет, если посчитать A/B-тест только по дошедшим?

В базе есть эксперимент onboarding_checklist: части пользователей на первом экране показывали чек-лист. В таблице experiment_exposures 3 068 человек, у каждого — вариант и флаг converted: совершил ли участник целевое действие теста. Оба промежуточных шага случаются после показа: пространство создают через 35 минут, экспорт делают через два дня. Честное сравнение идёт по всем, кому показали. Соблазнительное — «по тем, кто хотя бы создал рабочее пространство: остальные всё равно продуктом не пользовались».

Три способа отбора дают три ответа: +10,27, +9,76 и +12,11 п. п. На этой базе они расходятся в пределах шума. Зато выборка сжалась с 3 068 человек до 634, и интервал вокруг разницы вырос с ±3,05 до ±6,85 п. п.

Сильного искажения здесь нет: доля дошедших до шага в группах почти одинакова. Пространство создали 58,2% контроля и 60,5% теста — разница 2,4 ± 3,5 п. п., в пределах шума; экспорт сделали 20,6% и 20,8%. Учебные данные так построены, что чек-лист не меняет, кто дойдёт до шага. В настоящем эксперименте рассчитывать на это нельзя: изменение на первом экране часто влияет именно на то, кто пойдёт дальше.

Конверсия в эксперименте onboarding_checklist при разном отборе участников (разница посчитана по неокруглённым долям)
Кого считаемУчастниковcontrol, %checklist, %Разница, п. п.95% интервал, ± п. п.
все показанные3 06820,0430,30+10,273,05
создали пространство1 82119,9329,69+9,763,94
сделали экспорт63421,0233,13+12,116,85
Конверсия по вариантам: все показанные и только дошедшие до шага
WITH steps AS (
  SELECT
    user_id,
    MAX(CASE WHEN event_name = 'workspace_created' THEN 1 ELSE 0 END) AS has_workspace,
    MAX(CASE WHEN event_name = 'export_completed' THEN 1 ELSE 0 END) AS has_export
  FROM events
  GROUP BY user_id
),
scoped AS (
  SELECT 1 AS scope_no, 'все показанные' AS scope, x.variant, x.converted
  FROM experiment_exposures x
  UNION ALL
  SELECT 2, 'создали пространство', x.variant, x.converted
  FROM experiment_exposures x
  JOIN steps s ON s.user_id = x.user_id
  WHERE s.has_workspace = 1
  UNION ALL
  SELECT 3, 'сделали экспорт', x.variant, x.converted
  FROM experiment_exposures x
  JOIN steps s ON s.user_id = x.user_id
  WHERE s.has_export = 1
)
SELECT
  scope,
  variant,
  COUNT(*) AS users,
  SUM(CASE WHEN converted THEN 1 ELSE 0 END) AS conversions,
  ROUND(100.0 * SUM(CASE WHEN converted THEN 1 ELSE 0 END) / COUNT(*), 2) AS conversion_pct
FROM scoped
GROUP BY scope_no, scope, variant
ORDER BY scope_no, variant DESC;
pythonPython: разница конверсий, 95%-й интервал и доля дошедших для каждого отбора
import numpy as np

# из запроса выше: (участников, конверсий) для control и checklist
scopes = {
    'все показанные':       ((1527, 306), (1541, 467)),
    'создали пространство': ((888, 177), (933, 277)),
    'сделали экспорт':      ((314, 66), (320, 106)),
}
shown_c, shown_t = 1527, 1541

for name, ((n_c, x_c), (n_t, x_t)) in scopes.items():
    p_c, p_t = x_c / n_c, x_t / n_t
    se = np.sqrt(p_c * (1 - p_c) / n_c + p_t * (1 - p_t) / n_t)
    print(f'{name:21s} n = {n_c + n_t:4d}'
          f'  разница {(p_t - p_c) * 100:+.2f} ± {1.96 * se * 100:.2f} п. п.'
          f'  дошли: control {n_c / shown_c:.1%}, checklist {n_t / shown_t:.1%}')

Почему сравнение по дошедшим нечестно, даже когда числа сошлись?

Рандомизация уравнивает группы в момент показа. Всё, что случилось после, может зависеть от варианта — в том числе и то, дошёл ли человек до шага. Отфильтровав по шагу, вы сравниваете две группы, отобранные по-разному.

Условный пример: числа придуманы для иллюстрации, это не учебная база. В каждой группе по 1 000 человек. В контроле до шага дошли 300, целевое действие совершили 150. Чек-лист довёл до шага 500 человек, целевое действие совершили 200.

По всем показанным тест выигрывает: 20% против 15%. По дошедшим проигрывает: 40% против 50%. Чек-лист привёл к шагу 200 дополнительных человек, менее мотивированных. Если те 300, кто дошёл бы и без чек-листа, ведут себя так же, как в контроле, то добавочные 200 дали 50 конверсий, то есть 25%. Они размыли долю, хотя принесли продукту 50 лишних конверсий.

Бывает и зеркальная картина: вариант отпугивает слабо заинтересованных, до шага доходят самые упорные, и конверсия «по дошедшим» растёт при падении общей. Поэтому знаменатель в A/B-тесте — все, кого распределили в группу. Шаг воронки можно сделать отдельной метрикой, но не фильтром. Резать результат можно по тому, что известно до показа: устройство, канал, дата регистрации. Такие сегменты рандомизация уравняла; пример — разбор этого теста по устройствам в SQL.

pythonPython: условный пример, где отбор по шагу переворачивает вывод
import pandas as pd

# условные числа, не учебная база: чек-лист доводит до шага больше людей
ab = pd.DataFrame({
    'variant':   ['control', 'checklist'],
    'shown':     [1000, 1000],
    'reached':   [300, 500],   # дошли до промежуточного шага
    'converted': [150, 200],   # совершили целевое действие
}).set_index('variant')

ab['cr_shown'] = ab.converted / ab.shown
ab['cr_reached'] = ab.converted / ab.reached
print(ab[['cr_shown', 'cr_reached']])

extra_reached = ab.loc['checklist', 'reached'] - ab.loc['control', 'reached']
extra_converted = ab.loc['checklist', 'converted'] - ab.loc['control', 'converted']
print(f'добавочных дошедших {extra_reached}, из них конверсий {extra_converted}'
      f' ({extra_converted / extra_reached:.0%})')

Как заметить ошибку выжившего в своём запросе?

Большую часть случаев закрывает один вопрос: кто не попал в выборку и почему. Если причина выбывания связана с метрикой — ушёл, не оплатил, не дошёл до шага, — результат смещён.

В SQL выжившие отбираются тихо, без предупреждений. WHERE status = 'active', JOIN с таблицей платежей или событий, HAVING COUNT(*) >= 3 — каждая такая строка убирает людей из знаменателя. Полезно посчитать, скольких именно.

Сколько людей отрезал каждый фильтр из примеров выше
ФильтрОсталосьОтброшеноДоля отброшенных, %
статус подписки active515 из 91239743,5
заходил на восьмой неделе467 из 1 04257555,2
есть событие export_completed988 из 4 6133 62578,6
A/B: создал рабочее пространство1 821 из 3 0681 24740,6
  • Знаменатель берите от входа: зарегистрировались, впервые оплатили, попали в группу теста. Не «остались на сегодня».
  • Выбывшие остаются в расчёте со своими нулями: LEFT JOIN и COALESCE(…, 0) вместо JOIN.
  • Сравнивайте когорты одного возраста, а не срез «все активные сейчас».
  • Рядом со средней «по активным» ставьте число людей, по которым она посчитана, и размер исходной когорты.
  • Пересчитайте метрику на полной совокупности. Если ответ заметно другой, фильтр отбирал не случайно.

Что показывает расчёт по когортам и где его границы?

Вернёмся к выручке на клиента и разложим её по месяцу регистрации. Знаменателей снова три: все зарегистрированные, все платившие и клиенты с активной подпиской.

Внутри когорты разница между «на платившего» и «на активного» почти исчезает: 43,65 и 44,02 в июне, 24,35 и 24,32 в августе. Активные клиенты не платят больше своих ровесников. Просто среди активных много июньских: 46,4% против 30,9% среди всех плативших. В общем срезе смешались когорты разного возраста, и фильтр по статусу сдвинул смесь в сторону старых.

У когорт своя ловушка, обратная: незрелость. Августовская регистрация принесла 3,29 доллара против 11,81 у июньской, и большая часть разрыва — незрелость: у этих людей было меньше месяца на первую оплату и не было времени на продление. Но не вся. За первые 30 дней жизни июньская когорта дала 6,64 доллара на зарегистрированного, июльская — 5,47: с 1 июля в базе появился платный поиск, и его пользователи платят реже. Сравнивайте когорты на одинаковом сроке жизни, а потом проверяйте, одинаков ли их состав. И причину ухода когорта не называет: она исправляет знаменатель, не больше.

Выручка за всё время по месяцу регистрации на трёх знаменателях, $
Месяц регистрацииЗарегистрировалисьПлатилиАктивных подписокНа зарегистрированногоНа платившегоНа активного
июнь1 04228223911,8143,6544,02
июль1 6763742297,2232,3433,56
август1 895256473,2924,3524,32
Выручка по когортам регистрации: знаменатель от входа, от первой оплаты и от оставшихся
WITH paid AS (
  SELECT user_id, SUM(amount) AS revenue
  FROM payments
  GROUP BY user_id
)
SELECT
  EXTRACT(MONTH FROM u.signup_date) AS signup_month,
  COUNT(*) AS registered,
  COUNT(p.user_id) AS payers,
  SUM(CASE WHEN s.status = 'active' THEN 1 ELSE 0 END) AS active_subs,
  ROUND(SUM(p.revenue) / COUNT(*), 2) AS revenue_per_registered,
  ROUND(SUM(p.revenue) / COUNT(p.user_id), 2) AS revenue_per_payer,
  ROUND(
    SUM(CASE WHEN s.status = 'active' THEN p.revenue ELSE 0 END)
      / SUM(CASE WHEN s.status = 'active' THEN 1 ELSE 0 END),
    2
  ) AS revenue_per_active
FROM users u
LEFT JOIN paid p ON p.user_id = u.user_id
LEFT JOIN subscriptions s ON s.user_id = u.user_id
GROUP BY EXTRACT(MONTH FROM u.signup_date)
ORDER BY signup_month;

Чем ошибка выжившего отличается от смещения отбора и ошибки подтверждения?

Смещение отбора (selection bias) — общее название ситуаций, когда способ попадания в выборку связан с тем, что вы измеряете. Ошибка выжившего — его частный случай: отбор идёт во времени, и в выборке остаются те, кто «дожил». Смещение отбора бывает и без выбывания: опрос в мобильном приложении не слышит тех, кто работает с компьютера, хотя никто никуда не ушёл.

Ошибка подтверждения (confirmation bias) — не про данные, а про аналитика: это склонность искать и запоминать то, что подтверждает готовую гипотезу. Две ошибки часто работают в паре. Гипотеза «продукт удерживает хорошо» подсказывает посмотреть на активных, а данные по активным её подтверждают.

Когда смотреть только на выживших нормально? Когда вопрос о них самих: текущая месячная выручка, нагрузка на поддержку, план продлений на следующий месяц. Ошибка начинается в момент переноса, когда вывод по оставшимся распространяют на всех, кто приходит.

Три ошибки, которые часто путают
ОшибкаГде возникаетПримерЧто помогает
Смещение отбораСпособ набора выборки связан с измеряемымОпрос только в мобильном приложенииОписать, кто мог и кто не мог попасть в выборку
Ошибка выжившегоВ выборке остались прошедшие отбор временемСредняя выручка по активным подпискамЗнаменатель от входа в когорту
Ошибка подтвержденияВ голове аналитикаПроверены только срезы, где гипотеза сходитсяЗаранее записать, какой результат гипотезу опровергнет

Частые вопросы

Почему ошибку выжившего трудно заметить? Данные о выбывших не лежат рядом с пометкой «пропущено»: их нет в таблице, с которой вы работаете. Запрос выполняется, числа сходятся, и ничто не подсказывает, что знаменатель неполный.

Какие есть примеры ошибки выжившего? В аналитике — средний чек по активным клиентам, вовлечённость «на активного пользователя», опрос дошедших до конца воронки, A/B-тест по совершившим промежуточное действие. В быту — советы «как я добился успеха»: те, кто делал то же самое и не добился, советов не раздают.

Как избежать ошибки выжившего? Для каждой метрики «по активным» узнать, сколько людей отбросил фильтр, и пересчитать её от входа в когорту. Полный список проверок — в разделе о том, как заметить ошибку в своём запросе.

Как ошибка выжившего проявляется в бизнесе и инвестициях? Рейтинг фондов за десять лет состоит из фондов, которые эти десять лет просуществовали. Закрытые и присоединённые к другим в него не попадают, поэтому средняя доходность по списку выше той, что получил бы инвестор, выбиравший фонд в начале периода. С компаниями так же: в выборке «успешных» нет тех, кто действовал похоже и закрылся.

Ошибка выжившего и систематическая ошибка выжившего — одно и то же? Да. Оба названия переводят английское survivorship bias, второе подчёркивает, что искажение не случайное: оно повторится на любой выборке, собранной тем же способом.

Что читать дальше

Запросы из статьи можно выполнить в песочнице симулятора SQL-аналитика: там та же учебная база. Для начала поменяйте в запросе про недели июньскую когорту на июльскую и проверьте, на какой неделе её окно наблюдения перестаёт быть полным.

Второе упражнение — пересчитать таблицу каналов только для регистраций с 1 июля, когда запустили платный поиск, и посмотреть, как изменится его доля среди зарегистрированных и среди сделавших экспорт.

Продолжить чтение
Вся библиотека
Продуктовая аналитика2 октября 2026 г.16 мин

Парадокс Монти Холла: решение, объяснение простыми словами и симуляция

Парадокс Монти Холла простыми словами: почему смена двери выигрывает в 2/3 игр. Перебор, формула Байеса, симуляция на Python и SQL и три правила ведущего с разными ответами.

Читать материал
Продуктовая аналитика25 сентября 2026 г.12 мин
Ломаная линия, которая сильно скачет слева и постепенно ложится на горизонтальную прямую справа

Закон больших чисел простыми словами: формулировка и примеры

Закон больших чисел: почему среднее и доля стабилизируются с ростом выборки. Пример с монетой, накопленная конверсия A/B-теста в SQL, слабая и сильная форма, ошибка игрока и когда закон работает медленно.

Читать материал
Продуктовая аналитика24 сентября 2026 г.9 мин
Две почти одинаковые колонки на весах, стрелка которых стоит у нуля

Нулевая гипотеза простыми словами: что это и как её формулировать

Нулевая гипотеза (H0) — утверждение, что эффекта или разницы нет. Чем она отличается от альтернативной гипотезы H1, как формулировать H0 для A/B-теста и продуктовых вопросов, что значит «отвергнуть» и «не отвергнуть» H0 — с расчётом z-теста на учебной базе.

Читать материал