Документация Engee
Notebook

Множественная линейная регрессия: прогнозирование расхода топлива автомобилей

В данном примере демонстрируется построение модели множественной линейной регрессии для прогнозирования расхода топлива автомобилей на основе их мощности и массы с использованием метода наименьших квадратов. Исходные данные взяты из датасета mtcars.

Базовая формула множественной линейной регрессии:

где:

расход топлива (л/100км),

нормализованная мощность двигателя,

нормализованная масса автомобиля,

свободный член (intercept),

коэффициент при мощности,

коэффициент при массе,

случайная ошибка.

Датасет mtcars - это классический набор данных о характеристиках 32 автомобилей 1973-74 годов выпуска, собранный из журнала Motor Trend. Датасет содержит информацию о расходе топлива, мощности двигателя, весе, количестве цилиндров и других технических характеристиках автомобилей.

Этот датасет широко используется в академических курсах по статистике, эконометрике и машинному обучению как стандартный пример для демонстрации регрессионного анализа.

Установка и запуск необходимых библиотек:

In [ ]:
Pkg.add(["RDatasets", "Statistics", "DataFrames"])
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using RDatasets        # Для загрузки данных
using Plots            # Визуализация
using Statistics       # Статистические функции
using DataFrames       # Работа с таблицами

Загрузка и преобразование данных:

In [ ]:
cars = dataset("datasets", "mtcars")  # Загружаем встроенный набор данных

# Выбираем предикторы и целевую переменную
cars[:, "weight_tons"] = cars[:, "WT"] .* 0.453592  # Вес: из тысяч фунтов в тонны
X_raw = cars[:, ["HP", "weight_tons"]]   # Мощность (hp) и вес (тонны)
cars[:, "fuel_l100km"] = 235.22 ./ cars[:, "MPG"]  # Расход: из миль/галлон в л/100км
y = cars[:, "fuel_l100km"]               # Расход топлива (л/100км)

# Преобразуем названия колонок для ясности
rename!(X_raw, [:HP, :weight_tons])
Out[0]:
32×2 DataFrame
7 rows omitted
RowHPweight_tons
Int64Float64
11101.18841
21101.30408
3931.05233
41101.4583
51751.56036
61051.56943
72451.61932
8621.44696
9951.42881
101231.56036
111231.56036
121801.84612
131801.6919
⋮⋮⋮
21971.1181
221501.59664
231501.55809
242451.74179
251751.74406
26660.877701
27910.970687
281130.686285
292641.43789
301751.25645
313351.61932
321091.26099

Загружаем классический датасет mtcars и конвертируем американские единицы измерения в метрические для лучшего понимания. Вес переводим из тысяч фунтов в тонны (умножение на 0.453592), а расход топлива - из миль на галлон в литры на 100 км. Выбираем мощность и вес как предикторы для прогнозирования расхода топлива.

Нормализация и подготовка матриц:

In [ ]:
normalize(x) = (x .- mean(x)) ./ std(x)
X = hcat(ones(nrow(X_raw)), normalize(X_raw.HP), normalize(X_raw.weight_tons))

y = float(y)  # Преобразуем в вещественные числа
Out[0]:
32-element Vector{Float64}:
 11.200952380952382
 11.200952380952382
 10.316666666666666
 10.99158878504673
 12.578609625668449
 12.995580110497237
 16.44895104895105
  9.64016393442623
 10.316666666666666
 12.251041666666667
 13.214606741573034
 14.34268292682927
 13.596531791907514
  ⋮
 10.94046511627907
 15.175483870967742
 15.475000000000001
 17.685714285714283
 12.251041666666667
  8.616117216117216
  9.046923076923077
  7.737500000000001
 14.887341772151897
 11.94010152284264
 15.681333333333333
 10.99158878504673

Применяем z-score нормализацию к предикторам, приводя их к стандартному виду (среднее=0, стандартное отклонение=1). Это улучшает численную устойчивость алгоритма и делает коэффициенты сравнимыми между собой. Формируем матрицу X, добавляя столбец единиц для свободного члена регрессии.

Решение методом наименьших квадратов:

