← Назад к вопросам

Как мультиколлинеарность влияет на линейную регрессию?

2.0 Middle🔥 161 комментариев
#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как мультиколлинеарность влияет на линейную регрессию?

Мультиколлинеарность — проблема, когда два или несколько признаков в модели сильно коррелируют друг с другом. Это серьезно влияет на качество и интерпретируемость линейной регрессии.

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

Простой пример:

  • Признак 1: зарплата в долларах
  • Признак 2: зарплата в евро

Эти признаки практически идентичны (линейная трансформация), между ними отношение 1:0.85. Это мультиколлинеарность.

import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression

# Создаём коррелирующие признаки
np.random.seed(42)
n = 100

X1 = np.random.randn(n)
X2 = X1 + 0.01 * np.random.randn(n)  # почти идентичен X1

y = 2*X1 + 3*X2 + np.random.randn(n)  # истинные коэффициенты: 2 и 3

X = np.column_stack([X1, X2])
model = LinearRegression()
model.fit(X, y)

print(f"Истинные коэффициенты: w1=2, w2=3")
print(f"Оценённые коэффициенты: w1={model.coef_[0]:.2f}, w2={model.coef_[1]:.2f}")
print(f"Корреляция между X1 и X2: {np.corrcoef(X1, X2)[0, 1]:.2f}")

Результат: коэффициенты будут очень неустойчивыми и непредсказуемыми!

Проблемы мультиколлинеарности

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

Малые изменения в данных приводят к большим изменениям в weights:

# Проблема: нестабильность
X_train = np.array([[1, 1], [1.01, 1], [1, 1.01], [2, 2], [2.01, 2]])
y_train = np.array([2, 2.1, 2.1, 4, 4.1])

model1 = LinearRegression().fit(X_train, y_train)
print(f"Коэффициенты модель 1: {model1.coef_}")

# Добавим одно наблюдение
X_train2 = np.vstack([X_train, [[2, 2]]])
y_train2 = np.hstack([y_train, [4]])

model2 = LinearRegression().fit(X_train2, y_train2)
print(f"Коэффициенты модель 2: {model2.coef_}")
# Коэффициенты сильно отличаются!

2. Трудная интерпретация коэффициентов

Вес признака становится бессмысленным, потому что его эффект смешан с эффектом коррелирующего признака:

# Что означает коэффициент?
# На практике непонятно, какой признак действительно влияет на y

# Пример: зарплата сотрудника
features = {
    "years_of_experience": 10,        # коэффициент: 5000
    "age": 35,                        # коэффициент: -3000 (!!)
    # age и years_of_experience коррелируют (~0.9)
    # Отрицательный коэффициент для age — артефакт мультиколлинеарности!
}

3. Высокая дисперсия оценок параметров

Математически, дисперсия коэффициентов:

Var(β) = σ² * (X^T * X)^(-1)

Если X^T * X близка к singular (не обратима), дисперсия стремится к бесконечности.

4. Переобучение (overfitting)

Модель может "запомнить" случайный шум вместо истинных закономерностей.

Как обнаружить мультиколлинеарность?

1. Матрица корреляции

import pandas as pd
from sklearn.datasets import load_diabetes

data = load_diabetes()
X = pd.DataFrame(data.data, columns=data.feature_names)

# Матрица корреляции
corr_matrix = X.corr()
print(corr_matrix)

# Визуализировать
import seaborn as sns
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')

Если есть коэффициенты корреляции > 0.8 или < -0.8 между признаками — проблема.

2. VIF (Variance Inflation Factor)

Лучший метод количественно измерить мультиколлинеарность.

from statsmodels.stats.outliers_influence import variance_inflation_factor

# 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.sort_values('VIF', ascending=False))

# Интерпретация VIF:
# VIF < 5: хорошо
# 5 < VIF < 10: умеренная мультиколлинеарность (требует внимания)
# VIF > 10: серьёзная мультиколлинеарность (нужно действовать)

3. Число обусловленности (Condition Number)

from numpy.linalg import cond

X_scaled = (X - X.mean()) / X.std()  # нормализируем
cond_number = cond(X_scaled.T @ X_scaled)

print(f"Condition number: {cond_number:.2f}")
# < 30: хорошо
# 30-100: умеренная мультиколлинеарность
# > 100: серьёзная мультиколлинеарность

Как решить проблему мультиколлинеарности?

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

# Если age и years_of_experience коррелируют на 0.95
# Оставляем только один (например, experience более информативен)

X_reduced = X.drop(columns=['age'])
model = LinearRegression().fit(X_reduced, y)

2. Feature Engineering (объединить признаки)

# Вместо двух коррелирующих признаков создать один
X['experience_age_ratio'] = X['years_of_experience'] / X['age']
X = X.drop(columns=['years_of_experience', 'age'])

3. Ridge регрессия (L2 регуляризация)

Добавляет штраф за большие коэффициенты:

from sklearn.linear_model import Ridge

model = Ridge(alpha=1.0)  # alpha контролирует силу регуляризации
model.fit(X, y)

# Ridge стабилизирует коэффициенты, но не удаляет признаки
print(model.coef_)  # более разумные значения

4. Lasso регрессия (L1 регуляризация)

Может обнулять коэффициенты (автоматический feature selection):

from sklearn.linear_model import Lasso

model = Lasso(alpha=0.1)
model.fit(X, y)

# Некоторые коэффициенты будут ровно 0
print(model.coef_)  # один из коррелирующих признаков обнулится

5. Principal Component Analysis (PCA)

Трансформировать признаки в некоррелирующие компоненты:

from sklearn.decomposition import PCA

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

model = LinearRegression().fit(X_pca, y)

# PCA убирает мультиколлинеарность, но признаки теперь не интерпретируемы

Практическая рекомендация

# Полный workflow
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge, Lasso
from sklearn.model_selection import cross_val_score

# 1. Проверить на мультиколлинеарность
vif = variance_inflation_factor(X.values, 0)
if vif > 10:
    print("Серьёзная мультиколлинеарность!")

# 2. Выбрать подход
if high_interpretability_needed:
    # Удалить коррелирующие признаки или комбинировать их
    X_cleaned = remove_high_vif_features(X, threshold=10)
    model = LinearRegression().fit(X_cleaned, y)
else:
    # Использовать регуляризацию
    model = Ridge(alpha=1.0)  # или Lasso
    model.fit(X, y)

# 3. Валидировать
scores = cross_val_score(model, X, y, cv=5)
print(f"Cross-val R²: {scores.mean():.3f} +/- {scores.std():.3f}")

Итог

Мультиколлинеарность в линейной регрессии:

  • Делает коэффициенты нестабильными и неинтерпретируемыми
  • Увеличивает дисперсию оценок
  • Приводит к переобучению
  • Решения: удаление признаков, Ridge/Lasso регуляризация, PCA, feature engineering
  • Когда важна интерпретируемость: удалять признаки
  • Когда важна точность: использовать Ridge/Lasso