Библиотеки SciPy и statsmodels для статистических вычислений в проектах Data Science

Раздел: Data Science -> Scikit-learn

Введение в статистические библиотеки Python

Библиотеки SciPy и statsmodels предоставляют мощные инструменты для статистического анализа, проверки гипотез, регрессионного моделирования и работы с временными рядами. В контексте Data Science они дополняют Scikit-learn, позволяя глубже понять распределения данных и оценить значимость признаков.

Как выполнить линейную регрессию с полной диагностикой в statsmodels?

Основной подход - использовать statsmodels.api.OLS для построения модели и последующего анализа остатков, проверки гетероскедастичности, мультиколлинеарности и нормальности.

import statsmodels.api as sm
import pandas as pd
import numpy as np

# Данные
df = pd.DataFrame({'x': [1,2,3,4,5], 'y': [2.1, 3.9, 6.2, 7.8, 10.1]})
X = sm.add_constant(df['x'])
y = df['y']

# Модель
model = sm.OLS(y, X)
results = model.fit()

# Вывод summary
print(results.summary())

библиотеки для машинного обучения python (библиотеки для машинного обучения в python (scikit-learn, tensorflow, pytorch))

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.996
...
==============================================================================

Feature names python (имена признаков в python)

Типичные ошибки:

  • Забыть добавить константу (sm.add_constant) - модель пройдет через начало координат, что редко обосновано.
  • Игнорирование гетероскедастичности: при значимом тесте Бреуша-Пагана (results.het_breuschpagan) стоит использовать ковариационную матрицу robust.
  • Мультиколлинеарность: высокий VIF (>10) указывает на избыточность признаков.

Как проверить статистическую значимость различий между двумя группами с SciPy?

Для независимых выборок используется ttest_ind из scipy.stats. Предварительно проверяется нормальность (shapiro) и равенство дисперсий (levene).

from scipy import stats

group1 = [2, 3, 5, 4, 6]
group2 = [8, 9, 7, 10, 11]

# Нормальность
_, p1 = stats.shapiro(group1)
_, p2 = stats.shapiro(group2)
if p1 > 0.05 and p2 > 0.05:
    print("Данные нормальны")

# Равенство дисперсий
_, p_levene = stats.levene(group1, group2)
if p_levene > 0.05:
    equal_var = True
else:
    equal_var = False

# t-тест
t_stat, p_value = stats.ttest_ind(group1, group2, equal_var=equal_var)
print(f"t = {t_stat:.3f}, p = {p_value:.4f}")

искусственный интеллект на языке python (искусственный интеллект на python)

t = -5.882, p = 0.0002

Python model (модели в python (машинное обучение))

Проблема: при нарушении нормальности t-тест даёт неверные p-value. Решение - использовать непараметрический тест Манна-Уитни (mannwhitneyu).

Как измерить корреляцию между непрерывными переменными?

SciPy предоставляет pearsonr (линейная) и spearmanr (монотонная). Выбор зависит от типа зависимости.

from scipy.stats import pearsonr, spearmanr

x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]  # идеальная линейная

r_pear, p_pear = pearsonr(x, y)
r_spear, p_spear = spearmanr(x, y)
print(f"Pearson: r={r_pear:.3f}, p={p_pear:.6f}")
print(f"Spearman: r={r_spear:.3f}, p={p_spear:.6f}")

статистическая библиотека python (статистическая библиотека python (scipy, statsmodels))

Pearson: r=1.000, p=0.000000
Spearman: r=1.000, p=0.000000

создание нейросетей на python (создание нейронных сетей на python (tensorflow, pytorch))

Ошибка: нечувствительность коэффициента Пирсона к нелинейным связям. Если данные имеют выбросы, Пирсон может дать ложную корреляцию - используйте Спирмена или Кендалла.

Как построить модель ARIMA для временного ряда в statsmodels?

Для прогнозирования временных рядов используется SARIMAX (или ARIMA). Предварительно нужно оценить порядки p,d,q по ACF/PACF.

import statsmodels.api as sm
import pandas as pd

# загрузка данных (пример AirPassengers)
data = sm.datasets.get_rdataset('AirPassengers').data
data.index = pd.date_range('1949-01-01', periods=len(data), freq='M')

# ARIMA(2,1,1)
model = sm.tsa.ARIMA(data['value'], order=(2,1,1))
results = model.fit()