In [ ]:
#Реализация МНК (аналитическое решение)
β = inv(X'X) * X'y  # (XᵀX)⁻¹Xᵀy
Out[0]:
3-element Vector{Float64}:
 12.755331278523013
  1.2062112633104227
  2.643362422121514

Применяем классическую формулу МНК для получения оптимальных коэффициентов регрессии. Эта формула минимизирует сумму квадратов остатков и дает единственное аналитическое решение для линейной регрессии. Результат β содержит три коэффициента: свободный член, коэффициент при мощности и коэффициент при массе.

Предсказания и оценка качества модели:

In [ ]:
y_pred = X * β
residuals = y - y_pred

# Метрики качества
mse = mean(residuals.^2)
rmse = sqrt(mse)
r2 = 1 - sum(residuals.^2) / sum((y .- mean(y)).^2);

Вычисляем предсказанные значения расхода топлива и находим разность между фактическими и предсказанными значениями. Рассчитываем ключевые метрики качества: среднеквадратичную ошибку (MSE), её корень (RMSE) для оценки точности в исходных единицах, и коэффициент детерминации (R²) для оценки объясненной дисперсии.

Визуализация многомерной регрессии:

In [ ]:
# 3D-визуализация для обоих признаков
p1 = plot(title="Многомерная регрессия", legend=:none, size=(800, 600))
scatter!(X_raw.HP, X_raw.weight_tons, y, marker=:circle, color=:blue, 
         xlabel="Мощность (л.с.)", ylabel="Масса (тонны)", zlabel="Расход (л/100км)")
surface!(sort(unique(X_raw.HP)), sort(unique(X_raw.weight_tons)), 
         (x,y) -> β[1] + β[2]*(x - mean(X_raw.HP))/std(X_raw.HP) + β[3]*(y - mean(X_raw.weight_tons))/std(X_raw.weight_tons),
         alpha=0.5)

display(p1)

На трёхмерном графике отображено влияние обеих переменных на расход топлива. Синие точки представляют собой фактические наблюдения, а полупрозрачная поверхность - предсказания регрессионной модели.

In [ ]:
# Вывод результатов
println("\nРезультаты регрессионного анализа:")
println("==================================================")
println("Коэффициенты модели:")
println(" - Константа (b0): ", round(β[1], digits=4), " л/100км")
println(" - Мощность (b1): ", round(β[2], digits=4), " л/100км на 1 std мощности")
println(" - Масса (b2):      ", round(β[3], digits=4), " л/100км на 1 std веса")
println("\nМетрики качества:")
println(" - MSE:  ", round(mse, digits=4), " (л/100км)²")
# @markdown Результат регрессионного анализа:
println(" - RMSE: ", round(rmse, digits=4), " л/100км")
println(" - R²:   ", round(r2, digits=4))
println("==================================================")

# Интерпретация коэффициентов
hp_std = std(X_raw.HP)
weight_std = std(X_raw.weight_tons)

println("\nИнтерпретация:")
println("- При увеличении мощности на 1 стандартное отклонение (≈$(round(hp_std, digits=1)) л.с.),")
println("  расход топлива изменяется на ", round(β[2], digits=2), " л/100км")
println("- При увеличении массы на 1 стандартное отклонение (≈$(round(weight_std, digits=2)) тонны),")
println("  расход топлива изменяется на ", round(β[3], digits=2), " л/100км")
println("- Intercept (", round(β[1], digits=1), " л/100км) - средний расход при средних мощности и массе")
Результаты регрессионного анализа:
==================================================
Коэффициенты модели:
 - Константа (b0): 12.7553 л/100км
 - Мощность (b1): 1.2062 л/100км на 1 std мощности
 - Масса (b2):      2.6434 л/100км на 1 std веса

Метрики качества:
 - MSE:  2.2109 (л/100км)²
 - RMSE: 1.4869 л/100км
 - R²:   0.8471
==================================================

Интерпретация:
- При увеличении мощности на 1 стандартное отклонение (≈68.6 л.с.),
  расход топлива изменяется на 1.21 л/100км
- При увеличении массы на 1 стандартное отклонение (≈0.44 тонны),
  расход топлива изменяется на 2.64 л/100км
- Intercept (12.8 л/100км) - средний расход при средних мощности и массе

Выводы:

В данном примере было рассмотрено применение метода наименьших квадратов для построения множественной линейной регрессионной модели на классическом датасете mtcars, содержащем характеристики 32 автомобилей 1973-74 годов выпуска.

В качестве зависимой переменной выступал расход топлива автомобилей (л/100км), а в качестве независимых переменных - нормализованная мощность двигателя и масса транспортного средства.