← Назад к вопросам
Как проверить нормальность выборки?
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
- Для машинного обучения нормальность менее критична, чем для классической статистики