37 KiB
Построение модели регрессии с использованием Scikit-learn: четыре подхода к регрессии
Инфографика от Dasani Madipalli
Тест перед лекцией
Этот урок доступен на языке R!
Введение
До этого момента вы изучили, что такое регрессия, используя пример данных из набора данных о ценах на тыквы, который мы будем использовать на протяжении всего урока. Вы также визуализировали данные с помощью Matplotlib.
Теперь вы готовы углубиться в регрессию для машинного обучения. Хотя визуализация помогает понять данные, настоящая сила машинного обучения заключается в обучении моделей. Модели обучаются на исторических данных, чтобы автоматически выявлять зависимости в данных, и позволяют предсказывать результаты для новых данных, которые модель ранее не видела.
В этом уроке вы узнаете больше о двух типах регрессии: основной линейной регрессии и полиномиальной регрессии, а также о некоторых математических основах этих методов. Эти модели позволят нам предсказывать цены на тыквы в зависимости от различных входных данных.
🎥 Нажмите на изображение выше, чтобы посмотреть короткое видео о линейной регрессии.
В рамках этой программы мы предполагаем минимальные знания математики и стремимся сделать материал доступным для студентов из других областей. Обращайте внимание на заметки, 🧮 математические вставки, диаграммы и другие инструменты для облегчения понимания.
Предварительные знания
К этому моменту вы уже должны быть знакомы со структурой данных о тыквах, которые мы изучаем. Вы можете найти их предварительно загруженными и очищенными в файле notebook.ipynb этого урока. В файле цена на тыквы отображается за бушель в новом датафрейме. Убедитесь, что вы можете запускать эти ноутбуки в ядрах Visual Studio Code.
Подготовка
Напомним, вы загружаете эти данные, чтобы задавать им вопросы.
- Когда лучше всего покупать тыквы?
- Какую цену я могу ожидать за упаковку миниатюрных тыкв?
- Стоит ли покупать их в корзинах на полбушеля или в коробках на 1 1/9 бушеля? Давайте продолжим исследовать эти данные.
В предыдущем уроке вы создали датафрейм Pandas и заполнили его частью исходного набора данных, стандартизировав цены по бушелю. Однако, сделав это, вы смогли собрать только около 400 точек данных, и только за осенние месяцы.
Посмотрите на данные, которые мы предварительно загрузили в ноутбуке, сопровождающем этот урок. Данные предварительно загружены, и начальная диаграмма рассеяния построена для отображения данных по месяцам. Возможно, мы сможем получить больше деталей о природе данных, если очистим их еще больше.
Линия линейной регрессии
Как вы узнали в Уроке 1, цель упражнения по линейной регрессии — построить линию, чтобы:
- Показать взаимосвязь переменных. Показать связь между переменными.
- Сделать прогнозы. Делать точные прогнозы о том, где новая точка данных окажется относительно этой линии.
Для построения такой линии обычно используется метод наименьших квадратов. Термин "наименьшие квадраты" означает, что все точки данных вокруг линии регрессии возводятся в квадрат, а затем складываются. В идеале, итоговая сумма должна быть как можно меньше, так как мы хотим минимизировать количество ошибок, или наименьшие квадраты.
Мы делаем это, потому что хотим смоделировать линию, которая имеет минимальное суммарное расстояние от всех наших точек данных. Мы также возводим термины в квадрат перед их сложением, так как нас интересует их величина, а не направление.
🧮 Покажите мне математику
Эта линия, называемая линией наилучшего соответствия, может быть выражена уравнением:
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. Используя диаграмму рассеяния, вы можете быстро визуализировать этот коэффициент. Если точки данных на графике выстроены в аккуратную линию, корреляция высокая, но если точки разбросаны повсюду, корреляция низкая.
Хорошая модель линейной регрессии будет иметь высокий коэффициент корреляции (ближе к 1, чем к 0) при использовании метода наименьших квадратов с линией регрессии.
✅ Запустите ноутбук, сопровождающий этот урок, и посмотрите на диаграмму рассеяния "Месяц к цене". Кажется ли, что данные о продажах тыкв имеют высокую или низкую корреляцию, согласно вашему визуальному анализу диаграммы? Изменится ли это, если использовать более точную меру вместо Месяца, например, день года (т.е. количество дней с начала года)?
В приведенном ниже коде мы предполагаем, что данные очищены, и получен датафрейм new_pumpkins, похожий на следующий:
| ID | Месяц | ДеньГода | Сорт | Город | Упаковка | Низкая цена | Высокая цена | Цена |
|---|---|---|---|---|---|---|---|---|
| 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)
Теперь, когда вы понимаете математику линейной регрессии, давайте создадим модель регрессии, чтобы выяснить, какая упаковка тыкв будет иметь лучшие цены. Кто-то, покупающий тыквы для праздничного тыквенного поля, может захотеть получить эту информацию, чтобы оптимизировать свои покупки.
Поиск корреляции
🎥 Нажмите на изображение выше, чтобы посмотреть короткое видео о корреляции.
Из предыдущего урока вы, вероятно, видели, что средняя цена по месяцам выглядит так:
Это предполагает, что должна быть некоторая корреляция, и мы можем попробовать обучить модель линейной регрессии, чтобы предсказать связь между Месяцем и Ценой или между ДнемГода и Ценой. Вот диаграмма рассеяния, показывающая последнюю связь:
Давайте проверим, есть ли корреляция, используя функцию corr:
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))
Похоже, что корреляция довольно мала: -0.15 для Месяца и -0.17 для ДняГода, но может быть другая важная связь. Кажется, что существуют разные кластеры цен, соответствующие различным сортам тыкв. Чтобы подтвердить эту гипотезу, давайте построим каждую категорию тыкв разным цветом. Передавая параметр ax в функцию построения диаграммы рассеяния, мы можем отобразить все точки на одном графике:
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')
Если теперь рассчитать корреляцию между Ценой и ДнемГода с помощью функции 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входных данных, чтобы пакет линейной регрессии правильно их понял. Линейная регрессия ожидает 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 после подгонки содержит все коэффициенты регрессии, к которым можно получить доступ через свойство .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 включает удобный API для создания пайплайнов, чтобы объединить различные этапы обработки данных. Пайплайн — это цепочка оценщиков. В нашем случае мы создадим пайплайн, который сначала добавит полиномиальные признаки в нашу модель, а затем обучит регрессию:
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. Мы также можем использовать полиномы более высокой степени, если захотим.
Пайплайны можно использовать так же, как и оригинальный объект LinearRegression, то есть мы можем вызвать fit для пайплайна, а затем использовать 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 кодированные категориальные + числовые признаки) из приведенного выше примера вместе с полиномиальной регрессией. Вот полный код для вашего удобства:
# set up training data
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']
# make train-test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# setup and train the pipeline
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
pipeline.fit(X_train,y_train)
# predict results for test data
pred = pipeline.predict(X_test)
# calculate MSE and determination
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. Хотя мы стремимся к точности, пожалуйста, учитывайте, что автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникающие в результате использования данного перевода.






