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

Как проверить нормальность выборки?

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

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

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

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

Как проверить нормальность выборки?

Проверка нормальности выборки (normality test) — это статистический тест, определяющий, следует ли выборка нормальному (Гауссовскому) распределению. Это важно для многих статистических тестов и моделей, которые предполагают нормальность данных.

Визуальные методы

1. Гистограмма + нормальная кривая

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# Нормальные данные
data_normal = np.random.normal(loc=100, scale=15, size=1000)

# Ненормальные данные (экспоненциальное распределение)
data_skewed = np.random.exponential(scale=50, size=1000)

fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# Нормальные данные
axes[0].hist(data_normal, bins=30, density=True, alpha=0.7, label='Data')
mu, sigma = data_normal.mean(), data_normal.std()
x = np.linspace(mu - 4*sigma, mu + 4*sigma, 100)
axes[0].plot(x, stats.norm.pdf(x, mu, sigma), 'r-', label='Normal PDF')
axes[0].set_title('Нормальные данные')
axes[0].legend()

# Ненормальные данные
axes[1].hist(data_skewed, bins=30, density=True, alpha=0.7, label='Data')
axes[1].set_title('Ненормальные данные (асимметричные)')
axes[1].legend()

plt.tight_layout()
plt.show()

2. Q-Q Plot (Quantile-Quantile Plot)

from scipy import stats
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# Нормальные данные
stats.probplot(data_normal, dist="norm", plot=axes[0])
axes[0].set_title('Q-Q Plot: Нормальные данные')
axes[0].text(0.05, 0.95, 'Близко к прямой = нормальные',
             transform=axes[0].transAxes, verticalalignment='top')

# Ненормальные данные
stats.probplot(data_skewed, dist="norm", plot=axes[1])
axes[1].set_title('Q-Q Plot: Ненормальные данные')
axes[1].text(0.05, 0.95, 'Отклоняется от прямой = ненормальные',
             transform=axes[1].transAxes, verticalalignment='top')

plt.tight_layout()
plt.show()

print("Интерпретация Q-Q Plot:")
print("- Если точки лежат близко к прямой → нормальное распределение")
print("- Если точки отклоняются → ненормальное распределение")
print("- S-образный график → положительная асимметрия")
print("- Z-образный график → отрицательная асимметрия")

Статистические тесты

1. Shapiro-Wilk тест (лучший для n < 5000)

from scipy.stats import shapiro

# Нормальные данные
statistic_normal, p_value_normal = shapiro(data_normal)
print(f"Shapiro-Wilk тест (нормальные данные):")
print(f"  Статистика: {statistic_normal:.4f}")
print(f"  P-value: {p_value_normal:.6f}")
if p_value_normal > 0.05:
    print(f"  Вывод: Данные нормальны (p > 0.05)\n")
else:
    print(f"  Вывод: Данные НЕ нормальны (p < 0.05)\n")

# Ненормальные данные
statistic_skewed, p_value_skewed = shapiro(data_skewed)
print(f"Shapiro-Wilk тест (ненормальные данные):")
print(f"  Статистика: {statistic_skewed:.4f}")
print(f"  P-value: {p_value_skewed:.6f}")
if p_value_skewed > 0.05:
    print(f"  Вывод: Данные нормальны (p > 0.05)")
else:
    print(f"  Вывод: Данные НЕ нормальны (p < 0.05)")

2. Kolmogorov-Smirnov тест

from scipy.stats import kstest

# Сравниваем с нормальным распределением
statistic_ks, p_value_ks = kstest(
    data_normal,
    'norm',
    args=(data_normal.mean(), data_normal.std())
)
print(f"Kolmogorov-Smirnov тест:")
print(f"  Статистика: {statistic_ks:.4f}")
print(f"  P-value: {p_value_ks:.6f}")
if p_value_ks > 0.05:
    print(f"  Вывод: Данные нормальны")
else:
    print(f"  Вывод: Данные НЕ нормальны")

3. Anderson-Darling тест

from scipy.stats import anderson

result = anderson(data_normal, dist='norm')
print(f"Anderson-Darling тест:")
print(f"  Статистика: {result.statistic:.4f}")
print(f"  Критические значения: {result.critical_values}")
print(f"  Уровни значимости: {result.significance_level}%")

if result.statistic < result.critical_values[2]:  # 5% уровень значимости
    print(f"  Вывод: Данные нормальны")
else:
    print(f"  Вывод: Данные НЕ нормальны")

4. D'Agostino-Pearson тест

from scipy.stats import normaltest

# Комбинирует эксцесс и асимметрию
statistic, p_value = normaltest(data_normal)
print(f"D'Agostino-Pearson тест:")
print(f"  Статистика: {statistic:.4f}")
print(f"  P-value: {p_value:.6f}")
if p_value > 0.05:
    print(f"  Вывод: Данные нормальны")
else:
    print(f"  Вывод: Данные НЕ нормальны")

5. Jarque-Bera тест

from scipy.stats import jarque_bera

