Репрезентативность выборки: что это и как её проверить
Репрезентативная выборка — та, чей способ отбора не искажает ответ на ваш вопрос. Виды смещений, проверка на SQL и хи-квадратом, взвешивание и когда без репрезентативности можно обойтись.
Содержание статьи
Команда запустила опрос о пользе отчётов прямо в разделе отчётов. Ответов много, вывод напрашивается: «37% пользователей делают экспорт, значит, он нужен больше чем каждому третьему». Но опрос видят только те, кто хотя бы раз создал отчёт. Можно ли переносить их ответы на всех пользователей? Это и есть вопрос о репрезентативности. Разберём, что она значит, какие бывают смещения, как проверить выборку на известных признаках с помощью SQL и хи-квадрата, как взвешивание исправляет часть перекоса и почему не исправляет остальное. Все числа — из учебной базы SQL-курса, где ответ заранее известен.
Что такое репрезентативная выборка
Репрезентативная выборка — это выборка, по которой можно без систематического сдвига оценить нужный показатель генеральной совокупности. Проще: способ отбора не связан с тем, что вы измеряете, настолько, чтобы исказить ответ.
Из определения следуют две вещи. Репрезентативность — свойство механизма отбора, а не числа ответов. И она всегда относится к конкретному вопросу. Одна и та же выборка может честно показывать долю мобильных пользователей и сильно завышать долю тех, кто пользуется экспортом.
Поэтому вопрос «репрезентативна ли выборка вообще» не имеет ответа. Рабочая формулировка звучит так: «можно ли по этой выборке оценить вот этот показатель для вот этой совокупности».
- Репрезентативность зависит от того, как отбирали, а не от того, сколько отобрали.
- Проверить её напрямую нельзя: можно только сравнить выборку с совокупностью по признакам, которые известны для всех.
- Совпадение по известным признакам — необходимое, но не достаточное условие.
- Взвешивание исправляет перекос по тем признакам, по которым взвешивали, и по всему, что с ними связано. Остальное остаётся.
Почему большая выборка не гарантирует репрезентативность
Рост выборки уменьшает случайную ошибку, но не трогает систематическую. Если отбор перекошен, миллион ответов даст очень узкий интервал вокруг неверного числа.
Классический пример — выборы в США 1936 года. Журнал Literary Digest разослал около 10 миллионов анкет, получил примерно 2,4 миллиона ответов и предсказал победу Альфа Лэндона; Рузвельт выиграл с большим отрывом. Адреса брали в основном из списков подписчиков, телефонных книг и регистраций автомобилей, а отвечали охотнее противники действующего президента.
На учебной базе эффект виден так же ясно. Среди 1 775 пользователей, создавших хотя бы один отчёт, экспорт делали 37,01%. Во всей базе из 4 613 человек — 21,42%. Опрос в разделе отчётов почти вдвое завысил бы долю пользователей экспорта, и собрать ещё тысячу ответов в том же месте ничего бы не изменило.
Какие бывают смещения выборки
Смещения различаются тем, на каком шаге люди выпадают из выборки. Название помогает понять, где искать причину и что с ней можно сделать.
| Смещение | Что происходит | Пример в продукте |
|---|---|---|
| Ошибка отбора (selection bias) | Правило отбора связано с измеряемым показателем | Опрос в разделе отчётов про использование экспорта |
| Неполный охват (coverage) | Часть совокупности вообще не может попасть в выборку | Опрос в вебе, а треть аудитории пользуется только приложением |
| Неответы (non-response) | Приглашены все, но ответили не все, и ответившие отличаются | Письмо с опросом открывают в основном активные клиенты |
| Самоотбор (self-selection) | Человек сам решает, участвовать ли | NPS заполняют самые вовлечённые и самые недовольные |
| Ошибка выжившего (survivorship) | В данных остались только те, кто «дожил» до момента измерения | Анализ удовлетворённости по текущим клиентам без ушедших |
Если изучать удовлетворённость только по текущим клиентам, недовольные, которые уже ушли, в расчёт не попадут. Оценка выйдет выше реальной, а причины оттока останутся невидимыми.
Как проверить репрезентативность выборки
Прямой проверки нет: ответов тех, кто в выборку не попал, вы не знаете. Косвенная проверка — сравнить выборку с совокупностью по признакам, которые известны для всех: канал привлечения, устройство, страна, месяц регистрации, тариф. Если выборка расходится с базой по ним, это сигнал, что она может расходиться и по тому, что вы спрашиваете.
Сделаем это для «респондентов» — 1 775 пользователей, у которых есть событие report_created. Запрос собирает доли каналов в базе и среди респондентов одной таблицей; для месяца регистрации и устройства меняется только поле группировки.
Перекос заметен сразу. Пользователи из paid_search составляют 22,0% базы и только 13,4% респондентов. Органика и рефералы, наоборот, представлены сильнее. По месяцу регистрации и устройству расхождения мягче, около 3 п.п.: июньских пользователей и десктопа среди респондентов чуть больше.
| Признак | Значение | Во всей базе (4 613) | Среди респондентов (1 775) | Разница, п.п. |
|---|---|---|---|---|
| Канал | organic | 37,9% | 43,4% | +5,5 |
| Канал | paid_search | 22,0% | 13,4% | −8,6 |
| Канал | partner | 17,6% | 15,8% | −1,8 |
| Канал | referral | 22,5% | 27,4% | +4,9 |
| Месяц регистрации | июнь | 22,6% | 25,6% | +3,0 |
| Месяц регистрации | июль | 36,3% | 34,5% | −1,8 |
| Месяц регистрации | август | 41,1% | 39,9% | −1,2 |
| Устройство | desktop | 51,7% | 54,7% | +3,0 |
| Устройство | mobile | 48,3% | 45,3% | −3,0 |
Учебная база SQL-курса: 4 613 пользователей, из них 1 775 создали хотя бы один отчёт.
with respondents as (
select distinct user_id
from events
where event_name = 'report_created'
)
select u.channel,
count(*) as population,
count(r.user_id) as respondents,
round(100.0 * count(*) / sum(count(*)) over (), 1) as population_pct,
round(100.0 * count(r.user_id) / sum(count(r.user_id)) over (), 1) as respondents_pct
from users u
left join respondents r on r.user_id = u.user_id
group by u.channel
order by u.channel;Как отличить перекос от случайного расхождения: хи-квадрат
Даже честная случайная выборка не совпадёт с базой до десятой доли процента. Чтобы понять, укладывается ли расхождение в случайный разброс, подходит критерий согласия хи-квадрат: он сравнивает наблюдаемые числа в выборке с теми, что ожидались бы при долях как в совокупности. В SciPy это scipy.stats.chisquare.
Для респондентов по каналу статистика равна 96,1, p ≈ 1,1·10⁻²⁰: такой перекос случайностью не объяснить. По месяцу регистрации p = 0,0098, по устройству p = 0,011 — расхождения небольшие, но на 1 775 наблюдениях уже заметные.
Для контраста проверим десять систематических выборок user_id % 10 = 0 … 9, примерно по 461 человеку. Восемь проходят проверку, две получают p = 0,029 и 0,041. При пороге 0,05 честная выборка ошибочно «проваливается» примерно в одном случае из двадцати, так что два из десяти — неудача, но не аномалия. Отсюда практическое правило: смотрите на размер расхождений в п.п., а не только на p. На большой выборке значимым станет и расхождение в полпроцента, которое ни на что не влияет.
Тот же тест лежит в основе проверки SRM в A/B-тестах: там сравнивают фактическое деление трафика между вариантами с запланированным.
import numpy as np
from scipy.stats import chisquare
def check(population, observed):
population, observed = np.array(population), np.array(observed)
expected = population / population.sum() * observed.sum()
return chisquare(observed, f_exp=expected)
# Кто создал хотя бы один отчёт (1775 человек) против всех 4613
checks = {
"канал": ([1747, 1015, 814, 1037], [770, 238, 281, 486]), # organic, paid_search, partner, referral
"месяц": ([1042, 1676, 1895], [454, 612, 709]), # июнь, июль, август
"устройство": ([2384, 2229], [971, 804]), # desktop, mobile
}
for name, (population, observed) in checks.items():
stat, p = check(population, observed)
print(f"{name}: хи-квадрат = {stat:.1f}, p = {p:.2g}")
# Десять систематических выборок user_id % 10 = 0 … 9, распределение по каналам
channels = [1747, 1015, 814, 1037]
systematic = [
[182, 99, 90, 90], [173, 99, 82, 108], [169, 104, 103, 86],
[192, 114, 64, 92], [174, 98, 77, 112], [164, 111, 74, 112],
[167, 100, 80, 114], [173, 84, 80, 124], [166, 110, 80, 105],
[187, 96, 84, 94],
]
for k, observed in enumerate(systematic):
stat, p = check(channels, observed)
print(f"user_id % 10 = {k}: хи-квадрат = {stat:.2f}, p = {p:.3f}")
# канал: хи-квадрат = 96.1, p = 1.1e-20
# месяц: хи-квадрат = 9.3, p = 0.0098
# устройство: хи-квадрат = 6.5, p = 0.011
# user_id % 10 = 0: хи-квадрат = 3.09, p = 0.378
# user_id % 10 = 1: хи-квадрат = 0.26, p = 0.967
# user_id % 10 = 2: хи-квадрат = 8.99, p = 0.029
# user_id % 10 = 3: хи-квадрат = 8.28, p = 0.041
# user_id % 10 = 4: хи-квадрат = 1.03, p = 0.795
# user_id % 10 = 5: хи-квадрат = 2.88, p = 0.410
# user_id % 10 = 6: хи-квадрат = 1.41, p = 0.703
# user_id % 10 = 7: хи-квадрат = 7.04, p = 0.071
# user_id % 10 = 8: хи-квадрат = 1.19, p = 0.756
# user_id % 10 = 9: хи-квадрат = 2.16, p = 0.541Как сделать выборку репрезентативной: стратификация, квоты, взвешивание
Лучше всего исправлять перекос до сбора данных. Стратифицированная выборка делит совокупность на группы — например, по каналу — и отбирает из каждой случайно, в нужной пропорции. Квоты работают похоже, но внутри группы отбор уже не случайный: «набрать 220 ответов из paid_search» можно и за счёт самых активных. Квоты выравнивают состав, но не гарантируют честность внутри квоты.
Если данные уже собраны, остаётся пост-стратификация: взвешивание ответов так, чтобы доли групп совпали с совокупностью. Вес группы равен её доле в базе, делённой на долю в выборке. У paid_search вес 22,0% / 13,4% ≈ 1,64: каждый ответ из этого канала считается за 1,64 ответа. У органики вес 0,873, у рефералов 0,821, у партнёров 1,115.
Взвешенная оценка доли — это сумма по группам: доля группы в базе, умноженная на показатель внутри группы в выборке. Проверим на двух вопросах, для которых знаем правду по всей базе.
Доля платящих среди респондентов — 21,24%, во всей базе 19,77%. После взвешивания по каналу получаем 19,99%: почти вся ошибка ушла. Так вышло потому, что внутри каждого канала респонденты платят примерно так же часто, как все: в органике 23,25% против 23,47%, в рефералах 24,69% против 26,81%. Перекос по оплатам объяснялся составом каналов.
С экспортом не так. Среди респондентов его делали 37,01%, после взвешивания — 36,96%, а правда — 21,42%. Внутри каждого канала респонденты делают экспорт намного чаще остальных: в paid_search 35,71% против 12,71% по каналу в целом. Отбор шёл по вовлечённости, а не по каналу, и вес по каналу её не видит.
вес группы = доля в совокупности / доля в выборке p̂_взв = Σ (доля группы в совокупности · p̂ группы)Взвешивание работает, если внутри каждой группы ответившие похожи на неответивших по изучаемому признаку.
Для оплат взвешивание почти убирает ошибку, для экспорта — нет: отбор связан с вовлечённостью, а не с каналом.
# Пост-стратификация по каналу: вес = доля канала в базе / доля в выборке
channels = ["organic", "paid_search", "partner", "referral"]
population = [1747, 1015, 814, 1037] # все пользователи
sample = [770, 238, 281, 486] # создали отчёт
payers = [179, 25, 53, 120] # из них платили
exporters = [288, 85, 109, 175] # из них делали экспорт
N, n = sum(population), sum(sample)
for ch, P_c, n_c in zip(channels, population, sample):
print(f"{ch:12} вес = {(P_c / N) / (n_c / n):.3f}")
def raw_and_weighted(hits):
raw = sum(hits) / n
weighted = sum(P_c / N * h / n_c for P_c, h, n_c in zip(population, hits, sample))
return raw, weighted
for name, hits, truth in [("платили", payers, 912 / N), ("экспорт", exporters, 988 / N)]:
raw, w = raw_and_weighted(hits)
print(f"{name}: в выборке {raw:.2%}, после взвешивания {w:.2%}, во всей базе {truth:.2%}")
# organic вес = 0.873
# paid_search вес = 1.641
# partner вес = 1.115
# referral вес = 0.821
# платили: в выборке 21.24%, после взвешивания 19.99%, во всей базе 19.77%
# экспорт: в выборке 37.01%, после взвешивания 36.96%, во всей базе 21.42%Почему совпадение по известным признакам ничего не доказывает
Пример с экспортом показывает границу метода. Можно взвесить выборку так, что каналы, месяцы и устройства совпадут с базой до десятой доли процента, и всё равно ошибиться вдвое. Сравнение по известным признакам ловит перекос, но не подтверждает его отсутствие.
Практический вывод — думать о механизме. Спросите: почему эти люди оказались в выборке и может ли эта причина быть связана с ответом? Опрос в разделе отчётов отбирает тех, кто уже пользуется отчётами. Значит, любой вопрос про использование функций будет завышен, какие бы веса вы ни подобрали.
Если признак, от которого зависит отбор, есть в данных, взвешивайте по нему. Здесь это могла бы быть активность: число событий за первую неделю или факт создания отчёта. Если такого признака нет, честнее переформулировать вопрос: «среди пользователей отчётов 37% делают экспорт» — верное и полезное утверждение.
Когда нерепрезентативная выборка — не проблема
В A/B-тесте участники почти никогда не репрезентативны для всей аудитории: туда попадает трафик конкретных двух недель, конкретного сезона, часто одной платформы. Но сравнение вариантов всё равно честное, потому что внутри теста пользователей распределяют между группами случайно. Рандомизация даёт внутреннюю валидность: разница между A и B вызвана изменением, а не составом групп.
Вопрос о переносе результата — внешняя валидность — остаётся отдельным. Эффект, измеренный в августе на новых пользователях из России, может не повториться в декабре или в другой стране. Поэтому в описании теста фиксируют, на ком он шёл, а основную метрику и ограничители выбирают до запуска.
Второй случай — качественные исследования. Если цель интервью — найти, где пользователи спотыкаются, а не измерить, как часто это случается, нужны разнообразные собеседники, а не пропорциональные. Проблемы стоит искать у тех, кто с ними сталкивается, а доли — считать на данных о поведении.
Чек-лист перед тем, как переносить выводы на всех
Короткий список вопросов, которые стоит задать до того, как число из опроса или сегмента попадёт в презентацию.
- О какой совокупности вывод? Назовите её одной фразой.
- Кто мог попасть в выборку, а кто не мог в принципе?
- Кто из приглашённых ответил и чем ответившие могут отличаться?
- Совпадает ли выборка с базой по каналу, устройству, стране, возрасту аккаунта? Смотрите на разницу в п.п.
- Связан ли механизм отбора с измеряемым показателем? Если да, взвешивание не поможет.
- Если взвешивали — сравните оценку до и после. Сильный сдвиг говорит о большом перекосе, а значит, и о риске по невидимым признакам.
Что почитать дальше и где потренироваться
Базовые понятия — генеральная совокупность, выборка, параметр и погрешность — разобраны в отдельном материале. Повторить запросы из статьи и проверить свои выборки можно в песочнице SQL-курса: там та же учебная база.
Материалы по теме
Какой статистический метод выбрать: t-тест, хи-квадрат, бутстреп, Байес или регрессия
Навигатор по методам для аналитика: когда сравнивать средние t-тестом, доли и категории хи-квадратом, где нужен бутстреп, байесовский апдейт, линейная или логистическая регрессия — и что каждый из них не скажет.
Проверка SRM: как понять, что сплит A/B-теста перекосило
Что такое SRM в A/B-тесте, как проверить перекос сплита критерием χ², почему порог здесь 0,0005 вместо 0,05 и что делать, когда трафик разошёлся по группам не по плану.
Почему метрика обманывает: состав, календарь, база и декомпозиция
Как честно посчитанная метрика приводит к неверному выводу: парадокс Симпсона, регрессия к среднему, сезонность, аномалии и декомпозиция роста по вкладам сегментов.