Моделирование цены с помощью регулярной линейной модели и Xgboost

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

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

Поэтому для начала мы собираемся реализовать методы регуляризации для линейной регрессии данных о ценах на недвижимость.

Данные

Отличный набор данных о ценах на жилье можно найти здесь.

import warnings
def ignore_warn(*args, **kwargs):
    pass
warnings.warn = ignore_warn
import numpy as np 
import pandas as pd 
%matplotlib inline
import matplotlib.pyplot as plt 
import seaborn as sns
from scipy import stats
from scipy.stats import norm, skew
from sklearn import preprocessing
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNetCV, ElasticNet
from xgboost import XGBRegressor, plot_importance 
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import StratifiedKFold
pd.set_option('display.float_format', lambda x: '{:.3f}'.format(x))
df = pd.read_csv('house_train.csv')
df.shape

(df.isnull().sum() / len(df)).sort_values(ascending=False)[:20]

Хорошая новость заключается в том, что у нас есть много функций, с которыми можно поиграть (81), плохая новость в том, что 19 функций имеют пропущенные значения, а 4 из них имеют более 80% пропущенных значений. Для любой функции, если в ней отсутствуют 80% значений, она не может быть настолько важной, поэтому я решил удалить эти 4 функции.

df.drop(['PoolQC', 'MiscFeature', 'Alley', 'Fence', 'Id'], axis=1, inplace=True)

Изучите особенности

Целевое распределение функций

sns.distplot(df['SalePrice'] , fit=norm);
# Get the fitted parameters used by the function
(mu, sigma) = norm.fit(df['SalePrice'])
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))
#Now plot the distribution
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
            loc='best')
plt.ylabel('Frequency')
plt.title('Sale Price distribution')
#Get also the QQ-plot
fig = plt.figure()
res = stats.probplot(df['SalePrice'], plot=plt)
plt.show();

Целевая особенность - SalePrice смещена вправо. Как линейные модели, такие как нормально распределенные данные, мы преобразуем SalePrice и сделаем его более нормально распределенным.

sns.distplot(np.log1p(df['SalePrice']) , fit=norm);
# Get the fitted parameters used by the function
(mu, sigma) = norm.fit(np.log1p(df['SalePrice']))
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))
#Now plot the distribution
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
            loc='best')
plt.ylabel('Frequency')
plt.title('log(Sale Price+1) distribution')
#Get also the QQ-plot
fig = plt.figure()
res = stats.probplot(np.log1p(df['SalePrice']), plot=plt)
plt.show();

Корреляция между числовыми характеристиками

pd.set_option('precision',2)
plt.figure(figsize=(10, 8))
sns.heatmap(df.drop(['SalePrice'],axis=1).corr(), square=True)
plt.suptitle("Pearson Correlation Heatmap")
plt.show();

Между некоторыми функциями существует сильная корреляция. Например, GarageYrBlt и YearBuilt, TotRmsAbvGrd и GrLivArea, GarageArea и GarageCars сильно коррелированы. На самом деле они выражают более или менее одно и то же. Позже я разрешаю ElasticNetCV уменьшить избыточность.

Корреляция между SalePrice и другими числовыми характеристиками

corr_with_sale_price = df.corr()["SalePrice"].sort_values(ascending=False)
plt.figure(figsize=(14,6))
corr_with_sale_price.drop("SalePrice").plot.bar()
plt.show();

Корреляция между SalePrice и GeneralQual самая высокая (около 0,8). Также GrLivArea показывает корреляцию более 0,7, а GarageCars показывает корреляцию более 0,6. Давайте рассмотрим эти 4 функции более подробно.

sns.pairplot(df[['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars']])
plt.show();

Функциональная инженерия

  • Функции преобразования журнала с сильно искаженным распределением (перекос ›0,75)
  • Фиктивное кодирование категориальных функций
  • Заполните NaN средним значением столбца.
  • Тренировочная и тестовая наборы разделены.

ElasticNet

  • Регрессия Ridge и Lasso - это регуляризованные модели линейной регрессии.
  • ElasticNe t по сути представляет собой гибрид Лассо / Ридж, который влечет за собой минимизацию целевой функции, которая включает как L1 (лассо), так и L2 (Ридж) норм.
  • ElasticNet полезен, когда существует несколько взаимосвязанных функций.
  • Класс ElasticNetCV можно использовать для установки параметров alpha (α) и l1_ratio (ρ) путем перекрестной проверки.
  • ElasticNetCV: модель ElasticNet с выбором наилучшей модели путем перекрестной проверки.

Посмотрим, что ElasticNetCV выберет для нас.

0 ‹Оптимальное l1_ratio‹ 1, обозначающее штраф, представляет собой комбинацию L1 и L2, то есть комбинацию Лассо и Ридж.

Оценка модели

RMSE здесь на самом деле RMSLE (среднеквадратичная логарифмическая ошибка). Потому что мы взяли журнал фактических значений. Вот хорошая статья, объясняющая различия между RMSE и RMSLE.

Важность функции

feature_importance = pd.Series(index = X_train.columns, data = np.abs(cv_model.coef_))
n_selected_features = (feature_importance>0).sum()
print('{0:d} features, reduction of {1:2.2f}%'.format(
    n_selected_features,(1-n_selected_features/len(feature_importance))*100))
feature_importance.sort_values().tail(30).plot(kind = 'bar', figsize = (12,5));

Уменьшение количества функций на 58,91% выглядит продуктивным. Четыре наиболее важных функции, выбранные ElasticNetCV, - это Condition2_PosN, MSZoning_C (все), Exterior1st_BrkComm и GrLivArea. Мы собираемся увидеть, как эти функции сравниваются с выбранными Xgboost.

Xgboost

Первую модель Xgboost мы начинаем с параметров по умолчанию.

Это уже намного лучше модели, выбранной ElasticNetCV!

Во второй модели Xgboost мы постепенно добавляем несколько параметров, которые должны повысить точность модели.

Опять улучшение!

Третья модель Xgboost, мы добавляем скорость обучения, надеюсь, она даст более точную модель.

К сожалению, улучшения не произошло. Я пришел к выводу, что xgb_model2 - лучшая модель.

Важность функции

from collections import OrderedDict
OrderedDict(sorted(xgb_model2.get_booster().get_fscore().items(), key=lambda t: t[1], reverse=True))

Xgboost выбрал 4 наиболее важных функции: LotArea, GrLivArea, TotalQual и TotalBsmtSF.

ElasticNetCV и Xgboost выбрали только одну функцию GrLivArea.

Итак, теперь мы собираемся выбрать некоторые важные функции и снова установить Xgboost.

Еще одно небольшое улучшение!

Блокнот Jupyter можно найти на Github. Наслаждайтесь остатком недели!