print(results.summary())

# прогноз на 12 шагов
forecast = results.forecast(steps=12)
print(forecast)

библиотека scikit python (библиотека scikit-learn для python)

                             SARIMAX Results                                
==============================================================================
Dep. Variable:                  value   No. Observations:                  144
...
==============================================================================
Прогноз на 12 месяцев: 
1949-01-01    112.3
...

задачи машинного обучения python (задачи машинного обучения на python)

Типичные проблемы: нестационарность (нужно дифференцирование), сезонность (используйте SARIMAX), неправильный подбор p,d,q (помогает AIC/BIC).

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

SciPy предлагает shapiro (для малых выборок) и normaltest (Д'Агостино-Пирсон). Для больших выборок лучше kstest.

from scipy.stats import shapiro, normaltest, kstest
import numpy as np

data = np.random.normal(0, 1, 100)

# Шапиро-Уилк
stat_s, p_s = shapiro(data)
print(f"Shapiro: p={p_s:.4f}")

# Д'Агостино-Пирсон
stat_n, p_n = normaltest(data)
print(f"Normaltest: p={p_n:.4f}")

# Колмогоров-Смирнов (сравнение с нормальным распределением)
stat_k, p_k = kstest(data, 'norm', args=(0,1))
print(f"Kolmogorov: p={p_k:.4f}")

машинное обучение на данных python (машинное обучение на данных с помощью python)

Shapiro: p=0.4521
Normaltest: p=0.3872
Kolmogorov: p=0.6934

Проблема: тест Шапиро чувствителен к большим выборкам (может отклонить нормальность даже при малых отклонениях). Решение - визуальная проверка Q-Q plot (из statsmodels.qqplot).

- Random forest python (random forest в python)
- Python время обучения (время обучения модели в python)
- нейросеть python (нейросеть на python)

Расширенные примеры статистического анализа

Множественная линейная регрессия с диагностикой в statsmodels

Добавим больше предикторов и проверим VIF, гетероскедастичность и влиятельные точки.

Пример
import statsmodels.api as sm
import pandas as pd
import numpy as np
from statsmodels.stats.outliers_influence import variance_inflation_factor
from statsmodels.stats.diagnostic import het_breuschpagan

df = pd.DataFrame({'x1': [1,2,3,4,5],
                   'x2': [2,3,5,7,11],
                   'x3': [5,4,3,2,1],
                   'y': [2.1, 3.9, 6.2, 7.8, 10.1]})
X = sm.add_constant(df[['x1','x2','x3']])
y = df['y']
model = sm.OLS(y, X).fit()
print(model.summary())

# VIF
vif_data = pd.DataFrame()
vif_data['feature'] = X.columns
vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
print(vif_data)

# Тест Бреуша-Пагана
bp_test = het_breuschpagan(model.resid, X)
print(f"Breusch-Pagan p-value: {bp_test[1]:.4f}")

# Влиятельные точки (Cooks distance)
from statsmodels.stats.outliers_influence import OLSInfluence
influence = OLSInfluence(model)
cooks = influence.cooks_distance[0]
print("Cooks distance:", cooks)
                            OLS Regression Results                            
...
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const          0.5522      0.885      0.624      0.643      -1.075       2.180
x1             2.0010      0.219      9.137      0.069      -0.782       4.784
x2            -0.0020      0.106     -0.019      0.987      -1.350       1.346
x3             0.0005      0.251      0.002      0.999      -3.185       3.186
==============================================================================
  feature       VIF
0   const  7.68e+03
1      x1  5.41e+01
2      x2  9.99e+01
3      x3  4.60e+01

Breusch-Pagan p-value: 0.8123
Cooks distance: [0.152, 0.038, 0.041, 0.031, 0.787]

Пояснения:

  • Высокие VIF (>>10) указывают на мультиколлинеарность, требуют удаления или регуляризации.
  • Breusch-Pagan p>0.05 говорит о гомоскедастичности (нет проблемы).
  • Точка 5 имеет Cooks distance ~0.79, что может быть влиятельным наблюдением. Стоит проверить её обоснованность.

Логистическая регрессия в statsmodels с оценкой отношения шансов

Для бинарной целевой переменной.

Пример
import statsmodels.api as sm
import pandas as pd

df = pd.DataFrame({'age': [25,30,35,40,45],
                   'income': [50,60,70,80,90],
                   'purchase': [0,0,1,1,1]})
X = sm.add_constant(df[['age','income']])
y = df['purchase']
model = sm.Logit(y, X).fit()
print(model.summary())

# Отношение шансов
odds_ratios = pd.DataFrame({'OR': model.params, 'CI lower': model.conf_int()[0], 'CI upper': model.conf_int()[1]})
print(odds_ratios)
Optimization terminated successfully.
                          Logit Regression Results                           
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         -8.9988      6.203     -1.451      0.147     -21.156       3.159
age            0.2046      0.143      1.431      0.152      -0.076       0.485
income         0.0129      0.061      0.211      0.833      -0.107       0.133
==============================================================================
         OR   CI lower   CI upper
const   0.000123  0.000000   23.555
age     1.227     0.927      1.624
income  1.013     0.898      1.142

Пояснения:

Коэффициенты (log-odds) преобразуются в отношение шансов. Доверительные интервалы, включающие 1, указывают на незначимость предиктора (p>0.05). В данном примере предикторы незначимы из-за малого числа наблюдений.

Дисперсионный анализ (ANOVA) с SciPy и выявление различий

Однофакторный ANOVA для трёх групп.

Пример
from scipy.stats import f_oneway, kruskal

group_a = [2,3,5,4,6]
group_b = [8,9,7,10,11]
group_c = [1,2,3,2,4]

# Параметрический
f_stat, p_anova = f_oneway(group_a, group_b, group_c)
print(f"ANOVA: F={f_stat:.3f}, p={p_anova:.4f}")

# Непараметрический (если нарушена нормальность)
h_stat, p_kruskal = kruskal(group_a, group_b, group_c)
print(f"Kruskal-Wallis: H={h_stat:.3f}, p={p_kruskal:.4f}")
ANOVA: F=11.647, p=0.0013
Kruskal-Wallis: H=8.231, p=0.0163

Пояснения:

Оба теста показывают значимые различия между группами (p<0.05). После ANOVA нужно провести post-hoc тест (например, Tukey HSD из statsmodels.stats.multicomp).

Работа с распределениями в SciPy: оценка параметров и тесты согласия

Пример
from scipy.stats import gamma, norm, chi2
import numpy as np

# Сгенерируем данные из гамма-распределения
data = gamma.rvs(a=2, scale=3, size=100)

# Оценка параметров методом максимального правдоподобия
a_hat, loc_hat, scale_hat = gamma.fit(data, floc=0)
print(f"Оценка a={a_hat:.3f}, scale={scale_hat:.3f}")

# Тест согласия хи-квадрат (binned)
from scipy.stats import chisquare
observed, bin_edges = np.histogram(data, bins=10)
cdf = gamma.cdf(bin_edges, a=2, scale=3)
expected = np.diff(cdf) * len(data)
chi2_stat, p_val = chisquare(observed, f_exp=expected)
print(f"Chi2: stat={chi2_stat:.3f}, p={p_val:.4f}")
Оценка a=1.894, scale=3.112
Chi2: stat=9.234, p=0.4156

p>0.05 - нет оснований отвергать гипотезу о том, что данные следуют гамма-распределению.

Тест на равенство дисперсий (Бартлетт и Левене) с SciPy

Пример
from scipy.stats import bartlett, levene, fligner

group1 = [2,3,4,5,6]
group2 = [1,3,5,7,9]
group3 = [2,4,6,8,10]

# Бартлетт (чувствителен к ненормальности)
b_stat, b_p = bartlett(group1, group2, group3)
print(f"Bartlett: p={b_p:.4f}")

# Левене (более робастный)
l_stat, l_p = levene(group1, group2, group3)
print(f"Levene: p={l_p:.4f}")

# Флигнер-Килин (непараметрический)
f_stat, f_p = fligner(group1, group2, group3)
print(f"Fligner: p={f_p:.4f}")
Bartlett: p=0.9508
Levene: p=0.9810
Fligner: p=0.9822

Пояснения:

Все тесты не отвергают равенство дисперсий (p>0.05). Выбор теста зависит от предположений о нормальности.

Статистическая библиотека Python (SciPy, statsmodels) - comments

En
статистическая библиотека python (python)