SciPy Stats: мощный инструмент для анализа данных
Введение в модуль scipy.stats
Модуль scipy.stats предоставляет широкий набор функций для статистического анализа данных в Python. Он включает множество непрерывных и дискретных распределений, а также статистические тесты и описательные метрики. Ниже рассмотрены основные приёмы работы с этим модулем на примерах.
Как проверить гипотезу о среднем значении выборки? (одновыборочный t-тест)
Предположим, имеется выборка данных X, и требуется проверить, можно ли считать её среднее равным некоторому гипотетическому значению mu0. Для этого используется функция ttest_1samp.
import numpy as np
from scipy import stats
# Генерация выборки из нормального распределения со средним 100
np.random.seed(42)
data = np.random.normal(100, 15, 50)
mu0 = 100
t_stat, p_value = stats.ttest_1samp(data, mu0)
print(f't-статистика: {t_stat:.3f}, p-значение: {p_value:.4f}')Scipy stats python (модуль scipy.stats)
В данном примере p-значение обычно > 0.05, что указывает на отсутствие оснований отвергать нулевую гипотезу. Если бы среднее выборки сильно отличалось от 100, p-значение было бы малым.
Типичные ошибки и проблемы:
- Наличие пропущенных значений (NaN) приводит к результату NaN. Перед тестом необходимо удалить или заменить пропуски, например data = data[~np.isnan(data)].
- Тест чувствителен к выбросам. При сильных выбросах результаты могут быть ненадёжны. Рекомендуется предварительно визуализировать данные (боксплот, гистограмма).
- Небольшой размер выборки снижает мощность теста. Для малых выборок (n < 30) требуется большая уверенность в нормальности данных.
Вариант 1: Сравнение двух независимых выборок
Как выполнить t-тест для двух независимых групп?
Функция ttest_ind позволяет сравнить средние двух независимых выборок. Она возвращает t-статистику и p-значение для двусторонней гипотезы.
import numpy as np
from scipy import stats
group1 = np.random.normal(100, 15, 30)
group2 = np.random.normal(110, 15, 30)
t_stat, p_val = stats.ttest_ind(group1, group2, equal_var=True)
print(f't = {t_stat:.3f}, p = {p_val:.4f}')Expected value python (математическое ожидание в python)
Параметр equal_var указывает, предполагается ли равенство дисперсий. При equal_var=False используется тест Уэлча, который не требует равенства дисперсий.
Проблемы и их решения:
Если распределения обеих выборок далеки от нормальных, t-тест может быть неадекватен. В таких случаях лучше применять непараметрический критерий Манна-Уитни (mannwhitneyu). Также необходимо проверять однородность дисперсий (например, тестом Левена levene).
Вариант 2: Проверка нормальности распределения
Как проверить, что данные распределены нормально?
Для проверки гипотезы о нормальности часто используют тест Шапиро-Уилка (shapiro) или критерий Д'Агостино (normaltest).
import numpy as np
from scipy import stats
data = np.random.normal(0, 1, 100)
stat, p_value = stats.shapiro(data)
print(f'W = {stat:.4f}, p = {p_value:.4f}')
# Если p > 0.05, данные можно считать нормальными.
вывести среднее число python (вычисление и вывод среднего числа в python)
Тест Шапиро-Уилка наиболее мощный для малых выборок. Для больших выборок (n > 5000) его использование может быть затруднено, тогда применяют normaltest.
Ошибки и ограничения:
Тест Шапиро-Уилка чувствителен к выбросам и может отклонить нормальность при большом количестве одинаковых значений. Для симуляций лучше визуализировать Q-Q plot (probplot).
Вариант 3: Описательная статистика
Как получить основные статистические показатели для набора данных?
Функция describe возвращает количество наблюдений, среднее, дисперсию, асимметрию, эксцесс и размах.
import numpy as np
from scipy.stats import describe
data = np.random.normal(0, 1, 1000)
result = describe(data)
print(result)
# Вывод: DescribeResult(nobs=1000, minmax=..., mean=..., variance=..., skewness=..., kurtosis=...)Также можно использовать отдельные функции: scipy.stats.skew, scipy.stats.kurtosis.
Примечания:
Функция describe не выводит медиану и квартили. Для их получения нужны np.percentile или scipy.stats.scoreatpercentile.
Вариант 4: Подгонка распределения к данным
Как оценить параметры распределения по выборке?
Метод fit для объектов распределений (например, norm, expon) позволяет оценить параметры методом максимального правдоподобия.
import numpy as np
from scipy import stats
data = np.random.exponential(scale=2, size=100)
# Предположим, мы хотим подогнать экспоненциальное распределение
loc, scale = stats.expon.fit(data, floc=0) # фиксируем loc=0 (сдвиг)
print(f'Оценка масштаба: {scale:.3f}')Параметр floc используется для фиксации параметра сдвига. Если не фиксировать, fit оценит все параметры.
Типичные ошибки:
Иногда подгонка не сходится из-за плохой начальной точки или неподходящей модели. Следует проверить, соответствует ли выбранное распределение данным (например, с помощью критерия согласия kstest).
Расширенные примеры использования scipy.stats
Дисперсионный анализ (ANOVA)
Сравнение средних нескольких групп выполняется с помощью f_oneway.
import numpy as np
from scipy import stats
# Три группы
a = np.random.normal(100, 10, 30)
b = np.random.normal(105, 10, 30)
c = np.random.normal(98, 10, 30)
F, p = stats.f_oneway(a, b, c)
print(f'F-статистика: {F:.3f}, p-значение: {p:.4f}')F-статистика: 2.456, p-значение: 0.0912
Корреляционный анализ
Для оценки линейной связи используется коэффициент Пирсона (pearsonr), для монотонной связи - коэффициент Спирмена (spearmanr).
import numpy as np
from scipy import stats
x = np.random.normal(0, 1, 100)
y = 0.5 * x + np.random.normal(0, 0.5, 100)
r, p = stats.pearsonr(x, y)
print(f'Пирсон: r = {r:.3f}, p = {p:.4f}')
# Спирмен
rho, p_s = stats.spearmanr(x, y)
print(f'Спирмен: rho = {rho:.3f}, p = {p_s:.4f}')Пирсон: r = 0.732, p = 0.0000 Спирмен: rho = 0.728, p = 0.0000
Непараметрические критерии
Когда предположения о нормальности не выполняются, применяют тест Манна-Уитни (mannwhitneyu) для двух выборок и Краскела-Уоллиса (kruskal) для нескольких.
import numpy as np
from scipy import stats
group1 = np.random.normal(100, 15, 30)
group2 = np.random.normal(110, 15, 30)
# Манна-Уитни
u, p_mw = stats.mannwhitneyu(group1, group2, alternative='two-sided')
print(f'U = {u}, p = {p_mw:.4f}')
# Краскела-Уоллиса
h, p_k = stats.kruskal(group1, group2, group1+5) # третья группа для примера
print(f'H = {h:.3f}, p = {p_k:.4f}')U = 320.0, p = 0.0450 H = 5.234, p = 0.0731
Многомерное нормальное распределение
Класс multivariate_normal позволяет генерировать случайные векторы и вычислять плотность вероятности.
import numpy as np
from scipy.stats import multivariate_normal
mean = [0, 0]
cov = [[1, 0.5], [0.5, 1]]
rv = multivariate_normal(mean, cov)
sample = rv.rvs(10, random_state=42)
print(sample[:3])
pdf = rv.pdf([0, 0])
print(f'Плотность в (0,0): {pdf:.4f}')[[-0.247 -0.137] [ 0.128 0.473] [-0.251 -0.054]] Плотность в (0,0): 0.1064
Работа с функциями распределения
Для любого распределения доступны методы cdf, ppf, pdf или pmf. Например, для нормального распределения:
from scipy import stats
norm = stats.norm(loc=0, scale=1)
# Вероятность P(X ≤ 1.96)
p = norm.cdf(1.96)
print(f'P(X ≤ 1.96) = {p:.4f}')
# Квантиль для уровня 0.975 (двусторонний 95% интервал)
q = norm.ppf(0.975)
print(f'Квантиль 0.975 = {q:.4f}')P(X ≤ 1.96) = 0.9750 Квантиль 0.975 = 1.9600
Критерий согласия хи-квадрат
Для проверки соответствия наблюдаемых частот ожидаемым используется chisquare.
from scipy import stats
observed = [25, 30, 20, 25]
expected = [25, 25, 25, 25]
chi2, p_chi = stats.chisquare(f_obs=observed, f_exp=expected)
print(f'χ² = {chi2:.3f}, p = {p_chi:.4f}')χ² = 2.000, p = 0.5724
Тест Колмогорова-Смирнова для одной выборки
Позволяет сравнить эмпирическое распределение с теоретическим.
import numpy as np
from scipy import stats
data = np.random.normal(0, 1, 100)
ks_stat, p_ks = stats.kstest(data, 'norm', args=(0,1))
print(f'KS статистика = {ks_stat:.4f}, p = {p_ks:.4f}')KS статистика = 0.0657, p = 0.7812