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

Инфографика от Dasani Madipalli
До сих пор вы исследовали, что такое регрессия, используя пример данных, собранных из датасета с ценами на тыквы, который мы будем использовать на протяжении всего урока. Вы также визуализировали данные с помощью Matplotlib.
Теперь вы готовы глубже погрузиться в регрессию для машинного обучения. В то время как визуализация позволяет понять данные, реальная сила Машинного Обучения заключается в обучении моделей. Модели обучаются на исторических данных, чтобы автоматически улавливать зависимости данных, и они позволяют предсказывать результаты для новых данных, которые модель ранее не видела.
В этом уроке вы узнаете больше о двух типах регрессии: базовая линейная регрессия и полиномиальная регрессия, а также о математике, лежащей в основе этих методов. Эти модели позволят нам предсказывать цены на тыквы в зависимости от различных входных данных.
🎥 Нажмите на изображение выше для краткого видеообзора линейной регрессии.
В рамках этой учебной программы мы предполагаем минимальные знания математики и стремимся сделать материал доступным для студентов из других областей, поэтому следите за примечаниями, 🧮 подсказками, диаграммами и другими средствами обучения для облегчения понимания.
К этому моменту вы должны быть знакомы со структурой данных по тыквам, которые мы изучаем. Вы можете найти их заранее загруженными и предварительно очищенными в файле notebook.ipynb этого урока. В файле цена на тыквы отображается за бушель в новой таблице данных. Убедитесь, что вы можете запускать эти ноутбуки в ядрах Visual Studio Code.
Напоминаем, что вы загружаете эти данные, чтобы задавать вопросы и анализировать их.
- Когда лучше всего покупать тыквы?
- Какую цену я могу ожидать за ящик мини-тыкв?
- Стоит ли покупать их в полубушельных корзинах или в ящике на 1 1/9 бушеля? Продолжим изучение этих данных.
В предыдущем уроке вы создали фрейм данных Pandas и заполнили его частью исходного датасета, стандартизировав цены на бушель. Однако, при этом вы смогли собрать только около 400 точек данных и только за осенние месяцы.
Взгляните на данные, которые мы заранее загрузили в сопроводительном ноутбуке этого урока. Они сразу загружены, и построен начальный диаграмм разброса для отображения данных по месяцам. Возможно, мы можем получить немного больше информации о природе данных, очистив их более подробно.
Как вы узнали в Уроке 1, цель упражнения по линейной регрессии — построить линию, чтобы:
- Показать взаимосвязь переменных. Показать связь между переменными
- Делать предсказания. Точно предсказывать, где новый datapoint будет расположена относительно этой линии.
Обычно метод наименьших квадратов используется для построения такой линии. Термин «наименьшие квадраты» относится к процессу минимизации общей ошибки модели. Для каждой точки данных мы измеряем вертикальное расстояние (называемое остатком) между фактической точкой и нашей линией регрессии.
Мы возводим эти расстояния в квадрат по двум основным причинам:
-
Величина, а не направление: Мы хотим одинаково воспринимать ошибку -5 и +5. Квадрат превращает все значения в положительные.
-
Штраф для выбросов: Квадрат придаёт больший вес большим ошибкам, заставляя линию оставаться ближе к точкам, которые находятся далеко.
Затем мы суммируем все эти квадраты. Наша цель — найти такую линию, для которой эта сумма будет минимальной (самой маленькой возможной) — отсюда и название «наименьшие квадраты».
🧮 Покажите мне математику
Эта линия, называемая линией наилучшего попадания, может быть выражена уравнением:
Y = a + bX
X— это «объясняющая переменная».Y— «зависимая переменная». Наклон линии —b, аa— пересечение с осью Y, то есть значениеYприX = 0.Сначала вычисляем наклон
b. Инфографика от Jen LooperДругими словами, говоря о нашем исходном вопросе из данных о тыквах: "предсказать цену тыквы за бушель по месяцам",
Xбудет ссылаться на цену, аY— на месяц продажи.Вычислите значение Y. Если вы платите около $4, значит пора апрель! Инфографика от Jen Looper
Математика, вычисляющая линию, должна демонстрировать наклон, который также зависит от пересечения, или где расположен
Y, когдаX = 0.Метод вычисления этих значений можно посмотреть на сайте Math is Fun. Также посетите калькулятор наименьших квадратов, чтобы увидеть, как значения чисел влияют на линию.
Еще один термин, который нужно понять — это коэффициент корреляции между заданными переменными X и Y. Используя диаграмму рассеяния, вы можете быстро визуализировать этот коэффициент. График с точками, разбросанными в аккуратной линии, имеет высокую корреляцию, а график с точками, разбросанными повсюду между X и Y — низкую корреляцию.
Хорошая модель линейной регрессии — это та, у которой высокий (ближе к 1, чем к 0) коэффициент корреляции при использовании метода наименьших квадратов с линией регрессии.
✅ Запустите ноутбук, сопровождающий этот урок, и посмотрите на диаграмму разброса «Месяц — цена». Кажется ли вам, что данные о зависимости Месяца от Цены для продаж тыкв имеют высокую или низкую корреляцию, исходя из вашего визуального восприятия диаграммы разброса? Изменится ли это, если использовать более точный показатель, например день года (то есть количество дней с начала года)?
В коде ниже мы предполагаем, что данные очищены, и получен фрейм данных с названием new_pumpkins, похожий на следующий:
| ID | Month | DayOfYear | Variety | City | Package | Low Price | High Price | Price |
|---|---|---|---|---|---|---|---|---|
| 70 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 15.0 | 15.0 | 13.636364 |
| 71 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 18.0 | 18.0 | 16.363636 |
| 72 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 18.0 | 18.0 | 16.363636 |
| 73 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 17.0 | 17.0 | 15.454545 |
| 74 | 10 | 281 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 15.0 | 15.0 | 13.636364 |
Код для очистки данных доступен в
notebook.ipynb. Мы выполнили те же шаги очистки, что и в предыдущем уроке, и рассчитали столбецDayOfYearс помощью следующего выражения:
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)Теперь, когда у вас есть понимание математики, стоящей за линейной регрессией, давайте создадим регрессионную модель, чтобы проверить, можем ли мы предсказать, какой пакет тыкв будет иметь лучшие цены. Кто-то, покупающий тыквы для праздничного тыквенного участка, может захотеть иметь такую информацию, чтобы оптимизировать покупки пакетов для участка.
🎥 Нажмите на изображение выше, чтобы посмотреть короткое видеообзор корреляции.
Из предыдущего урока вы, вероятно, видели, что средняя цена по месяцам выглядит так:
Это предполагает, что существует некоторая корреляция, и мы можем попытаться обучить модель линейной регрессии, чтобы предсказать связь между Month и Price, или между DayOfYear и Price. Вот диаграмма разброса, показывающая вторую связь:
Давайте проверим корреляцию с помощью функции corr:
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))Похоже, что корреляция довольно низкая: -0.15 для Month и -0.17 для DayOfMonth, но возможно есть еще одна важная зависимость. Кажется, что существуют разные кластеры цен, соответствующие различным сортам тыкв. Чтобы подтвердить это предположение, давайте построим график для каждой категории тыкв разным цветом. Передавая параметр ax в функцию scatter, мы можем отобразить все точки на одном графике:
ax=None
colors = ['red','blue','green','yellow']
for i,var in enumerate(new_pumpkins['Variety'].unique()):
df = new_pumpkins[new_pumpkins['Variety']==var]
ax = df.plot.scatter('DayOfYear','Price',ax=ax,c=colors[i],label=var)Наше исследование указывает, что сорт тыкв оказывает большее влияние на цену, чем фактическая дата продажи. Это можно увидеть на столбчатой диаграмме:
new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')Для начала сосредоточимся только на одном сорте тыкв — 'pie type' — и посмотрим, какое влияние оказывает дата на цену:
pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
pie_pumpkins.plot.scatter('DayOfYear','Price') Если теперь вычислить корреляцию между Price и DayOfYear с помощью функции corr, мы получим что-то около -0.27 — что означает, что обучение предсказательной модели имеет смысл.
Перед обучением модели линейной регрессии важно убедиться, что данные чисты. Линейная регрессия плохо работает с пропущенными значениями, поэтому разумно избавиться от всех пустых ячеек:
pie_pumpkins.dropna(inplace=True)
pie_pumpkins.info()Другой подход — заполнить пустые значения средними значениями по соответствующему столбцу.
🎥 Нажмите на изображение выше для краткого видеообзора линейной и полиномиальной регрессии.
Для обучения модели линейной регрессии мы будем использовать библиотеку Scikit-learn.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_splitНачнем с разделения входных значений (признаков) и ожидаемого выходного значения (метки) в отдельные массивы numpy:
X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
y = pie_pumpkins['Price']Обратите внимание, что нам пришлось выполнить
reshapeдля входных данных, чтобы пакет Linear Regression корректно их понял. Линейная регрессия ожидает на вход 2D-массив, где каждая строка массива соответствует вектору входных признаков. В нашем случае, поскольку у нас только один вход, нам нужен массив формы N×1, где N — размер набора данных.
Далее нужно разделить данные на обучающую и тестовую выборки, чтобы после обучения мы могли проверить модель:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)Наконец, обучение самой модели линейной регрессии занимает всего две строки кода. Определяем объект LinearRegression и подгоняем его под наши данные с помощью метода fit:
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)Объект LinearRegression после выполнения метода fit содержит все коэффициенты регрессии, к которым можно получить доступ через свойство .coef_. В нашем случае есть только один коэффициент, который должен быть около -0.017. Это означает, что цены, похоже, немного падают со временем, но не слишком сильно, примерно на 2 цента в день. Также мы можем получить точку пересечения регрессии с осью Y с помощью lin_reg.intercept_ — в нашем случае это будет около 21, что указывает на цену в начале года.
Чтобы увидеть, насколько точна наша модель, мы можем предсказать цены на тестовом наборе данных, а затем измерить, насколько близки наши прогнозы к ожидаемым значениям. Это можно сделать с помощью метрики средней квадратичной ошибки (MSE), которая является средним всех квадратов разниц между ожидаемым и предсказанным значением.
pred = lin_reg.predict(X_test)
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')Наша ошибка кажется примерно равной 2 баллам, что составляет ~17%. Не очень хорошо. Еще одним показателем качества модели является коэффициент детерминации, который можно получить следующим образом:
score = lin_reg.score(X_train,y_train)
print('Model determination: ', score)Если значение равно 0, это означает, что модель не учитывает входные данные и действует как худший линейный предсказатель, который просто возвращает среднее значение результата. Значение 1 означает, что мы можем идеально предсказать все ожидаемые выходы. В нашем случае коэффициент около 0.06, что довольно низко.
Мы также можем построить график тестовых данных вместе с линией регрессии, чтобы лучше увидеть, как работает регрессия в нашем случае:
plt.scatter(X_test,y_test)
plt.plot(X_test,pred)Другим типом линейной регрессии является полиномиальная регрессия. Хотя иногда существует линейная зависимость между переменными — чем больше объем тыквы, тем выше цена — иногда такие зависимости нельзя представить в виде плоскости или прямой линии.
✅ Вот еще несколько примеров данных, для которых может подойти полиномиальная регрессия
Еще раз взгляните на зависимость между Датой и Ценой. Кажется ли этот диаграмма рассеяния такой, которую обязательно нужно анализировать прямой линией? Может ли цена колебаться? В этом случае вы можете попробовать полиномиальную регрессию.
✅ Полиномы — это математические выражения, которые могут состоять из одной или нескольких переменных и коэффициентов
Полиномиальная регрессия строит кривую, чтобы лучше подогнать нелинейные данные. В нашем случае, если мы добавим в входные данные переменную DayOfYear в квадрате, мы сможем аппроксимировать наши данные параболой, у которой будет минимум в определенной точке в течение года.
Scikit-learn включает полезный pipeline API для объединения разных этапов обработки данных. Pipeline — это цепочка оценивателей. В нашем случае мы создадим pipeline, который сначала добавляет полиномиальные признаки в нашу модель, а затем обучает регрессию:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)Использование PolynomialFeatures(2) означает, что мы включаем все полиномы второй степени из входных данных. В нашем случае это просто DayOfYear2, но если есть две переменные X и Y, то это будет X2, XY и Y2. Мы также можем использовать полиномы более высокого порядка, если хотим.
Pipeline можно использовать так же, как и исходный объект LinearRegression, то есть мы можем fit pipeline, а затем использовать predict для получения результатов предсказания. Вот график, показывающий тестовые данные и аппроксимирующую кривую:
Используя полиномиальную регрессию, мы можем получить слегка меньшую MSE и более высокий коэффициент детерминации, но не значительно. Нам нужно учитывать другие признаки!
Вы можете заметить, что минимальные цены на тыквы наблюдаются примерно около Хэллоуина. Как вы это объясните?
🎃 Поздравляем, вы только что создали модель, которая может помочь предсказывать цену пироговых тыкв. Вероятно, вы можете повторить ту же процедуру для всех видов тыкв, но это будет утомительно. Давайте теперь научимся учитывать сорт тыквы в нашей модели!
В идеальном мире мы хотим иметь возможность предсказывать цены для разных сортов тыкв, используя одну модель. Однако столбец Variety отличается от таких столбцов, как Month, потому что он содержит нечисловые значения. Такие столбцы называют категориальными.
🎥 Нажмите на изображение выше для короткого видеообзора по использованию категориальных признаков.
Здесь вы видите, как средняя цена зависит от сорта:
Чтобы учесть сорт, сначала нужно преобразовать его в числовой формат, то есть закодировать. Существует несколько способов сделать это:
- Простой числовой кодировкой построится таблица разных сортов, и затем имя сорта будет заменено индексом в этой таблице. Это не лучшая идея для линейной регрессии, потому что линейная регрессия воспринимает числовое значение индекса напрямую и добавляет его к результату, умножая на коэффициент. В нашем случае зависимость между номером индекса и ценой явно нелинейна, даже если мы упорядочим индексы в каком-то определенном порядке.
- One-hot кодирование заменит столбец
Varietyна 4 отдельных столбца, по одному на каждый сорт. Каждый столбец будет содержать1, если соответствующая строка относится к данному сорту, и0иначе. Это означает, что в регрессии будет четыре коэффициента, по одному для каждого сорта тыквы, ответственных за "стартовую цену" (или скорее "дополнительную цену") для конкретного сорта.
Ниже показано, как можно закодировать сорт с помощью one-hot кодирования:
pd.get_dummies(new_pumpkins['Variety'])| ID | FAIRYTALE | MINIATURE | MIXED HEIRLOOM VARIETIES | PIE TYPE |
|---|---|---|---|---|
| 70 | 0 | 0 | 0 | 1 |
| 71 | 0 | 0 | 0 | 1 |
| ... | ... | ... | ... | ... |
| 1738 | 0 | 1 | 0 | 0 |
| 1739 | 0 | 1 | 0 | 0 |
| 1740 | 0 | 1 | 0 | 0 |
| 1741 | 0 | 1 | 0 | 0 |
| 1742 | 0 | 1 | 0 | 0 |
Для обучения линейной регрессии с one-hot кодированным сортом в качестве входных данных, нам просто нужно правильно инициализировать данные X и y:
X = pd.get_dummies(new_pumpkins['Variety'])
y = new_pumpkins['Price']Остальная часть кода такая же, как и использованная выше для обучения линейной регрессии. Если попробовать, вы увидите, что средняя квадратичная ошибка примерно такая же, но мы получаем значительно более высокий коэффициент детерминации (~77%). Чтобы получить еще более точные предсказания, можно учитывать больше категориальных признаков, а также числовые признаки, такие как Month или DayOfYear. Чтобы получить один большой массив признаков, можно использовать join:
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']Здесь мы также учитываем City и тип Package, что дает нам MSE 2.84 (10%) и коэффициент детерминации 0.94!
Чтобы получить лучшую модель, мы можем использовать объединённые (one-hot кодированные категориальные + числовые) данные из приведенного примера вместе с полиномиальной регрессией. Вот полный код для вашего удобства:
# подготовить обучающие данные
X = pd.get_dummies(new_pumpkins['Variety']) \
.join(new_pumpkins['Month']) \
.join(pd.get_dummies(new_pumpkins['City'])) \
.join(pd.get_dummies(new_pumpkins['Package']))
y = new_pumpkins['Price']
# сделать разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# настроить и обучить конвейер
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
# предсказать результаты для тестовых данных
pred = pipeline.predict(X_test)
# вычислить MSE и коэффициент детерминации
mse = np.sqrt(mean_squared_error(y_test,pred))
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
score = pipeline.score(X_train,y_train)
print('Model determination: ', score)Это должно дать нам лучший коэффициент детерминации почти 97% и MSE=2.23 (~8% ошибки предсказания).
| Модель | MSE | Коэффициент детерминации |
|---|---|---|
Линейная регрессия по DayOfYear |
2.77 (17.2%) | 0.07 |
Полиномиальная регрессия по DayOfYear |
2.73 (17.0%) | 0.08 |
Линейная регрессия по Variety |
5.24 (19.7%) | 0.77 |
| Линейная регрессия со всеми признаками | 2.84 (10.5%) | 0.94 |
| Полиномиальная регрессия со всеми признаками | 2.23 (8.25%) | 0.97 |
🏆 Отличная работа! Вы создали четыре модели регрессии за один урок и повысили качество модели до 97%. В заключительном разделе про регрессию вы узнаете о логистической регрессии для определения категорий.
Попробуйте проверить разные переменные в этом блокноте, чтобы понять, как корреляция влияет на точность модели.
В этом уроке мы изучили линейную регрессию. Существует и другие важные типы регрессий. Ознакомьтесь с техниками пошаговой (Stepwise), Ridge, Lasso и Elasticnet регрессии. Хороший курс для изучения — курс статистического обучения Стэнфорда.
Отказ от ответственности:
Этот документ был переведен с использованием сервиса автоматического перевода Co-op Translator. Несмотря на наши усилия обеспечить точность, имейте в виду, что автоматический перевод может содержать ошибки или неточности. Оригинальный документ на исходном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется обратиться к профессиональному переводчику. Мы не несем ответственности за любые недоразумения или неправильные толкования, возникшие в результате использования данного перевода.












