← Назад к вопросам

Какие ошибки выборки существуют и как их минимизировать?

2.2 Middle🔥 192 комментариев
#Статистика и A/B тестирование

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ошибки выборки (Sampling Errors): типы и стратегии минимизации

Ошибки выборки возникают когда мы работаем с подмножеством популяции вместо полных данных. Это фундаментальная проблема в статистике и машинном обучении.

Основной концепт

ПОПУЛЯЦИЯ (все данные)
└─ ВЫБОРКА (наши данные)
   └─ ОШИБКА ВЫБОРКИ (разница между выборкой и популяцией)

Типы ошибок выборки

1. Ошибка за счёт случайности (Sampling Error)

Даже если выборка случайная, она не идеально отражает популяцию.

import numpy as np

# Популяция: орлы vs решки в честной монете (50-50)
population = np.array([0] * 5000 + [1] * 5000)  # 50% орлы, 50% решки
true_p = 0.5

print(f'Истинная вероятность: {true_p}')

# Разные выборки дают разные результаты
np.random.seed(42)
for sample_size in [10, 100, 1000]:
    sample = np.random.choice(population, size=sample_size, replace=True)
    sample_p = sample.mean()
    error = abs(sample_p - true_p)
    print(f'\nВыборка размер {sample_size}:')
    print(f'  Вероятность в выборке: {sample_p:.3f}')
    print(f'  Ошибка: {error:.3f}')

# Вывод:
# Истинная вероятность: 0.5
# Выборка размер 10:
#   Вероятность в выборке: 0.400
#   Ошибка: 0.100
# Выборка размер 100:
#   Вероятность в выборке: 0.450
#   Ошибка: 0.050
# Выборка размер 1000:
#   Вероятность в выборке: 0.502
#   Ошибка: 0.002 ← Ошибка меньше с больших выборкой!

Формула стандартной ошибки:

SE = σ / √n

Где:
σ — стандартное отклонение популяции
n — размер выборки

Вывод: Ошибка уменьшается с √n

2. Bias (Смещение выборки)

Выборка систематически смещена от популяции.

# Пример: опрос о зарплате
# Популяция: все работники (включая бедных и богатых)
# Наша выборка: только люди на LinkedIn (смещено к IT специалистам)
# → Результат: завышенные зарплаты

# Пример с кодом:
from sklearn.datasets import make_classification

# Истинная популяция
X_pop, y_pop = make_classification(
    n_samples=100000,
    weights=[0.7, 0.3],  # 70% класс 0, 30% класс 1
    random_state=42
)
print(f'Истинное соотношение: {y_pop.mean():.1%} класс 1')

# Смещённая выборка (случайно выбрали только класс 1)
small_sample = np.random.choice(np.where(y_pop == 1)[0], size=100)
sample_bias = y_pop[small_sample].mean()
print(f'\nСмещённая выборка: {sample_bias:.1%} класс 1')
print(f'Bias: {sample_bias - y_pop.mean():.1%}')

# Несмещённая выборка
unbiased_sample = np.random.choice(len(y_pop), size=1000)
sample_unbiased = y_pop[unbiased_sample].mean()
print(f'\nНесмещённая выборка: {sample_unbiased:.1%} класс 1')
print(f'Bias: {sample_unbiased - y_pop.mean():.1%}')

3. Selection Bias (Предвзятость выбора)

Способ выбора выборки систематически смещён.

Примеры Selection Bias:

1. Survivor Bias
   - Изучаем успешные стартапы
   - Забываем о 99% которые закрылись
   - Вывод: startups легче чем на самом деле

2. Non-Response Bias
   - Опрос зарплаты
   - Отвечают только довольные (или недовольные)
   - Среднее значение смещено

3. Berkson's Paradox
   - В больнице может быть отрицательная корреляция
   - Между симптомами которые не коррелируют в популяции

4. Availability Bias
   - Используем данные которые легко найти
   - Пропускаем редкие но важные случаи

4. Undersampling Bias

Недостаточная выборка меньшинства в несбалансированных классах.

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report

