Что такое мультиколлинеарность

Коротко

Мультиколлинеарность — когда две или несколько фич (независимых переменных) в регрессии сильно коррелируют между собой.

Это ломает интерпретацию модели: вы не знаете, какая из коррелированных фич реально влияет на target.

Пример

Модель предсказывает зарплату аналитика:

  • years_of_experience
  • years_since_graduation

Эти две фичи почти одинаковые (r=0.95). Модель не может разобрать, какая из них «настоящая причина».

Коэффициенты могут стать нестабильными:

  • В одной выборке: experience = +10000, since_graduation = -5000.
  • В другой: experience = -3000, since_graduation = +13000.

Сумма — одинаковая, но интерпретация каждого — мусор.

Почему это плохо

1. Нестабильные коэффициенты

Меняются с каждой выборкой. Нельзя доверять.

2. Огромные стандартные ошибки

Confidence interval коэффициента широкий → «значимость» плывёт.

3. Плохая интерпретация

«Experience влияет на зарплату на +X₽» — неверно, если есть since_graduation в модели.

4. Но predictions могут быть OK

Модель всё ещё предсказывает неплохо, просто коэффициенты врут. Для пониманияfeature importance — проблема.

Если хочется сразу закрепить тему на практике — открой тренажёр в Telegram. 10 минут в день — и синтаксис в пальцах.

Как обнаружить

1. Корреляционная матрица

corr = df.corr()
import seaborn as sns
sns.heatmap(corr, annot=True, cmap='coolwarm')

Ищем пары с |r| > 0.7.

2. VIF (Variance Inflation Factor)

Более точный способ:

from statsmodels.stats.outliers_influence import variance_inflation_factor

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

Интерпретация:

  • VIF = 1 — нет мультиколлинеарности.
  • VIF < 5 — ОК.
  • VIF 5-10 — подозрительно.
  • VIF > 10 — серьёзная multicollinearity.

3. Condition Number

np.linalg.cond(X.values)

30 — проблема. > 100 — серьёзная.

Как лечить

1. Удалить одну из коррелированных

Самое простое:

# Если experience и since_graduation коррелируют на 0.95 — оставить одну
features = ['experience', 'education', 'location']  # without since_graduation

2. Объединить в одну

Сумма, среднее, главная компонента:

df['education_experience'] = df['experience'] + df['since_graduation']

3. PCA (Principal Component Analysis)

Преобразовать коррелированные в независимые компоненты:

from sklearn.decomposition import PCA

pca = PCA(n_components=5)
X_pca = pca.fit_transform(X)

Но интерпретация компонент теряется.

4. Ridge / Lasso регрессия

Регуляризация «гасит» коэффициенты коррелированных фич:

from sklearn.linear_model import Ridge, Lasso

ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)

5. Увеличить выборку

Больше данных → стабильнее коэффициенты. Но не всегда помогает.

Типичные источники

1. Дублирующие фичи

price_usd и price_rub с фиксированным курсом — жесткая колинеарность.

2. Связанные временные

year, month, day_of_year — если все включить, плохо.

3. One-hot encoding без dropping first

# ❌ Dummy trap: все колонки линейно зависимы
pd.get_dummies(df['color'])  # red, blue, green

# ✅ Dropping first — убирает колинеарность
pd.get_dummies(df['color'], drop_first=True)  # blue, green

4. Сумма = total

Если a + b + c = total, и total тоже в модели — колинеарность.

Когда игнорировать

Если модель используется только для prediction (не интерпретации) — мультиколлинеарность не мешает.

В ML-моделях (XGBoost, Random Forest) — они внутри справляются.

В линейной / логистической регрессии — нужно лечить.

Чтобы не только читать теорию, но и решать реальные задачи — загляните в бот Карьерника. Там по каждой теме подборка вопросов с разборами.

Пример полного анализа

import pandas as pd
import numpy as np
from statsmodels.stats.outliers_influence import variance_inflation_factor
import statsmodels.api as sm

df = pd.read_csv('data.csv')
features = ['x1', 'x2', 'x3', 'x4', 'x5']
X = df[features]
y = df['target']

# Correlation matrix
print(X.corr())

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

# Если VIF > 10 для x2 — удаляем
features_clean = ['x1', 'x3', 'x4', 'x5']
X_clean = df[features_clean]

# Fit регрессию
model = sm.OLS(y, sm.add_constant(X_clean)).fit()
print(model.summary())

На собеседовании

Вопросы:

  • «Что такое мультиколлинеарность?»
  • «Как обнаружить?» (corr matrix, VIF).
  • «Как решить?» (удалить, merge, PCA, Ridge).
  • «Влияет на predictions?» (нет, на интерпретацию да).

Читайте также

FAQ

Насколько strong correlation ≠ problem?

0.7+ обычно считают проблемой. 0.5-0.7 — borderline.

VIF обязательно считать?

Для интерпретационных моделей — да. Для ML-predictions — нет.

Multicollinearity в ML?

В tree-based (XGBoost, RF) — неважно. В линейных — важно.

Можно ли игнорировать?

Если важны predictions, не интерпретация — да.