Введение:

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

Набор данных:

Набор данных Boston Housing был первоначально опубликован в 1978 году Харрисоном и Рубинфельдом и с тех пор широко используется в регрессионном анализе. Он состоит из 506 наблюдений и 14 переменных, включая медианное значение домов, занимаемых владельцами, уровень преступности и соотношение учеников и учителей. Набор данных доступен в библиотеке scikit-learn на Python, что упрощает доступ и использование для анализа данных.

В этом разделе мы загрузим и изучим набор данных Boston Housing, чтобы лучше понять данные и их особенности. Мы будем использовать библиотеку Python pandas для загрузки набора данных в DataFrame и выполнения исследовательского анализа данных для выявления любых отсутствующих значений или выбросов.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston

boston = load_boston()
df = pd.DataFrame(boston.data, columns = boston.feature_names)
df['MEDV'] = boston.target
print(boston.data.shape)
print(boston.target.shape) 
print(boston.data[:5])  
print(boston.target[:5])  

В этом проекте мы работали с набором данных Boston Housing, который содержит информацию о различных особенностях домов в Бостоне. Мы загрузили набор данных с помощью функции load_boston() из библиотеки scikit-learn и преобразовали его в фрейм данных pandas. Фрейм данных содержит 13 функций и целевую переменную MEDV, которая представляет собой медианную стоимость домов, занимаемых владельцами, в тысячах долларов. Мы напечатали форму данных и целевых переменных, а также первые пять строк каждой из них, чтобы лучше понять данные.

corr_matrix = df.corr()

plt.figure(figsize=(12, 10))
sns.heatmap(corr_matrix, annot=True, cmap=plt.cm.Reds)
plt.show()

При анализе набора данных о жилье в Бостоне я решил исключить функции «RAD» и «NOX» из-за их высокой корреляции с другими переменными. Матрица корреляции показала, что эти два признака сильно коррелируют с другими признаками в наборе данных и, следовательно, они не важны для прогнозирования целевой переменной. Отбросив эти функции, я смог уменьшить сложность модели и улучшить ее производительность.

df2.hist(bins=30, figsize=(20,15))
plt.show()

Гистограмма, построенная с помощью функции df2.hist(), показывает распределение переменных в наборе данных. Параметр «bins» указывает количество интервалов, которые будут использоваться в гистограмме, а «figsize» устанавливает размер фигуры. Полученная гистограмма может дать представление о частоте и диапазоне переменных, а также выявить любые выбросы или необычные закономерности в данных.

sns.pairplot(df2, diag_kind='hist', corner=True)
plt.show()

Код используется для создания парного графика кадра данных «df2». Парная диаграмма показывает распределение каждой переменной по диагонали, а матрица диаграммы рассеяния каждой пары переменных — вне диагонали. Для параметра «diag_kind» установлено значение «hist», чтобы показать гистограмму каждой переменной, а для параметра «угол» установлено значение «Истина», чтобы отображать только нижний треугольник матрицы диаграммы рассеяния.

sns.jointplot(x='RM', y='MEDV', data=df2, kind='reg')
plt.show()

Этот код создает точечную диаграмму переменных «RM» (среднее количество комнат в жилище) и «MEDV» (медианное значение домов, занимаемых владельцами в 1000 долларов США), используя функцию совместного графика библиотеки Seaborn с типом «reg» (регрессия). . График показывает положительную корреляцию между двумя переменными, указывая на то, что дома с большим количеством комнат, как правило, имеют более высокие медианные значения. Линия регрессии имеет четкий положительный наклон, что свидетельствует о сильной взаимосвязи между переменными.

sns.boxplot(x=df2['MEDV'])

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

sns.distplot(df2['MEDV'], fit=stats.norm)
plt.show()

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

from sklearn.model_selection import train_test_split

X = df.drop('MEDV', axis=1)
y = df['MEDV']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

#################

from sklearn.linear_model import LinearRegression


X = df2[['RM']]


y = df2['MEDV']


model = LinearRegression()


model.fit(X_train, y_train)

y_pred = model.predict(X_test)

#######################

