Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Регрессия

🎯 Цель

После прочтения этой главы:

  • Знаете, что такое Regression и когда его использовать
  • Понимаете разницу между Linear, Polynomial, Ridge, Lasso, ElasticNet
  • Правильно интерпретируете метрики regression (RMSE, MAE, R²)
  • Строите regression-модель на реальном dataset и выполняете serve в FastAPI

Что нужно изучить

  • Linear Regression — самый базовый алгоритм, знает каждый ML-инженер
  • Polynomial Regression — нелинейные изгибы
  • Regularization — Ridge (L2), Lasso (L1), ElasticNet (L1+L2)
  • Feature scaling и его влияние на regression
  • Multicollinearity — когда features зависят друг от друга
  • Assumptions — linearity, normality, homoscedasticity (на простом уровне)
  • Метрики — MSE, RMSE, MAE, R², MAPE
  • Robust regression — при наличии outliers

Библиотеки

pip install scikit-learn statsmodels
  • scikit-learn — основное
  • statsmodels — если нужны статистические детали (p-value, confidence interval)

Важные темы

Интуиция Linear Regression

Цель — найти прямую вида y = w₀ + w₁x₁ + w₂x₂ +... + wₙxₙ:

  • Как можно ближе к фактам (y_true)
  • Мера «близости» — обычно MSE(Mean Squared Error)

Оптимизация: **Ordinary Least Squares (OLS)**или Gradient Descent.

Зачем нужен Regularization?

Если features много (часто больше, чем наблюдений) или они зависят друг от друга, модель overfitting. Решение — regularization:

  • Ridge (L2):loss + λ * Σwᵢ² — приближает features к нулю
  • Lasso (L1):loss + λ * Σ|wᵢ|делает точно нулём некоторые features (feature selection)
  • **ElasticNet:**смесь обоих
λ kichik (0)         λ o'rta              λ katta
Overfitting          Optimal               Underfitting
(model murakkab)                          (model oddiy)

Linear assumptions

  1. Linearity — действительно ли связь между y и X линейная?
  2. Independence — наблюдения независимы (для time series это нарушается)
  3. Homoscedasticity — variance ошибок одинаковая (проверка через residual plot)
  4. Normality — ошибки в нормальном распределении (Q-Q plot)
  5. No multicollinearity — features не сильно связаны друг с другом (VIF)

**Совет backend dev:**Эти assumptions не всегда обязательны для бизнеса — random forest или XGBoost работают и без них. Но для красивого результата с Linear Regression полезно.

Метрики — когда какая?

