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

Как идет обучение линейной модели?

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

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

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

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

Обучение линейной модели

Обучение линейной модели — это процесс нахождения оптимальных коэффициентов (весов), которые минимизируют ошибку предсказаний. Несмотря на кажущуюся простоту, это фундаментальный процесс, понимание которого критично для работы с более сложными моделями.

Формулировка задачи

Для линейной регрессии модель имеет вид:

y_pred = w0 + w1*x1 + w2*x2 + ... + wn*xn
y_pred = w^T * x

где:

  • w — вектор весов (coefficients) размера (n+1,)
  • x — вектор признаков (features) размера (n+1,), где первый элемент всегда 1 (для смещения/intercept)
  • y — целевая переменная

Два основных подхода к обучению

Подход 1: Аналитическое решение (Normal Equation)

Для линейной регрессии существует закрытая форма решения. Минимизируя Mean Squared Error (MSE):

L(w) = ||Xw - y||^2 = (Xw - y)^T(Xw - y)

Производная по w:

∂L/∂w = 2X^T(Xw - y) = 0

Решение (Normal Equation):

w = (X^T*X)^(-1) * X^T * y

Это прямое вычисление без итераций:

import numpy as np
from sklearn.linear_model import LinearRegression

# Способ 1: Scikit-learn (использует numpy.linalg.lstsq)
model = LinearRegression()
model.fit(X_train, y_train)
print(f"Веса: {model.coef_}")
print(f"Intercept: {model.intercept_}")

# Способ 2: Явное вычисление
X_with_bias = np.c_[np.ones(X_train.shape[0]), X_train]
w = np.linalg.inv(X_with_bias.T @ X_with_bias) @ X_with_bias.T @ y_train
y_pred = X_with_bias @ w

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

  • Точное решение за один вычислительный шаг
  • Не требует выбора learning rate
  • Не нужны итерации

Недостатки:

  • Требует вычисления матрицы (X^T*X)^(-1), что O(n^3) по сложности
  • Неустойчива численно, если матрица плохо обусловлена
  • Работает только для регрессии, не для классификации
  • Для больших n (>10000) становится неэффективной

Подход 2: Итеративная оптимизация (Gradient Descent)

Вместо прямого решения, используем итеративный алгоритм:

1. Инициализировать w случайными значениями
2. Вычислить предсказания: y_pred = X * w
3. Вычислить ошибки: error = y_pred - y
4. Вычислить градиент: ∇L = X^T * error / N
5. Обновить веса: w = w - α * ∇L
6. Повторить шаги 2–5 до сходимости
import numpy as np

class LinearRegressionGD:
    def __init__(self, learning_rate=0.01, n_iterations=1000):
        self.lr = learning_rate
        self.n_iter = n_iterations
        self.w = None
        self.losses = []
    
    def fit(self, X, y):
        n_samples, n_features = X.shape
        self.w = np.zeros(n_features)
        
        for _ in range(self.n_iter):
            # Predictions
            y_pred = X @ self.w
            
            # Compute loss (MSE)
            loss = np.mean((y_pred - y)**2)
            self.losses.append(loss)
            
            # Compute gradient
            gradient = (2 / n_samples) * X.T @ (y_pred - y)
            
            # Update weights
            self.w -= self.lr * gradient
        
        return self
    
    def predict(self, X):
        return X @ self.w

# Пример использования
model = LinearRegressionGD(learning_rate=0.01, n_iterations=100)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

Сравнение подходов

АспектNormal EquationGradient Descent
Скорость вычисленияO(n^3)O(n) за итерацию
Требует learning rateНетДа
Работает для больших nПлохоХорошо
Количество итераций1Много
ПрименимостьТолько регрессияРегрессия, классификация, DL

Практический пример: Полный pipeline

from sklearn.linear_model import LinearRegression, SGDRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
import matplotlib.pyplot as plt

# Генерируем данные
X = np.random.randn(100, 1)
y = 3 * X.squeeze() + 2 + np.random.randn(100) * 0.5

# Разбиваем
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Подход 1: Normal Equation
model_ne = LinearRegression()
model_ne.fit(X_train, y_train)
y_pred_ne = model_ne.predict(X_test)
mse_ne = mean_squared_error(y_test, y_pred_ne)
print(f"Normal Equation - MSE: {mse_ne:.3f}, Coef: {model_ne.coef_[0]:.3f}, Intercept: {model_ne.intercept_:.3f}")

# Подход 2: SGD (mini-batch gradient descent)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

model_sgd = SGDRegressor(loss='squared_error', max_iter=1000, learning_rate='optimal', eta0=0.01)
model_sgd.fit(X_train_scaled, y_train)
y_pred_sgd = model_sgd.predict(X_test_scaled)
mse_sgd = mean_squared_error(y_test, y_pred_sgd)
print(f"SGD - MSE: {mse_sgd:.3f}, Coef: {model_sgd.coef_[0]:.3f}")

# Визуализация
plt.scatter(X_test, y_test, label='Actual')
plt.plot(X_test, y_pred_ne, 'r-', label='Normal Equation')
plt.plot(X_test, y_pred_sgd, 'g--', label='SGD')
plt.legend()
plt.show()

Регуляризация при обучении

Для предотвращения переобучения добавляются штрафы за большие веса:

Ridge Regression (L2 регуляризация)

L(w) = ||Xw - y||^2 + λ*||w||^2
from sklearn.linear_model import Ridge

model = Ridge(alpha=1.0)  # alpha — параметр регуляризации
model.fit(X_train, y_train)

Lasso Regression (L1 регуляризация)

L(w) = ||Xw - y||^2 + λ*||w||_1
from sklearn.linear_model import Lasso

model = Lasso(alpha=0.1)  # Меньший alpha → меньше регуляризации
model.fit(X_train, y_train)

Elastic Net (L1 + L2)

from sklearn.linear_model import ElasticNet

model = ElasticNet(alpha=0.1, l1_ratio=0.5)
model.fit(X_train, y_train)

Диагностика обучения

Learning Curve

Показывает, как меняется ошибка с количеством данных:

from sklearn.model_selection import learning_curve

train_sizes, train_scores, val_scores = learning_curve(
    LinearRegression(), X, y, cv=5,
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='neg_mean_squared_error'
)

plt.plot(train_sizes, -train_scores.mean(axis=1), label='Train')
plt.plot(train_sizes, -val_scores.mean(axis=1), label='Validation')
plt.legend()
plt.show()

Convergence Curve

Показывает сходимость gradient descent:

import matplotlib.pyplot as plt

plt.plot(model.losses)
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.title('Convergence of Gradient Descent')
plt.show()

Важные моменты

  1. Нормализация: Признаки должны быть нормализованы перед обучением, особенно для GD
  2. Сходимость: GD может не сойтись если learning rate слишком большой
  3. Масштабируемость: Normal Equation O(n^3), GD O(n) за итерацию
  4. Регуляризация: Обязательна для плохо обусловленных задач

Обучение линейной модели — это простой, но мощный процесс, который лежит в основе современного машинного обучения.

Как идет обучение линейной модели? | PrepBro