Цена дома может зависеть от удивительно странных особенностей. Мы попытаемся предсказать цену дома по 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)
Мы завершили прогноз цен на жилье. Если вам понравился этот урок, оставьте аплодисменты!