# Несбалансированный датасет
X, y = make_classification(
    n_samples=10000,
    weights=[0.99, 0.01],  # 99% класс 0, 1% класс 1 (редкий класс)
    random_state=42
)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Неправильно: простое обучение
model = RandomForestClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print('Без балансировки:')
print(classification_report(y_test, y_pred))
# Output: Recall класса 1 очень низкий (20-30%)

# Правильно: балансирование выборки
from sklearn.utils import resample

# Oversampling редкого класса
idx_minority = np.where(y_train == 1)[0]
idx_majority = np.where(y_train == 0)[0]

# Дублируем редкие примеры
idx_minority_resampled = resample(idx_minority, n_samples=len(idx_majority))
idx_balanced = np.concatenate([idx_majority, idx_minority_resampled])

X_train_balanced = X_train[idx_balanced]
y_train_balanced = y_train[idx_balanced]

model = RandomForestClassifier()
model.fit(X_train_balanced, y_train_balanced)
y_pred = model.predict(X_test)

print('\nС балансировкой:')
print(classification_report(y_test, y_pred))
# Output: Recall класса 1 намного выше (70-80%)

Как минимизировать ошибки выборки

1. Увеличить размер выборки

import numpy as np
from scipy import stats

# Формула для размера выборки
# n = (Z² × p × (1-p)) / E²
#
# Где:
# Z — z-score (95% confidence → Z=1.96)
# p — предполагаемая пропорция (0.5 если неизвестна)
# E — margin of error (0.05 = 5%)

def sample_size(confidence=0.95, margin_error=0.05, p=0.5):
    z = stats.norm.ppf((1 + confidence) / 2)
    return int(np.ceil((z**2 * p * (1-p)) / margin_error**2))

for margin in [0.1, 0.05, 0.02]:
    n = sample_size(margin_error=margin)
    print(f'Для margin of error {margin*100}%: нужно {n} примеров')

# Output:
# Для margin of error 10%: нужно 97 примеров
# Для margin of error 5%: нужно 385 примеров
# Для margin of error 2%: нужно 2401 примеров

# Вывод: чтобы уменьшить ошибку в 2 раза → нужно 4x больше данных!

2. Случайная выборка (Random Sampling)

import numpy as np
import pandas as pd

data = pd.DataFrame({
    'id': range(100000),
    'value': np.random.randn(100000)
})

# Простая случайная выборка
sample = data.sample(n=1000, random_state=42)
print(f'Mean в популяции: {data["value"].mean():.4f}')
print(f'Mean в выборке: {sample["value"].mean():.4f}')
print(f'Разница: {abs(data["value"].mean() - sample["value"].mean()):.4f}')

3. Stratified Sampling (Стратифицированная выборка)

Гарантируем что выборка отражает распределение популяции.

from sklearn.model_selection import train_test_split

# Несбалансированные классы
X = np.random.randn(1000, 10)
y = np.array([0]*900 + [1]*100)  # 90% vs 10%

# БЕЗ stratification
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
print(f'Test set без stratification: {y_test.mean():.1%} класс 1')
# Может быть 8% или 12% - зависит от случайности

# С stratification (правильно!)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)
print(f'Test set с stratification: {y_test.mean():.1%} класс 1')
# Будет ровно 10% - как в популяции

4. Weighted Sampling (Взвешенная выборка)

# Даём больший вес редким примерам
from sklearn.utils import class_weight

y = np.array([0]*900 + [1]*100)
class_weights = class_weight.compute_class_weight(
    class_weight='balanced',
    classes=np.unique(y),
    y=y
)
print(f'Веса классов: {class_weights}')
# Output: Веса классов: [0.55 4.95]
# Класс 1 (редкий) имеет вес 4.95, класс 0 имеет вес 0.55

# Использование в модели
model = RandomForestClassifier()
model.fit(X, y, sample_weight=np.array([class_weights[yi] for yi in y]))

5. Cross-Validation (Перекрёстная валидация)

Берём несколько выборок вместо одной.

from sklearn.model_selection import cross_val_score, KFold

model = RandomForestClassifier()
kf = KFold(n_splits=5, shuffle=True, random_state=42)

scores = cross_val_score(model, X, y, cv=kf)