МетрикаФормулаИнтерпретацияКогда
MAE`mean(y - ŷ)`
MSEmean((y - ŷ)²)Квадратичная ошибка — штрафует большие ошибкиДля loss function
RMSEsqrt(MSE)В единицах измеренияСамая распространённая
1 - SSres/SStot0..1 (или отрицательное) — какой % данных объяснёнОценка модели
MAPE`mean(y - ŷ/

Примеры кода

Linear Regression — California Housing

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import numpy as np

# 1. Data
data = fetch_california_housing(as_frame=True)
X, y = data.data, data.target  # y = медианная цена дома ($100k)

# 2. Split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 3. Pipeline
pipeline = Pipeline([
    ("scaler", StandardScaler()),
    ("lr", LinearRegression()),
])
pipeline.fit(X_train, y_train)

# 4. Predict и метрики
y_pred = pipeline.predict(X_test)

rmse = np.sqrt(mean_squared_error(y_test, y_pred))
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print(f"RMSE: {rmse:.3f}")  # 0.745
print(f"MAE:  {mae:.3f}")   # 0.533
print(f"R²:   {r2:.3f}")    # 0.576

# 5. Coefficients
coefs = dict(zip(X.columns, pipeline.named_steps["lr"].coef_))
for name, c in sorted(coefs.items(), key=lambda x: abs(x[1]), reverse=True):
    print(f"  {name}: {c:+.3f}")

Ridge, Lasso, ElasticNet

from sklearn.linear_model import Ridge, Lasso, ElasticNet

models = {
    "LinearRegression": LinearRegression(),
    "Ridge (L2)":       Ridge(alpha=1.0, random_state=42),
    "Lasso (L1)":       Lasso(alpha=0.01, random_state=42),
    "ElasticNet":       ElasticNet(alpha=0.01, l1_ratio=0.5, random_state=42),
}

for name, model in models.items():
    pipe = Pipeline([("scaler", StandardScaler()), ("model", model)])
    pipe.fit(X_train, y_train)
    score = pipe.score(X_test, y_test)  # R²
    print(f"{name:20s}  R² = {score:.4f}")

Polynomial Regression

from sklearn.preprocessing import PolynomialFeatures

poly_pipeline = Pipeline([
    ("poly", PolynomialFeatures(degree=2, include_bias=False)),
    ("scaler", StandardScaler()),
    ("lr", LinearRegression()),
])
poly_pipeline.fit(X_train, y_train)
print(f"Polynomial R²: {poly_pipeline.score(X_test, y_test):.4f}")

Hyperparameter tuning — GridSearchCV

from sklearn.model_selection import GridSearchCV

ridge_pipe = Pipeline([("scaler", StandardScaler()), ("ridge", Ridge())])

param_grid = {"ridge__alpha": [0.01, 0.1, 1.0, 10.0, 100.0]}

gs = GridSearchCV(ridge_pipe, param_grid, cv=5, scoring="neg_root_mean_squared_error")
gs.fit(X_train, y_train)

print(f"Best alpha: {gs.best_params_['ridge__alpha']}")
print(f"Best CV RMSE: {-gs.best_score_:.3f}")

Интеграция с backend

Price prediction API (FastAPI)

from fastapi import FastAPI
from pydantic import BaseModel, Field
import joblib
import numpy as np
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app):
    app.state.model = joblib.load("models/california_housing_v1.joblib")
    yield

app = FastAPI(lifespan=lifespan, title="California Housing Price Predictor")

class HouseFeatures(BaseModel):
    MedInc: float = Field(..., gt=0, description="Median income (10k USD)")
    HouseAge: float = Field(..., ge=0, le=100)
    AveRooms: float = Field(..., gt=0)
    AveBedrms: float = Field(..., gt=0)
    Population: float = Field(..., gt=0)
    AveOccup: float = Field(..., gt=0)
    Latitude: float
    Longitude: float

class PricePrediction(BaseModel):
    predicted_price_100k: float
    predicted_price_usd: float

@app.post("/predict/", response_model=PricePrediction)
def predict_price(features: HouseFeatures):
    X = np.array([[
        features.MedInc, features.HouseAge, features.AveRooms,
        features.AveBedrms, features.Population, features.AveOccup,
        features.Latitude, features.Longitude,
    ]])
    pred = float(app.state.model.predict(X)[0])
    return PricePrediction(
        predicted_price_100k=pred,
        predicted_price_usd=pred * 100_000,
    )

Logging и мониторинг (начальный уровень)

import logging
from datetime import datetime

logger = logging.getLogger("ml_service")

@app.post("/predict/", response_model=PricePrediction)
def predict_price(features: HouseFeatures):
    start = datetime.now()
    X = np.array([list(features.dict().values())])
    pred = float(app.state.model.predict(X)[0])
    duration_ms = (datetime.now() - start).total_seconds() * 1000
    
    logger.info(
        "prediction",
        extra={
            "input": features.dict(),
            "prediction": pred,
            "duration_ms": duration_ms,
            "model_version": "v1",
        },
    )
    return PricePrediction(predicted_price_100k=pred, predicted_price_usd=pred * 100_000)

Ресурсы

  • Scikit-learn Regressionscikit-learn.org/stable/supervised_learning.html#regression
  • StatQuest — Linear Regression(YouTube)
  • StatQuest — Ridge, Lasso, ElasticNet(3 отдельных видео)
  • “Introduction to Statistical Learning”(ISLR) — бесплатный PDF, глубокий regression
  • Andrew Ng — ML Specialization Course 1(Linear Regression module)

🏋️ Упражнения

🟢 Easy

  1. На sklearn.datasets.load_diabetes() обучите Linear Regression, выведите R².
  2. Попробуйте alpha = [0.001, 0.01, 0.1, 1, 10, 100] в Ridge, нарисуйте, как меняется R².
  3. Сравните train и test R² — когда возникает overfitting?

🟡 Medium

  1. California Housing: сравните Linear, Ridge, Lasso, ElasticNet, Polynomial в виде таблицы.
  2. Manual gradient descent: напишите Linear Regression своими руками через numpy (без sklearn).
  3. Residual analysis: визуализируйте y_test - y_pred. Есть ли паттерн? (homoscedasticity check)

🔴 Hard

  1. Production-сервис: модель California Housing в Docker + FastAPI + Postgres (для логирования предсказаний). Healthcheck, Prometheus metrics (request_count, prediction_duration).
  2. A/B test infra: одновременно serve две модели (v1 и v2), разделите трафик 50/50, собирайте метрики отдельно для каждой.

Capstone

notebooks/month-02/01_regression.ipynb:

  • Kaggle — House Prices: Advanced Regression Techniques competition
  • Сделайте первый submit
  • Цель: top 50% (RMSE log <= 0.16)
  • Шаги: EDA → preprocessing → baseline с Ridge → feature engineering → feature selection с Lasso → submission

✅ Чек-лист

  • Понимаю математическую формулу Linear Regression (y = wx + b)
  • Знаю разницу между Ridge и Lasso (L1 vs L2)
  • Знаю, когда использовать RMSE и MAE
  • Могу объяснить смысл R² бизнесу
  • Умею создавать Pipeline (scaler + model)
  • Делаю tune гиперпараметров через GridSearchCV
  • Сделал serve regression-модели в FastAPI
  • Сделал первый Kaggle submission

Переходим к Classification.