Сообщество Engee

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

Автор
avatar-mikhailpetrovmikhailpetrov
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км), а в качестве независимых переменных - нормализованная мощность двигателя и масса транспортного средства.