Цена дома может зависеть от удивительно странных особенностей. Мы попытаемся предсказать цену дома по 79 характеристикам. Для этого воспользуемся набором данных Цены на жилье от Kaggle.

Импорт библиотек

Давайте сначала импортируем необходимые библиотеки. Если у вас не установлена ​​определенная библиотека, запустите команду ‘pip install ‹package_name›, чтобы установить ее.

import os
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import skew
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor

Загрузка наборов данных

Мы загрузим данные из Kaggle и разархивируем их в каталог с именем house_prices. Давайте посмотрим, что было внутри каталога, в который мы разархивировали данные.

for dirname, _, filenames in os.walk('./house_prices'):
    for filename in filenames:
        print(filename)

Мы загрузим поезд и тестовый набор данных. Далее распечатаем их формы.

train = pd.read_csv('./house_prices/train.csv')
test = pd.read_csv('./house_prices/test.csv')
print(f'Train shape : {train.shape}')
print(f'Test shape : {test.shape}')

Визуализация набора данных

Мы напечатаем заголовки наборов данных train и test, чтобы увидеть, как они выглядят на самом деле.

train.head(10)

test.head(10)

Мы воспользуемся функцией description, чтобы получить описание столбца «SalesPrice».

print(train['SalePrice'].describe())

Давайте изобразим распределение SalesPrice с помощью гистограммы. Мы можем ясно видеть, что распределение искажено вправо.

sns.histplot(train['SalePrice'],kde=True)

Мы воспользуемся преобразованием журнала, чтобы устранить перекос в распределении.

train['SalePrice'] = np.log1p(train['SalePrice'])
sns.histplot(train['SalePrice'],kde=True)

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

corr = train.corr()
highly_corr_features = corr.index[abs(corr["SalePrice"])>0.5]
plt.figure(figsize=(10,10))
map = sns.heatmap(train[highly_corr_features].corr(),annot=True,cmap="RdYlGn")

Давайте посмотрим на 10 основных функций, связанных с SalesPrice.

corr["SalePrice"].sort_values(ascending=False).head(10)

Давайте сопоставим некоторые характеристики с SalesPrice, чтобы увидеть, как они меняются по сравнению с SalesPrice.

fig = plt.figure(figsize=(12,10))
#GarageArea
plt.subplot(321)
sns.scatterplot(data=train, x='GarageArea', y="SalePrice")
#YearBuilt
plt.subplot(322)
sns.scatterplot(data=train, x='YearBuilt', y="SalePrice")
#WoodDeckSF
plt.subplot(323)
sns.scatterplot(data=train, x='WoodDeckSF', y="SalePrice")
#OverallQual
plt.subplot(324)
sns.scatterplot(data=train, x='OverallQual', y="SalePrice")
#BsmtUnfSF
plt.subplot(325)
sns.scatterplot(data=train, x='BsmtUnfSF', y="SalePrice")
#TotalBsmtSF
plt.subplot(326)
sns.scatterplot(data=train, x='TotalBsmtSF', y="SalePrice")

Мы объединим наборы данных train и test, чтобы упростить предварительную обработку. Позже мы их еще раз разделим.

data = pd.concat([train,test], axis=0)
y_train = train['SalePrice']
data = data.drop(['Id', 'SalePrice'], axis=1)
print(data.shape)

Давайте получим информацию о объединенном фрейме данных.

data.info()

Чтобы увидеть распределение типов данных по столбцам, мы построим круговую диаграмму.

data.dtypes.value_counts().plot.pie()

Напечатаем количество уникальных значений в каждом столбце.

print('UNIQUE VALUES\n')
for col in data.columns:
    print(f'{col}: {len(data[col].unique())}\n')

Мы опишем каждый столбец в данных, кроме столбцов с типом данных объекта.

data[data.select_dtypes(exclude='object').columns].describe()

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

#Visualizing the null values in all columns
plt.figure(figsize=(30,8));
sns.heatmap(data.isnull(), cmap='flare');

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

#Columns containing most null values
total = data.isnull().sum().sort_values(ascending=False)
percent = (data.isnull().sum() / data.isnull().count()*100).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
print(missing_data.head(10))

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

Если мы наблюдаем функции с отсутствующими значениями более 5, мы заметим, что они не важны и ни один из них не коррелирует ›0,5. Таким образом, мы можем удалить их без потери каких-либо существенных деталей.

Затем мы увидим, какие из оставшихся столбцов имеют нулевые значения.

#Dropping columns with > 5 null values
data.drop((missing_data[missing_data['Total'] > 5]).index, axis=1, inplace=True)
#Sorting columns w.r.t null values
total = data.isnull().sum().sort_values(ascending=False)
total.head(20)

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

Мы также удалим столбец «Утилиты», поскольку он содержит только одно значение, а именно «AllPub».

#Filling the numeric data
numeric_missed = ['BsmtFinSF1',
'BsmtFinSF2',
'BsmtUnfSF',
'TotalBsmtSF',
'BsmtFullBath',
'BsmtHalfBath',
'GarageArea',
'GarageCars']
for feature in numeric_missed:
    data[feature] = data[feature].fillna(0)
#Filling the categorical data
categorical_missed = ['Exterior1st',
'Exterior2nd',
'SaleType',
'MSZoning',
'Electrical',
'KitchenQual',
'Functional']
for feature in categorical_missed:
    data[feature] = data[feature].fillna(data[feature].mode()[0])
#Deleting 'Utilities' column
data.drop(['Utilities'], axis=1, inplace=True)

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

#Checking for any remaining null values
data.isnull().sum().max()

Давайте найдем наиболее искаженные столбцы в данных.

#Top skewed columns
numeric_features = data.dtypes[data.dtypes != 'object'].index
skewed_features = data[numeric_features].apply(lambda x: skew(x)).sort_values(ascending=False)
high_skew = skewed_features[abs(skewed_features) > 0.5]
print(high_skew)

Давайте применим преобразования журнала ко всем этим перекошенным столбцам.

#Transforming skewed columns
for feature in high_skew.index:
    data[feature] = np.log1p(data[feature])

Преобразуем категориальные переменные в числовые. Мы сделаем это с помощью метода get_dummies ().

#Converting categorical data to numerical
data = pd.get_dummies(data)
data.head()

Мы разделим данные на train и test. Мы будем использовать y_train, который мы создали в начале.

#Dividing data back into train & test
train =data[:len(y_train)]
test = data[len(y_train):]
#Printing thier shapes
print(train.shape, test.shape)

Далее мы разделим данные train на x_train, x_test, y_train и y_test , чтобы мы могли измерить производительность нашей модели.

x_train, x_test, y_train, y_test = train_test_split(train, y_train, test_size=0.2, random_state=42)

Создание модели

Давайте теперь определим нашу модель. Для этого мы воспользуемся RandomForestRegressor из sklearn.ensemble.

clf = RandomForestRegressor(n_estimators=300)

Мы будем использовать x_train и y_train, чтобы соответствовать нашей модели.

clf.fit(x_train, y_train)

Давайте посчитаем оценку нашей модели, используя x_test и y_test.

clf.score(x_test,y_test)

Прогноз

Мы подогнали модель и убедились в ее характеристиках. Спрогнозируем цены на дома на реальных тестовых данных.

#Making an prediction
prediction = clf.predict(test)
print(prediction)

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

#Applying reverse of log, i.e exp
np.expm1(prediction)

Мы завершили прогноз цен на жилье. Если вам понравился этот урок, оставьте аплодисменты!