print(f'Scores по фолдам: {scores}')
# Output: [0.92 0.91 0.93 0.90 0.92]
print(f'Mean: {scores.mean():.4f}')
print(f'Std: {scores.std():.4f}')  # Видим вариативность!

# Доверительный интервал
from scipy import stats
ci = stats.t.interval(0.95, len(scores)-1, loc=scores.mean(), scale=stats.sem(scores))
print(f'95% CI: [{ci[0]:.4f}, {ci[1]:.4f}]')

6. Bootstrap (Переменная выборка с возвращением)

import numpy as np
from sklearn.metrics import accuracy_score

# Оригинальная выборка
data = np.array([1, 2, 3, 4, 5])

# Bootstrap: берём с возвращением
np.random.seed(42)
bootstrap_samples = []
for i in range(1000):
    sample = np.random.choice(data, size=len(data), replace=True)
    bootstrap_samples.append(sample.mean())

bootstrap_samples = np.array(bootstrap_samples)

# Доверительный интервал из bootstrap
ci_lower = np.percentile(bootstrap_samples, 2.5)
ci_upper = np.percentile(bootstrap_samples, 97.5)

print(f'95% Bootstrap CI: [{ci_lower:.3f}, {ci_upper:.3f}]')

Практические стратегии

# ВСЕГДА делай это:

# 1. Проверь распределение
print(y.value_counts(normalize=True))

# 2. Используй stratified split
train_test_split(..., stratify=y)

# 3. Используй cross-validation
cross_val_score(..., cv=5)

# 4. Проверь на разных случайных seed
for seed in [42, 123, 456]:
    # обучи модель с seed
    
# 5. Если классы несбалансированы
# → используй class_weight='balanced'

# 6. Для критичных предсказаний
# → используй bootstrap для CI

# 7. Всегда отделяй test set
# → обучайся только на train

Математический взгляд

Ошибка предсказания = Bias² + Variance + Noise

Выборка добавляет:
- Bias: если выборка смещена (Selection Bias)
- Variance: если выборка маленькая (Random Sampling Error)

Мы минимизируем обе через:
- Хорошее распределение (stratification)
- Большой размер (n)
- Повторение (bootstrap, CV)

Практический пример: полный workflow

from sklearn.datasets import load_iris
from sklearn.model_selection import (
    train_test_split,
    cross_val_score,
    StratifiedKFold
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np

X, y = load_iris(return_X_y=True)

# 1. Stratified train-test split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)

# 2. Cross-validation на обучающей выборке
model = RandomForestClassifier(random_state=42)
scores = cross_val_score(
    model, X_train, y_train,
    cv=StratifiedKFold(n_splits=5),
    scoring='accuracy'
)

print(f'CV scores: {scores}')
print(f'Mean ± Std: {scores.mean():.4f} ± {scores.std():.4f}')

# 3. Final training и testing
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

# 4. Оценка
print(f'\nTest Accuracy: {model.score(X_test, y_test):.4f}')
print(f'\nClassification Report:\n{classification_report(y_test, y_pred)}')
print(f'\nConfusion Matrix:\n{confusion_matrix(y_test, y_pred)}')

# 5. Доверительный интервал для accuracy
from scipy import stats
ci = stats.binom.interval(
    0.95,
    len(y_test),
    model.score(X_test, y_test)
)
print(f'\n95% CI для Test Accuracy: [{ci[0]/len(y_test):.4f}, {ci[1]/len(y_test):.4f}]')

Заключение

Типы ошибок выборки:

  1. Random Sampling Error — неизбежен, уменьшается с √n
  2. Bias — систематическое смещение
  3. Selection Bias — предвзятость выбора
  4. Undersampling Bias — недостаточная выборка классов

Минимизация:

  • Увеличить размер выборки (√n закон)
  • Stratified sampling (сохранить распределение)
  • Weighted sampling (дать вес редким примерам)
  • Cross-validation (использовать несколько выборок)
  • Bootstrap (доверительные интервалы)
  • Проверить на разных random seeds

Правило:

Больше данных > Лучше алгоритм
Harder выборка > Гарантированный результат
Stratified > Random
CV > Single split