Набор данных, используемый в этом пошаговом руководстве, представляет собой Набор данных Ames Housing, составленный Дином Де Коком для использования в обучении науке о данных и выбранный для использования в Цены на жилье Kaggle: конкурс передовых методов регрессии. Я участвовал в этом конкурсе и решил написать статью для новых студентов, изучающих науку о данных. Это руководство будет разделено на 4 этапа:

  1. Исследование
  2. Уборка
  3. Разработка функций
  4. Моделирование и прогнозирование

Исследование

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

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

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

Распределение остроконечное (эксцесс), положительная асимметрия (асимметрия) и явно отклоняется от нормального распределения. Ниже вы можете увидеть значения для SalePrice, и если вы не знаете, что означают эти значения, ознакомьтесь с этой статьей.

Skewness: 1.882876
Kurtosis: 6.536282

Это распределение также присутствует в других функциях, таких как GrLivArea.

Если мы продолжим выбирать модель, чувствительную к гетероскедастичности (неодинаковая дисперсия в терминах ошибок для значений функции), это необходимо будет исправить с помощью преобразования, такого как Бокса-Кокса, или применения логарифма.

Мы проанализировали нашу целевую переменную, но как наши функции связаны с ней? Это называется двумерным анализом. Ниже мы можем увидеть график разброса SalePrice и TotalBsmtSF. Кажется, что их отношения линейны (слегка экспоненциальны?), и мы можем начать видеть некоторые выбросы, такие как дом в самой правой части графика, который имеет огромный подвал площадью более 6000 квадратных футов, но имеет низкую цену продажи и не следи за тенденцией. Этот выброс может быть домом в сельской местности, что объясняет разницу в цене и районе.

То же, что и выше. Мы видим тот самый выброс с жилой площадью более 5000 квадратных футов! Нам придется удалить их, иначе наша модель будет обучаться с выбросами, и наши прогнозы ухудшатся.

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

Уборка

Первое, что нужно сделать, это убедиться, что ваши функции имеют правильные типы данных. В этом наборе данных у нас есть много столбцов, таких как YrSold, MoSold и YrBuilt, которые считаются числами, но их следует рассматривать как категориальные переменные.

Может показаться странным рассматривать год как категориальную переменную. Однако мы не можем выполнять разумные математические операции с этими числами. Подумайте вот о чем: 2000 год в два раза больше, чем 1000 год? Это не так, и мы не можем так рассуждать, поэтому это должно быть категорично.

Далее мы удалим все столбцы с высоким процентом пропущенных значений.

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

Для числовых столбцов я заполнил большинство пропущенных значений 0, поскольку это означает, что функция отсутствует в наблюдении. Если GarageCars или TotalBsmtSF отсутствуют, в доме нет ни гаража, ни подвала. Единственным столбцом, который я ввел по-другому, был LotFrontage, поскольку его можно определить по законам о зонировании, поэтому я вменил его в медиану района.

Мы повторим тот же процесс для категориальных столбцов. Я заменил большинство отсутствующих значений на «Нет», так как это означает, что наблюдение не представляет функцию, а оставшиеся значения были им вменены с соответствующими модами. Для заполнения столбца MSZoning мода была взята из наблюдений того же самого MSSubClass, который идентифицирует тип продаваемого дома.

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

  • Есть более сложные способы сделать наши объекты более нормальными, например, с помощью преобразования Бокса-Кокса или Йео-Джонсона, но я собираюсь использовать простое преобразование log(x + 1). Я добавляю константу, поскольку некоторые из наших функций, таких как TotalBsmtSF, могут быть равны 0, а log(0) невозможен.
  • Признаки с низкой дисперсией неинформативны, потому что наша модель будет соответствовать наблюдениям с разными значениями. Если преобладающее значение в столбце превышает 99,5%, оно будет удалено.

На следующих графиках мы можем визуально увидеть, насколько наши данные стали более гауссовыми (нормальное распределение) после логарифмического преобразования.

Разработка функций

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

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

map1 = {'Ex': 5, 'Gd': 4, 'TA': 3, 'Fa': 2, 'Po': 1, 'None': 0}
train_test_features["TotalGarageQual"] = train_test_features["GarageQual"].replace(map1) * train_test_features["GarageCond"].replace(map1)
train_test_features["TotalExteriorQual"] = train_test_features["ExterQual"].replace(map1) * train_test_features["ExterCond"].replace(map1)

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

Моделирование

А вот и самое интересное, машинное обучение! Я решил использовать VotingRegressor из библиотеки sklearn, которая в основном объединяет несколько регрессоров и усредняет прогнозы для создания окончательного. Какие базовые модели я использовал?

  • Лассо
  • хребет
  • Эластичная сеть
  • GradientBoostingRegressor

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

GradientBoostingRegressor является единственным лишним, поскольку он не обязательно используется для линейной регрессии, но я добавил его, чтобы сбалансировать смещения, предполагаемые моделями линейной регрессии.

Вы можете перенастроить параметры и найти лучшие коэффициенты для моделей, но я решил упростить и оставить все как есть. Кроме того, не забудьте преобразовать прогнозы обратно, поскольку наша модель будет выводить их так, как если бы они также были преобразованы в журнал. В NumPy это можно сделать с помощью функции exmp1.

Результат

np.sqrt(-cross_val_score(pipe, X_train, y_train, scoring='neg_mean_squared_error')).mean()

После перекрестной проверки нашей модели на обучающих данных окончательная оценка составила 0,1002929, а на Kaggle официальная оценка составила 0,12070, что на момент написания этой статьи входит в 5% лучших результатов этого соревнования.

Я надеюсь, что это поможет и вдохновит вас в вашем путешествии по науке о данных, и если вам нужна моя записная книжка Jupyter, я был бы рад отправить вам ее.