- BrainTools - https://www.braintools.ru -
В предыдущей статье разобрали простую линейную регрессию [1], где целевая переменная зависела от одного фактора, но в реальной жизни всё сложнее. Представьте, что мы прогнозируем стоимость квартиры: она зависит не только от площади, но и от количества комнат, этажа, района, года постройки, наличия парковки и десятков других важных характеристик.
Множественная линейная регрессия – это естественное расширение простой линейной регрессии на случай с несколькими независимыми переменными (предикторами), и она позволяет:
Учитывать комплекс факторов – строить прогнозы на основе множества признаков одновременно,
Оценивать изолированное влияние каждого предиктора, контролируя эффект остальных переменных,
Повышать точность прогнозов по сравнению с одномерными моделями.
В этой статье мы разберем математическую основу метода и реализуем его с помощью Python и библиотеки scikit-learn.
Если простая линейная регрессия описывается уравнением прямой, то множественная регрессия стремится описать гиперплоскость в многомерном пространстве.
Начнем с уравнения, модель множественной линейной регрессии с n предикторами записывается следующим образом:
Y=β0+β1X1+β2X2+⋯+βnXn+ϵ
Где:
Y — зависимая переменная (то, что мы предсказываем)
X1, X2, X_n — независимые переменные (те самые предикторы)
β0 — интерсепт (свободный член), это, по сути, значение Y, когда все предикторы равны нулю
βi — коэффициенты регрессии, он нтерпретируются как ожидаемое изменение Y при увеличении Xi на одну единицу, но, при условии, что все остальные предикторы остаются неизменными
ϵ — случайная ошибка [2] (шум), которую модель не может объяснить
Как и в случае с простой регрессией, для нахождения оптимальных коэффициентов β используется метод наименьших квадратов, он минимизирует сумму квадратов вертикальных расстояний (остатков ϵ) между фактическими значениями Y и предсказанными моделью значениями. Решение этой задачи в матричном виде выглядит так:
β^=(XTX)−1XTyβ^
Где:
X — матрица признаков (с добавленным столбцом единиц для интерсепта)
y — вектор целевых значений
Прежде чем строить модель множественной регрессии, необходимо выполнить ряд важных подготовительных шагов.
Критически важный этап в машинном обучении [3] – это разделение данных на обучающую и тестовую выборки. Модель обучается на одной части данных, а проверяется на другой, которую она “не видела”, это помогает оценить, насколько хорошо модель будет работать с новыми данными, и избежать переобучения (overfitting), когда модель “запоминает” шум в обучающих данных вместо выявления общей закономерности.
Линейная регрессия работает с числами, если у вас есть категориальные признаки (например, город или тип недвижимости), их необходимо преобразовать, самый распространенный способ – это One-Hot Encoding (создание фиктивных переменных), когда каждая категория превращается в отдельную колонку из 0 и 1.
Хотя линейная регрессия не требует масштабирования в той же степени, что методы, основанные на градиентном спуске, стандартизация признаков может быть полезна для интерпретации коэффициентов и ускорения вычислений. Обычно используют StandardScaler для приведения признаков к нулевому среднему и единичной дисперсии.
Перейдем к практике, рассмотрим построение модели на классическом датасете Advertising, он содержит данные о продажах (Sales) в зависимости от бюджетов на рекламу в трёх каналах: TV, Radio и Newspaper.
Техническое задание: Предсказать объем продаж на основе затрат на рекламу в различных медиа.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
from sklearn.preprocessing import PolynomialFeatures
# Настройка визуализации
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("husl")
# Загрузка полного датасета Advertising (200 наблюдений)
url = "https://www.tu-chemnitz.de/mathematik/numa/lehre/ds-2018/exercises/Advertising.csv"
df = pd.read_csv(url)
# Проверяем и удаляем лишний столбец индекса, если он есть
if 'Unnamed: 0' in df.columns:
df = df.drop('Unnamed: 0', axis=1)
# Проверяем названия столбцов и приводим к стандартному виду
df.columns = [col.strip().lower() for col in df.columns]
if 'tv' in df.columns and 'radio' in df.columns and 'newspaper' in df.columns and 'sales' in df.columns:
df.columns = ['TV', 'Radio', 'Newspaper', 'Sales']
print("Первые 5 строк данных:")
print(df.head())
print(f"nРазмер данных: {df.shape}")
print(f"nНазвания столбцов: {df.columns.tolist()}")
Результат выполнения:
Первые 5 строк данных:
TV Radio Newspaper Sales
0 230.1 37.8 69.2 22.1
1 44.5 39.3 45.1 10.4
2 17.2 45.9 69.3 9.3
3 151.5 41.3 58.5 18.5
4 180.8 10.8 58.4 12.9
Размер данных: (200, 4)
Перед построением модели важно понять структуру данных и взаимосвязи между признакам
# Статистика данных
print("Статистика данных:")
print(df.describe())
# Корреляционная матрица
correlation_matrix = df.corr()
print("nКорреляция с целевой переменной Sales:")
print(correlation_matrix['Sales'].sort_values(ascending=False))
# Визуализация корреляционной матрицы
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, fmt='.3f')
plt.title('Корреляционная матрица признаков', fontsize=14)
plt.tight_layout()
plt.show()
# Парные графики зависимостей
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
for idx, feature in enumerate(['TV', 'Radio', 'Newspaper']):
axes[idx].scatter(df[feature], df['Sales'], alpha=0.6, color='steelblue')
axes[idx].set_xlabel(feature, fontsize=12)
axes[idx].set_ylabel('Sales', fontsize=12)
axes[idx].set_title(f'{feature} vs Sales', fontsize=14)
plt.tight_layout()
plt.show()
Статистика данных:
TV Radio Newspaper Sales
count 200.00000 200.000000 200.000000 200.000000
mean 147.04250 23.264000 30.554000 14.022500
std 85.85426 14.846809 21.778621 5.217457
min 0.70000 0.000000 0.300000 1.600000
25% 74.37500 9.975000 12.750000 10.375000
50% 149.75000 22.900000 25.750000 12.900000
75% 218.82500 36.525000 45.100000 17.400000
max 296.40000 49.600000 114.000000 27.000000
Корреляция с целевой переменной Sales:
Sales 1.000000
TV 0.782224
Radio 0.576223
Newspaper 0.228299
Name: Sales, dtype: float64