## Calculate performance metrics 
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
adj_r2 = 1 - (1-r2)*(len(y_test)-1)/(len(y_test)-X_test.shape[1]-1)

print("MSE:", mse)
print("MAE:", mae)
print("R-squared:", r2)
print("Adjusted R-squared:", adj_r2)

## ridge regression
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
X = df2.drop('MEDV', axis=1)
y = df2['MEDV']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)

y_pred = ridge.predict(X_test)

mse = mean_squared_error(y_test, y_pred)

print('MSE:', mse)
print('MAE:', mean_absolute_error(y_test, y_pred))
print('R-squared:', r2_score(y_test, y_pred))
print('Adjusted R-squared:', 1 - (1-r2_score(y_test, y_pred))*(len(y_test)-1)/(len(y_test)-X_test.shape[1]-1))
## Lasso Regression
from sklearn.linear_model import Lasso

lasso = Lasso(alpha=1.0)
lasso.fit(X_train, y_train)

y_pred = lasso.predict(X_test)

mse = mean_squared_error(y_test, y_pred)

print('MSE:', mse)
print('MAE:', mean_absolute_error(y_test, y_pred))
print('R-squared:', r2_score(y_test, y_pred))
print('Adjusted R-squared:', 1 - (1-r2_score(y_test, y_pred))*(len(y_test)-1)/(len(y_test)-X_test.shape[1]-1))

#######
## elasticnet regression
from sklearn.linear_model import ElasticNet

elasticnet = ElasticNet(alpha=1.0, l1_ratio=0.5)
elasticnet.fit(X_train, y_train)

y_pred = elasticnet.predict(X_test)

mse = mean_squared_error(y_test, y_pred)


############
## polynomial regression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

poly_features = PolynomialFeatures(degree=2)
X_poly = poly_features.fit_transform(X_train)

poly_reg = LinearRegression()
poly_reg.fit(X_poly, y_train)

X_test_poly = poly_features.fit_transform(X_test)

y_pred = poly_reg.predict(X_test_poly)

mse = mean_squared_error(y_test, y_pred)



###
## svr regression
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

svr = SVR(kernel='linear', C=1.0, epsilon=0.1)
svr.fit(X_train_scaled, y_train)

y_pred = svr.predict(X_test_scaled)

mse = mean_squared_error(y_test, y_pred)


## decision tree
from sklearn.tree import DecisionTreeRegressor

dt = DecisionTreeRegressor(max_depth=3, random_state=42)
dt.fit(X_train, y_train)

y_pred = dt.predict(X_test)

mse = mean_squared_error(y_test, y_pred)

####
##randomforest
from sklearn.ensemble import RandomForestRegressor

rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)

y_pred = rf.predict(X_test)

mse = mean_squared_error(y_test, y_pred)

print('MSE:', mse)
print('MAE:', mean_absolute_error(y_test, y_pred))
print('R-squared:', r2_score(y_test, y_pred))
print('Adjusted R-squared:', 1 - (1-r2_score(y_test, y_pred))*(len(y_test)-1)/(len(y_test)-X_test.shape[1]-1))

####
## Gradient boosting
from sklearn.ensemble import GradientBoostingRegressor

gb = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)
gb.fit(X_train, y_train)

y_pred = gb.predict(X_test)

mse = mean_squared_error(y_test, y_pred)

print('MSE:', mse)
print('MAE:', mean_absolute_error(y_test, y_pred))
print('R-squared:', r2_score(y_test, y_pred))
print('Adjusted R-squared:', 1 - (1-r2_score(y_test, y_pred))*(len(y_test)-1)/(len(y_test)-X_test.shape[1]-1))

  • Простая линейная регрессия: модель, в которой используется одна предикторная переменная для предсказания переменной отклика.
  • Множественная линейная регрессия: модель, которая использует несколько переменных-предикторов для прогнозирования переменной отклика.
  • Полиномиальная регрессия: модель, которая соответствует полиномиальной кривой к данным вместо прямой линии.
  • Гребневая регрессия: метод регуляризации, который добавляет к уравнению регрессии штрафной член для предотвращения переобучения.
  • Лассо-регрессия: еще один метод регуляризации, который добавляет штрафной член к уравнению регрессии, но также заставляет некоторые коэффициенты быть равными нулю.
  • Регрессия ElasticNet: комбинация гребенчатой ​​регрессии и регрессии лассо, которая добавляет штрафные условия L1 и L2 к уравнению регрессии.
  • Регрессия с усилением градиента: метод обучения ансамблю, который объединяет несколько деревьев решений для повышения точности и уменьшения дисперсии прогнозов.