statistic, p_value = jarque_bera(data_normal)
print(f"Jarque-Bera тест:")
print(f"  Статистика: {statistic:.4f}")
print(f"  P-value: {p_value:.6f}")
if p_value > 0.05:
    print(f"  Вывод: Данные нормальны")
else:
    print(f"  Вывод: Данные НЕ нормальны")

Статистики асимметрии и эксцесса

from scipy.stats import skew, kurtosis

# Асимметрия (Skewness)
skewness = skew(data_normal)
print(f"Асимметрия (Skewness): {skewness:.4f}")
print(f"  |skew| < 0.5: симметричное распределение (близко к нормальному)")
print(f"  0.5 < |skew| < 1: умеренная асимметрия")
print(f"  |skew| > 1: сильная асимметрия")

# Эксцесс (Kurtosis)
excess_kurtosis = kurtosis(data_normal)
print(f"\nИзбыточный эксцесс (Excess Kurtosis): {excess_kurtosis:.4f}")
print(f"  Для нормального распределения: 0")
print(f"  > 0: более острый пик (leptokurtic)")
print(f"  < 0: более плоский (platykurtic)")
print(f"  |kurt| < 0.5: близко к нормальному")

# Пример с ненормальными данными
print(f"\nАсимметрия ненормальных данных: {skew(data_skewed):.4f}")
print(f"Эксцесс ненормальных данных: {kurtosis(data_skewed):.4f}")

Комплексная проверка

from scipy.stats import shapiro, kstest, jarque_bera, skew, kurtosis
import pandas as pd

def check_normality(data, name="Data"):
    """Комплексная проверка нормальности"""
    print(f"\n{'='*50}")
    print(f"Проверка нормальности: {name}")
    print(f"{'='*50}")
    
    # Размер выборки
    n = len(data)
    print(f"\nРазмер выборки: {n}")
    
    # Статистики
    print(f"\nОписательная статистика:")
    print(f"  Среднее: {np.mean(data):.4f}")
    print(f"  Медиана: {np.median(data):.4f}")
    print(f"  Стд. отклонение: {np.std(data):.4f}")
    
    # Асимметрия и эксцесс
    skewness = skew(data)
    excess_kurtosis = kurtosis(data)
    print(f"\nАсимметрия (Skewness): {skewness:.4f}")
    print(f"Эксцесс (Kurtosis): {excess_kurtosis:.4f}")
    
    # Тесты
    print(f"\nСтатистические тесты:")
    
    if n < 5000:
        stat_sw, p_sw = shapiro(data)
        print(f"  Shapiro-Wilk: статистика={stat_sw:.4f}, p-value={p_sw:.6f}")
    
    stat_kb, p_kb = jarque_bera(data)
    print(f"  Jarque-Bera: статистика={stat_kb:.4f}, p-value={p_kb:.6f}")
    
    stat_dagostino, p_dagostino = normaltest(data)
    print(f"  D'Agostino: статистика={stat_dagostino:.4f}, p-value={p_dagostino:.6f}")
    
    # Итоговый вывод
    print(f"\nВывод:")
    tests_normal = []
    if n < 5000 and p_sw > 0.05:
        tests_normal.append("Shapiro-Wilk")
    if p_kb > 0.05:
        tests_normal.append("Jarque-Bera")
    if p_dagostino > 0.05:
        tests_normal.append("D'Agostino")
    
    if len(tests_normal) >= 2:
        print(f"  ✓ Данные НОРМАЛЬНЫ (большинство тестов указывают на нормальность)")
        return True
    else:
        print(f"  ✗ Данные НЕ НОРМАЛЬНЫ (большинство тестов отклоняют нормальность)")
        return False

# Использование
check_normality(data_normal, "Нормальные данные")
check_normality(data_skewed, "Ненормальные данные")

Что делать если данные не нормальны?

# 1. Логарифмирование (для асимметричных данных)
data_log = np.log1p(data_skewed)  # log(1 + x)
check_normality(data_log, "После логарифмирования")

# 2. Квадратный корень
data_sqrt = np.sqrt(data_skewed)
check_normality(data_sqrt, "После sqrt трансформации")

# 3. Степенные трансформации (Box-Cox)
from scipy.stats import boxcox
data_boxcox, lambda_param = boxcox(data_skewed + 1)
print(f"\nBox-Cox параметр lambda: {lambda_param:.4f}")
check_normality(data_boxcox, "После Box-Cox трансформации")

# 4. Используй непараметрические тесты
# Вместо t-test → Mann-Whitney U test
# Вместо ANOVA → Kruskal-Wallis test

Рекомендации

Используй Shapiro-Wilk если:

  • Размер выборки < 5000
  • Нужна наибольшая мощность теста

Используй Jarque-Bera если:

  • Больших размеров выборка
  • Есть выбросы

Используй визуальные методы если:

  • Нужно понять ТИП нарушения нормальности
  • Есть мультимодальность

Помни:

  • На больших выборках даже небольшие отклонения будут статистически значимы
  • Важнее смотреть на величину эффекта, чем на p-value
  • Для машинного обучения нормальность менее критична, чем для классической статистики