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

Как работает линейная регрессия?

1.2 Junior🔥 191 комментариев
#Машинное обучение

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

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

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

Линейная регрессия: полное объяснение

Основная идея

Линейная регрессия — это метод для предсказания непрерывного значения (y) на основе одной или нескольких входных переменных (x). Модель предполагает, что зависимость между x и y линейная.

Математическое определение

Для простой линейной регрессии (одна переменная):

y = β₀ + β₁*x + ε

Где:
y        = целевая переменная (continuous value)
x        = входная переменная
β₀       = intercept (смещение, точка где линия пересекает ось Y)
β₁       = slope (наклон, как y меняется при изменении x на 1 единицу)
ε        = ошибка (error term, шум)

Для множественной линейной регрессии (несколько переменных):

y = β₀ + β₁*x₁ + β₂*x₂ + ... + βₙ*xₙ + ε

В матричной форме:
y = X * β + ε

Где:
X        = матрица признаков (n_samples × n_features)
β        = вектор коэффициентов (n_features × 1)
ε        = вектор ошибок (n_samples × 1)

Как работает обучение

Цель: найти коэффициенты β₀, β₁, ..., βₙ, которые минимизируют ошибку.

Функция потерь (Loss function) — Mean Squared Error (MSE):

MSE = (1/n) * Σ(y_pred - y_actual)²
    = (1/n) * Σ(β₀ + β₁*x₁ + ... + βₙ*xₙ - y)²

Где:
n = количество примеров
Σ = сумма по всем примерам

Мы хотим найти β, которые минимизируют эту функцию.

Методы решения

1. Аналитическое решение (Closed-form) — Normal Equation

Это математическое решение, которое находит оптимальные β напрямую:

# Normal Equation
β = (X^T * X)^(-1) * X^T * y

Где:
X^T      = транспонированная матрица X
(X^T*X)^(-1) = обратная матрица

Пример в Python:

import numpy as np
from numpy.linalg import inv

# Добавляем column of 1s для intercept
X = np.column_stack([np.ones(n), X_original])

# Вычисляем коэффициенты
beta = inv(X.T @ X) @ X.T @ y

Преимущества:

  • Находит оптимальное решение за один раз
  • Быстро для малого количества признаков

Недостатки:

  • Если матрица X^T*X не invertible (сингулярна) — падает
  • Сложно для больших наборов данных (O(n³) сложность)
  • Чувствительна к multicollinearity

2. Градиентный спуск (Gradient Descent)

Итеративный метод: мы начинаем с случайных β и постепенно их улучшаем.

# Gradient Descent

Шаг 1: Инициализируем β случайно (или нулями)

Шаг 2: Для каждой итерации t = 1, 2, ..., T:
    a) Вычисляем gradient (производную MSE по β):
       dL/dβ = (2/n) * X^T * (X*β - y)
    
    b) Обновляем β в направлении противоположном градиенту:
       β ← β - α * dL/dβ
       
       Где α = learning rate (как быстро мы обновляем)

Шаг 3: Повторяем, пока loss не сходится

Варианты градиентного спуска:

# Batch Gradient Descent
# Используем ВСЕ данные для одного обновления β
beta = beta - learning_rate * gradient(X, y, beta)
# Результат: плавная, стабильная сходимость, но медленно

# Stochastic Gradient Descent (SGD)
# Используем ОДИН random пример для обновления
for i in range(n):
    random_idx = random.randint(0, n-1)
    x_i = X[random_idx]
    y_i = y[random_idx]
    beta = beta - learning_rate * gradient(x_i, y_i, beta)
# Результат: быстро, но шумно, может не сойтись

# Mini-batch Gradient Descent (лучший вариант)
batch_size = 32
for batch_idx in range(0, n, batch_size):
    X_batch = X[batch_idx:batch_idx+batch_size]
    y_batch = y[batch_idx:batch_idx+batch_size]
    beta = beta - learning_rate * gradient(X_batch, y_batch, beta)
# Результат: хороший баланс между скоростью и стабильностью

Преимущества:

  • Работает для больших датасетов
  • Понятный процесс
  • Гибкий (легко добавить регуляризацию)

Недостатки:

  • Нужно выбрать learning rate
  • Может застрять в локальном минимуме (но для линейной регрессии не существует локальных минимумов)

Реализация в Python

from sklearn.linear_model import LinearRegression
import numpy as np

# Создаём модель
model = LinearRegression()

# Обучаем на data
model.fit(X_train, y_train)

# Предсказываем
y_pred = model.predict(X_test)

# Коэффициенты
print("Intercept (β₀):", model.intercept_)
print("Coefficients (β₁, β₂, ...):", model.coef_)

Требования и предположения

Для хорошей работы линейной регрессии нужны:

  1. Linearity — связь между X и y должна быть линейной

    • Проверка: scatter plot
    • Если нелинейная — добавь polynomial features
  2. Independence — примеры должны быть независимы

    • Проверка: ACF plot (для временных рядов)
    • Если зависимы — используй другие методы (ARIMA, LSTM)
  3. Homoscedasticity — дисперсия ошибок должна быть постоянной

    • Проверка: residuals plot
    • Если нарушено — используй weighted regression
  4. Normality — ошибки должны распределяться нормально

    • Проверка: Q-Q plot
    • Если нарушено — может помочь log-трансформация y
  5. No multicollinearity — признаки не должны быть сильно скоррелированы

    • Проверка: VIF (Variance Inflation Factor) < 5
    • Если нарушено — удали коррелированные признаки или используй Ridge/Lasso

Регуляризация

Проблема: если у нас много признаков, модель может переобучиться

Ridge Regression (L2):

Loss = MSE + λ * Σ(β²)  # Штрафуем большие коэффициенты
model = Ridge(alpha=1.0)

Lasso Regression (L1):

Loss = MSE + λ * Σ|β|   # Может обнулить коэффициенты
model = Lasso(alpha=1.0)

Elastic Net (L1 + L2):

Loss = MSE + λ₁ * Σ|β| + λ₂ * Σ(β²)
model = ElasticNet(alpha=1.0, l1_ratio=0.5)

Метрики качества

from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error

# MSE (Mean Squared Error) — средняя квадратная ошибка
mse = mean_squared_error(y_test, y_pred)

# RMSE (Root MSE) — корень из MSE, в тех же единицах что y
rmse = np.sqrt(mse)

# MAE (Mean Absolute Error) — средняя абсолютная ошибка
mae = mean_absolute_error(y_test, y_pred)

# R² score — доля дисперсии, которую объясняет модель (0-1)
r2 = r2_score(y_test, y_pred)
# R² = 0.9 → модель объясняет 90% дисперсии

Когда использовать

  • Используй когда:

    • Зависимость между x и y линейная
    • Нужна интерпретируемая модель
    • Мало данных или признаков
    • Нужна быстрая модель
  • Не используй когда:

    • Зависимость нелинейная
    • Очень много признаков (используй Ridge/Lasso)
    • Нужна максимальная точность (tree-based методы обычно лучше)