Условие
В регрессии 15 предикторов. Некоторые «гуляют» по знаку коэффициента в зависимости от выборки. Что не так и как чинить?
Решение
Multicollinearity
Сильная корреляция предикторов между собой. Симптомы:
- Коэффициенты нестабильны (большой SE).
- Знаки могут переключаться при изменении выборки.
- R² высокий, индивидуальные t-значения низкие.
- Коэффициенты противоречат интуиции (отрицательный там, где должен быть положительный).
VIF (Variance Inflation Factor)
Для каждого предиктора X_j регрессируем его на остальные:
R²_j = R² этой регрессии
VIF_j = 1 / (1 - R²_j)
Интерпретация:
- VIF = 1: нет collinearity.
- VIF 1-5: умеренная, обычно ок.
- VIF 5-10: высокая, разбираться.
- VIF > 10: серьёзная проблема.
from statsmodels.stats.outliers_influence import variance_inflation_factor
vif = pd.DataFrame()
vif['feature'] = X.columns
vif['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif.sort_values('VIF', ascending=False)Что делать
- Удалить один из коррелированных предикторов (тот, у которого нет уникальной информации).
- Объединить в один (например, height+weight → BMI).
- PCA — заменить группу коррелированных на компоненты.
- Ridge regression: L2 регуляризация стабилизирует оценки.
from sklearn.linear_model import Ridge
model = Ridge(alpha=1.0).fit(X, y)Ridge не убирает collinearity, но даёт стабильные оценки.
- Lasso: L1 регуляризация выбивает одну из коррелированных → автоматический feature selection.
Когда multicollinearity не страшна
- Для prediction (а не для интерпретации β) — collinearity не мешает. Модель прогнозирует одинаково хорошо.
- Если интересует совместный эффект группы, а не indvidual.
- Если коэффициент конкретного X не важен для решения.
Diagnostics
# Корреляции
import seaborn as sns
sns.heatmap(X.corr(), annot=True)
# Condition number
import numpy as np
print(np.linalg.cond(X.T @ X)) # > 30 — collinearityPerfect multicollinearity
Когда X_j = линейная комбинация других → OLS не считается (singular matrix). Часто это dummy trap: включили все категории dummy без drop_first. Решение: pd.get_dummies(drop_first=True).
Подводные камни
- VIF чувствителен к scaling (нет!), но коэффициенты — да. Standardize для интерпретации.
- VIF > 10 — рекомендация, не закон. На bedrock-предикторах (важных для модели) можно мириться.
- Ridge возвращает biased оценки. Это OK, если вариативность меньше — bias-variance trade-off.
- PCA скрывает интерпретацию: компоненты не имеют смысла. Только если интерпретация не нужна.
- Categorical с many levels часто даёт VIF > 10 для отдельных уровней — это норма.
Эталонный ответ
VIF = 1/(1−R²_j). >5 — разбираться, >10 — проблема. Лечение: удалить, объединить, PCA, Ridge/Lasso. Для prediction multicollinearity не мешает; для интерпретации β — критична.