errors = y_test - y_pred
import matplotlib.pyplot as plt
plt.plot(errors, marker='o', linestyle='')
plt.title('Error Graphic')
plt.xlabel('Data Point')
plt.ylabel('Error')
plt.show()

Данный фрагмент кода вычисляет ошибку между прогнозируемыми и фактическими значениями для тестовых данных в регрессионной модели DF2. Затем он отображает ошибки для каждой точки данных на точечной диаграмме с маркерами. Этот график помогает определить любые закономерности или тенденции в ошибках, что может дать представление о производительности модели. Ось X представляет точки данных, а ось Y представляет ошибку. Более высокое значение по оси Y указывает на большую ошибку для соответствующей точки данных. Заголовок графика и метки осей обеспечивают дополнительный контекст для понимания цели графика.

models = [ridge, lasso, elasticnet, svr, dt, rf, gb]
model_names = ['Ridge Regression', 'Lasso Regression', 'ElasticNet Regression', 'SVR', 'Decision Tree', 'Random Forest', 'Gradient Boosting']

fig, axs = plt.subplots(3, 3, figsize=(15,15))

for i, model in enumerate(models):
    y_pred = model.predict(X_test)
    axs[i//3, i%3].scatter(y_test, y_pred, color='blue')
    axs[i//3, i%3].plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=4)
    axs[i//3, i%3].set_xlabel('Real Values')
    axs[i//3, i%3].set_ylabel('Predicted Values')
    axs[i//3, i%3].set_title(model_names[i])

plt.tight_layout()
plt.show()

Приведенный выше код используется для создания точечной диаграммы фактических значений по сравнению с прогнозируемыми значениями для нескольких моделей регрессии, включая Ridge, Lasso, ElasticNet, SVR, Decision Tree, Random Forest и Gradient Boosting. Каждая модель строится на отдельном графике, а диагональная линия представляет собой идеальную линию прогноза, где фактические и прогнозируемые значения равны. Ось X каждого подграфика представляет фактические значения, а ось Y представляет прогнозируемые значения. Эта визуализация помогает оценить производительность различных моделей регрессии и сравнить их на основе их прогностической способности.

# Create a pivot table to show all metrics for each model
df_metrics_pivot = pd.pivot_table(df_metrics, index='Model', 
                                   values=['R2 Score', 'Adjusted R2 Score', 'Mean Absolute Error', 'Mean Squared Error'])

# Display the pivot table
df_metrics_pivot

Основываясь на показателях производительности регрессионных моделей, мы можем заметить, что модели Random Forest и Gradient Boosting превзошли другие модели в прогнозировании целевой переменной «MEDV». Обе модели показали одинаковые результаты с точки зрения значений R-квадрата и скорректированного R-квадрата, что указывает на то, что они хорошо объясняют изменчивость данных. Кроме того, обе модели имеют более низкие значения MSE и MAE, что позволяет предположить, что они допустили меньше ошибок в прогнозировании. Таким образом, можно сделать вывод, что модели Random Forest и Gradient Boosting являются лучшими моделями для прогнозирования целевой переменной «MEDV» в этом наборе данных.

В заключение мы можем сказать, что наши регрессионные модели достаточно хорошо показали себя в прогнозировании средней стоимости домов, занимаемых владельцами. Однако, как однажды сказал известный статистик Джордж Бокс: «Все модели ошибочны, но некоторые из них полезны». Поэтому мы всегда должны помнить, что наши модели имеют ограничения и никогда не смогут идеально отразить сложную природу данных реального мира. Будем надеяться, что наши модели достаточно полезны, чтобы помочь нам принимать обоснованные решения на рынке недвижимости!