Подготовка данных для обучения
# Определяем признаки (X) и целевую переменную (y)
X = df[['TV', 'Radio', 'Newspaper']]
y = df['Sales']
# Разделение данных на обучающую и тестовую выборки (80% / 20%)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"Размер обучающей выборки: {X_train.shape[0]} samples")
print(f"Размер тестовой выборки: {X_test.shape[0]} samples")
Результат выполнения:
Размер обучающей выборки: 160 samples
Размер тестовой выборки: 40 samples
# Создание и обучение модели
model = LinearRegression()
model.fit(X_train, y_train)
# Вывод коэффициентов модели
print("=" * 50)
print("Коэффициенты модели множественной регрессии:")
print("=" * 50)
print(f"Интерсепт (Intercept): {model.intercept_:.4f}")
print("nКоэффициенты при признаках:")
for name, coef in zip(X.columns, model.coef_):
print(f" {name:10} : {coef:.4f}")
Результат выполнения:
==================================================
Коэффициенты модели множественной регрессии:
==================================================
Интерсепт (Intercept): 2.9791
Коэффициенты при признаках:
TV : 0.0447
Radio : 0.1892
Newspaper : 0.0028
Коэффициенты модели дают важную информацию о влиянии каждого фактора:
TV (0.0447): При увеличении бюджета на TV-рекламу на 1 тысячу долларов, продажи вырастут в среднем на 44.7 единиц, при неизменных бюджетах Radio и Newspaper.
Radio (0.1892): При увеличении бюджета на радио-рекламу на 1 тысячу долларов, продажи вырастут в среднем на 189.2 единиц это наибольший эффект среди всех каналов.
Newspaper (0.0028): Коэффициент близок к нулю и статистически незначим. Это означает, что при наличии TV и Radio в модели, реклама в газетах практически не влияет на продажи.
# Прогноз на тестовой выборке
y_pred = model.predict(X_test)
# Метрики качества
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print("n" + "=" * 50)
print("Оценка качества модели:")
print("=" * 50)
print(f"Среднеквадратичная ошибка (MSE): {mse:.2f}")
print(f"Корень из MSE (RMSE): {rmse:.2f}")
print(f"Средняя абсолютная ошибка (MAE): {mae:.2f}")
print(f"Коэффициент детерминации (R²): {r2:.4f}")
Результат выполнения:
==================================================
Оценка качества модели:
==================================================
Среднеквадратичная ошибка (MSE): 3.17
Корень из MSE (RMSE): 1.78
Средняя абсолютная ошибка (MAE): 1.46
Коэффициент детерминации (R²): 0.8994
Интерпретация метрик:
|
Метрика |
Значение |
Интерпретация |
|---|---|---|
|
R² |
0.8994 |
Модель объясняет 89.94% дисперсии продаж — это отличный результат |
|
RMSE |
1.78 |
В среднем модель ошибается на 1.78 тысяч единицпродаж |
|
MAE |
1.46 |
Средняя абсолютная ошибка составляет 1.46 тысяч единиц продаж |
Что означают эти цифры на практике:
Если предсказанный объем продаж составляет, например, 15 тысяч единиц, то реальное значение будет находиться в интервале 15 ± 1.78 тысяч единиц (если ориентироваться на RMSE) или 15 ± 1.46 тысяч единиц (если ориентироваться на MAE).
Разница между RMSE (1.78) и MAE (1.46) указывает на наличие небольшого количества ошибок с большим отклонением, которые RMSE “штрафует” сильнее из-за возведения в квадрат.
# Сравнение реальных и предсказанных значений
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.7)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('Фактические значения Sales')
plt.ylabel('Предсказанные значения Sales')
plt.title('Сравнение фактических и предсказанных значений')
plt.tight_layout()
plt.show()
# Анализ остатков
residuals = y_test - y_pred
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Гистограмма остатков
axes[0].hist(residuals, bins=10, edgecolor='black', alpha=0.7)
axes[0].axvline(x=0, color='red', linestyle='--')
axes[0].set_xlabel('Остатки')
axes[0].set_ylabel('Частота')
axes[0].set_title('Распределение остатков')
# Остатки vs предсказанные значения
axes[1].scatter(y_pred, residuals, alpha=0.7)
axes[1].axhline(y=0, color='red', linestyle='--')
axes[1].set_xlabel('Предсказанные значения')
axes[1].set_ylabel('Остатки')
axes[1].set_title('Остатки vs предсказанные значения')
plt.tight_layout()
plt.show()


Результат выполнения:
График 1: Сравнение фактических и предсказанных значений
На графике видно, что точки плотно группируются вокруг идеальной линии (красный пунктир), что говорит о хорошем качестве прогноза. Отклонения от линии невелики и распределены равномерно.
График 2: Распределение остатков (гистограмма)
Гистограмма остатков показывает распределение ошибок модели. Остатки приблизительно следуют нормальному распределению с центром в нуле, что подтверждает корректность модели.
График 3: Остатки vs предсказанные значения
Точки распределены случайным образом вокруг нулевой линии, без явных закономерностей. Это указывает на гомоскедастичность (постоянство дисперсии ошибок).
Давайте теперь еще сравним, насколько множественная регрессия лучше, чем одномерные модели:
# Простая регрессия только на TV
model_tv = LinearRegression()
model_tv.fit(X_train[['TV']], y_train)
y_pred_tv = model_tv.predict(X_test[['TV']])
r2_tv = r2_score(y_test, y_pred_tv)
# Простая регрессия только на Radio
model_radio = LinearRegression()
model_radio.fit(X_train[['Radio']], y_train)
y_pred_radio = model_radio.predict(X_test[['Radio']])
r2_radio = r2_score(y_test, y_pred_radio)
# Простая регрессия только на Newspaper
model_newspaper = LinearRegression()
model_newspaper.fit(X_train[['Newspaper']], y_train)
y_pred_newspaper = model_newspaper.predict(X_test[['Newspaper']])
r2_newspaper = r2_score(y_test, y_pred_newspaper)
print("=" * 50)
print("Сравнение моделей:")
print("=" * 50)
print(f"R² только TV: {r2_tv:.4f}")
print(f"R² только Radio: {r2_radio:.4f}")
print(f"R² только Newspaper: {r2_newspaper:.4f}")
print(f"R² множественная регрессия: {r2:.4f}")
Результат выполнения:
==================================================
Сравнение моделей:
==================================================
R² только TV: 0.6767
R² только Radio: 0.2634
R² только Newspaper: 0.0299
R² множественная регрессия: 0.8994
Анализ результатов:
Модель только с TV-рекламой объясняет 67.67% дисперсии продаж
Модель только с Radio-рекламой объясняет 26.34% дисперсии
Модель только с Newspaper-рекламой объясняет лишь 2.29% дисперсии
Множественная регрессия, учитывающая TV, Radio и Newspaper одновременно, объясняет 89.94% дисперсии
Таким образом, использование нескольких факторов позволяет значительно повысить качество прогноза R² увеличился по сравнению с лучшей одномерной моделью.
Множественная регрессия называется линейной из-за линейности по коэффициентам, но это не запрещает использовать нелинейные преобразования признаков.
Полиномиальная регрессия – это классический пример, когда мы добавляем квадраты или кубы существующих признаков, чтобы уловить криволинейные зависимости .
from sklearn.preprocessing import PolynomialFeatures
# Создаем полиномиальные признаки степени 2
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
# Разделяем данные с полиномиальными признаками
X_train_poly, X_test_poly, y_train, y_test = train_test_split(
X_poly, y, test_size=0.2, random_state=42
)
# Обучаем модель на полиномиальных признаках
model_poly = LinearRegression()
model_poly.fit(X_train_poly, y_train)
# Оценка качества
y_pred_poly = model_poly.predict(X_test_poly)
r2_poly = r2_score(y_test, y_pred_poly)
print("=" * 50)
print("Полиномиальная регрессия (degree=2):")
print("=" * 50)
print(f"Количество признаков после преобразования: {X_poly.shape[1]}")
print(f"R² полиномиальной модели: {r2_poly:.4f}")
print(f"R² линейной модели: {r2:.4f}")
Результат выполнения:
==================================================
Полиномиальная регрессия (degree=2):
==================================================
Количество признаков после преобразования: 9
R² полиномиальной модели: 0.9869
R² линейной модели: 0.8994
Анализ результатов:
– Полиномиальная модель (со степенью 2) использует 9 признаков вместо исходных 3;
– R² увеличился с 0.8994 до 0.9869 – модель объясняет уже 98.69% дисперсии;
– Однако на малых выборках (всего 10 наблюдений) есть риск переобучения, так как на каждый признак приходится всего 1 наблюдение.
Важно: Добавление слишком большого количества степеней может привести к переобучению. Контролировать сложность модели помогают кросс-валидация и метрика Adjusted R².
Множественная линейная регрессия – это мощный и интерпретируемый инструмент анализа данных и ее ключевые преимущества:
Интерпретируемость – благодаря ей мы можем сказать: “при увеличении X₁ на единицу, Y изменится на β₁, при неизменных остальных факторах”
Учет комплексных зависимостей – возможность моделировать влияние множества факторов одновременно
Фундамент для сложных методов – понимание принципов множественной регрессии необходимо для освоения Ridge, LASSO и нейронных сетей
Ключевые моменты, которые нужно запомнить:
|
Аспект |
Рекомендация |
|---|---|
|
Мультиколлинеарность |
Сильная корреляция между предикторами может делать оценки коэффициентов ненадежными |
|
Качество данных |
Модель чувствительна к выбросам — их нужно выявлять и обрабатывать |
|
Размер выборки |
Чем больше признаков, тем больше данных нужно для надежной оценки |
|
Сложность модели |
Больше признаков ≠ лучше. Используйте тестовую выборку для проверки |
Освоив множественную регрессию, вы получите фундамент для понимания более сложных алгоритмов машинного обучения. В следующих статьях мы рассмотрим методы регуляризации (Ridge и LASSO), которые помогают бороться с переобучением и отбирать наиболее важные признаки.
Датасет Advertising на Kaggle [4]
✔️Больше про будни и задачи аналитика данных в моем тг канале 🌸Таня и Данные📊 [5]
Автор: TanyaVSdannye
Источник [6]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/27734
URLs in this post:
[1] линейную регрессию: https://habr.com/ru/articles/1004248/
[2] ошибка: http://www.braintools.ru/article/4192
[3] обучении: http://www.braintools.ru/article/5125
[4] Датасет Advertising на Kaggle: https://www.kaggle.com/datasets/brsahan/advertising-spend-vs-sales/
[5] 🌸Таня и Данные📊: https://t.me/+ngceWABYnHZhOWUy
[6] Источник: https://habr.com/ru/articles/1015102/?utm_campaign=1015102&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.