330 KiB
Приступаем к работе...¶
Вариант задания: Продажи домов в округе Кинг (вариант - 6)
Определим бизнес-цели и цели технического проекта
Бизнес-цели:¶
- Оптимизация процесса оценки стоимости дома
Формулировка: Разработать модель, которая позволяет автоматически и точно оценивать стоимость дома на основании его характеристик (таких как площадь, количество комнат, состояние, местоположение).
Цель: Увеличить точность оценки стоимости недвижимости для агенств и потенциальных покупателей, а также сократить время и затраты на оценку недвижимости, обеспечивая более точное предсказание цены.
Ключевые показатели успеха (KPI):
Точность модели прогнозирования (RMSE): Минимизация среднеквадратичной ошибки до уровня ниже 10% от реальной цены, чтобы учитывать большие отклонения оценке.
Средная абсолютная ошибка (MAE): Модель должна предсказать цену с минимальной ошибкой и снизить MAE до 5% или меньше учитывая большие отклонения в оценке.
Скорость оценки: Уменьшение времени на оценку стоимости дома, чтобы быстрее получать результат.
Доступность: Внедрение модели в реальную систему для использования агентами недвижимости.
- Оптимизация затрат на ремонт перед продажей
Формулировка: Разработать модель, которая поможет продавцам домов и агентствам недвижимости определить, какие улучшения или реновации дадут наибольший прирост стоимости дома при минимальных затратах. Это поможет избежать ненужных расходов и максимизировать прибыль от продажи.
Цель: Снизить затраты на ремонт перед продажей, рекомендовать только те улучшения, которые максимально увеличат стоимость недвижимости, и сократить время на принятие решений по реновациям.
Ключевые показатели успеха (KPI):
Возврат инвестиций (ROI): Продавцы должны получать не менее 20% прироста стоимости дома на каждый вложенный доллар в реновацию. Например, если на ремонт было потрачено $10,000, цена дома должна увеличиться как минимум на $12,000.
Средняя стоимость ремонта на 1 сделку (CPA): Задача снизить расходы на ремонт, минимизировав ненужные траты. Например, оптимизация затрат до $5,000 на дом с учетом максимального прироста в цене.
Сокращение времени на принятие решений: Модель должна сокращать время, необходимое на оценку вариантов реноваций, до нескольких минут, что ускорит подготовку дома к продажи.
Технические цели проекта для каждой выделенной бизнес-цели¶
Создание модели для точной оценки стоимости дома.
Сбор и подготовка данных: Очистка данных от пропусков, выбросов, дубликатов (аномальных значений в столбцах price, sqft_living, bedrooms). Преобразование категориальных переменных (view, condition, waterfront) в числовую форму с применением One-Hot-Encoding. Нормализация и стандартизация с применением методов масштабирования данных (нормировка, стандартизация для числовых признаков, чтобы привести их к 1ому масштабу). Разбиение набора данных на обучающую, контрольную и тестовую выборки для предотвращения утечек данных и переобучения.
Разработка и обучение модели: Исследование моделей машинного обучения, проводя эксперименты с различными алгоритмами (линейная регрессия, случайный лес, градиентный бустинг, деревья решений) для предсказания стоимости недвижимости. Обучение модели на обучающей выборке с использованием метрик оценки качества, таких как RMSE (Root Mean Square Error) и MAE (Mean Absolute Error). Оценка качества моделей на тестовой выборке, минимизируя MAE и RMSE для получения точных прогнозов стоимости.
Развёртывание модели: Интеграция модели в существующую систему или разработка API для доступа к модели с недвижимостью и частными продавцами. Создание веб-приложения или мобильного интерфейса для удобного использования модели и получения прогнозов в режиме реального времени.Разработка модели для рекомендаций по реновациям.
Сбор и подготовка данных: Сбор данных о типах и стоимости реноваций, а также их влияние на конечную стоимость дома. Очистка и устранение неточных или неполных данных о ремонтах. Преобразование категориальных признаков (реновации, например, обновление крыши, замена окон) в числовой формат для представления этих данных с применением One-Hot-Encoding. Разбиение данных на обучающую и тестовую выборки для обучения модели.
Разработка и обучение модели: Использование модели регрессий (линейная регрессия, случайный лес) для предсказания и моделирования влияния конкретных реноваций на увеличение стоимости недвижимости. Оценка метрики (CPA - Cost Per Acquisition) оценка затрат на реновацию одной продажи и (ROI - Return on Investment) расчёт возврата на инвестиции от реновации дома, прирост стоимости после реновации. Обучение модели с целью прогнозирования изменений, которые могут принести наибольшую пользу для стоимости домов и реноваций.
Развёртывание модели: Создание интерфейса, где пользователи смогут вводить информацию о текущем состоянии дома и получать рекомендации по реновациям с расчётом ROI. Создать рекомендационную систему для продавцов недвижимости, которая будет предлагать набор реноваций.
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
# Подключим датафрейм и выгрузим данные
df = pd.read_csv(".//static//csv//kc_house_data.csv")
print(df.columns)
# Для наглядности
df.head()
# Описание данных (основные статистические показатели)
df.describe()
# Процент пропущенных значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
# Проверка на пропущенные данные
print(df.isnull().sum())
df.isnull().any()
Ооо, пропущенных колонок нету :)
Разбиваем на выборки (обучающую, тестовую, контрольную)
from sklearn.model_selection import train_test_split
# Разделение данных на обучающую и тестовую выборки (80% - обучение, 20% - тестовая)
train_data, test_data = train_test_split(df, test_size=0.2, random_state=42)
# Разделение данных на обучающую и контрольную выборки (80% - обучение, 20% - контроль)
train_data, val_data = train_test_split(df, test_size=0.2, random_state=42)
print("Размер обучающей выборки: ", len(train_data))
print("Размер контрольной выборки: ", len(val_data))
print("Размер тестовой выборки: ", len(test_data))
# Оценка сбалансированности целевой переменной (цена)
# Визуализация распределения цены в выборках (гистограмма)
def plot_price_distribution(data, title):
sns.histplot(data['price'], kde=True)
plt.title(title)
plt.xlabel('Цена')
plt.ylabel('Частота')
plt.show()
plot_price_distribution(train_data, 'Распределение цены в обучающей выборке')
plot_price_distribution(val_data, 'Распределение цены в контрольной выборке')
plot_price_distribution(test_data, 'Распределение цены в тестовой выборке')
# Оценка сбалансированности данных по целевой переменной (price)
print("Средняя цена в обучающей выборке: ", train_data['price'].mean())
print("Средняя цена в контрольной выборке: ", val_data['price'].mean())
print("Средняя цена в тестовой выборке: ", test_data['price'].mean())
from sklearn.model_selection import train_test_split
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
# Преобразование целевой переменной (цены) в категориальные диапазоны с использованием квантилей
train_data['price_category'] = pd.qcut(train_data['price'], q=4, labels=['low', 'medium', 'high', 'very_high'])
# Визуализация распределения цен после преобразования в категории
sns.countplot(x=train_data['price_category'])
plt.title('Распределение категорий цены в обучающей выборке')
plt.xlabel('Категория цены')
plt.ylabel('Частота')
plt.show()
# Балансировка категорий с помощью RandomOverSampler (увеличение меньшинств)
ros = RandomOverSampler(random_state=42)
X_train = train_data.drop(columns=['price', 'price_category'])
y_train = train_data['price_category']
X_resampled, y_resampled = ros.fit_resample(X_train, y_train)
# Визуализация распределения цен после oversampling
sns.countplot(x=y_resampled)
plt.title('Распределение категорий цены после oversampling')
plt.xlabel('Категория цены')
plt.ylabel('Частота')
plt.show()
# Применение RandomUnderSampler для уменьшения большего класса
rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X_resampled, y_resampled)
# Визуализация распределения цен после undersampling
sns.countplot(x=y_resampled)
plt.title('Распределение категорий цены после undersampling')
plt.xlabel('Категория цен')
plt.ylabel('Частота')
plt.show()
# Печать размеров выборки после балансировки
print("Размер обучающей выборки после oversampling и undersampling: ", len(X_resampled))
Конструирование признаков¶
Теперь приступим к конструированию признаков для решения каждой задачи.
Процесс конструирования признаков
Задача 1: Прогнозирование цен недвижимости. Цель технического проекта: Разработка модели машинного обучения для точного прогнозирования рыночной стоимости недвижимости.
Задача 2: Оптимизация затрат на ремонт перед продажей. Цель технического проекта: Разработка модели машинного обучения для точного прогнозирования по рекомендациям по реновациям.
Унитарное кодирование
Унитарное кодирование категориальных признаков (one-hot encoding). Преобразование категориальных признаков в бинарные векторы.
Дискретизация числовых признаков
Процесс преобразования непрерывных числовых значений в дискретные категории или интервалы (бины).
# Конструирование признаков
# Унитарное кодирование категориальных признаков (применение one-hot encoding)
# Пример категориальных признаков
categorical_features = ['date', 'waterfront', 'view', 'condition']
# Применение one-hot encoding
train_data_encoded = pd.get_dummies(train_data, columns=categorical_features)
val_data_encoded = pd.get_dummies(val_data, columns=categorical_features)
test_data_encoded = pd.get_dummies(test_data, columns=categorical_features)
df_encoded = pd.get_dummies(df, columns=categorical_features)
print("Столбцы train_data_encoded:", train_data_encoded.columns.tolist())
print("Столбцы val_data_encoded:", val_data_encoded.columns.tolist())
print("Столбцы test_data_encoded:", test_data_encoded.columns.tolist())
# Дискретизация числовых признаков (цены). Например, можно разделить площадь жилья на категории
# Пример дискретизации признака 'Общая площадь'
train_data_encoded['sqtf'] = pd.cut(train_data_encoded['sqft_living'], bins=5, labels=False)
val_data_encoded['sqtf'] = pd.cut(val_data_encoded['sqft_living'], bins=5, labels=False)
test_data_encoded['sqtf'] = pd.cut(test_data_encoded['sqft_living'], bins=5, labels=False)
# Пример дискретизации признака 'sqft_living' на 5 категорий
df_encoded['sqtf'] = pd.cut(df_encoded['sqft_living'], bins=5, labels=False)
Ручной синтез¶
Создание новых признаков на основе экспертных знаний и логики предметной области. К примеру, для данных о продаже домов можно создать признак цена за квадратный фут.
# Ручной синтез признаков
train_data_encoded['price_per_sqft'] = df['price'] / df['sqft_living']
val_data_encoded['price_per_sqft'] = df['price'] / df['sqft_living']
test_data_encoded['price_per_sqft'] = df['price'] / df['sqft_living']
# Пример создания нового признака - цена за квадратный фут
df_encoded['price_per_sqft'] = df_encoded['price'] / df_encoded['sqft_living']
Масштабирование признаков - это процесс преобразования числовых признаков таким образом, чтобы они имели одинаковый масштаб. Это важно для многих алгоритмов машинного обучения, которые чувствительны к масштабу признаков, таких как линейная регрессия, метод опорных векторов (SVM) и нейронные сети.
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Пример масштабирования числовых признаков
numerical_features = ['bedrooms', 'sqft_living']
scaler = StandardScaler()
train_data_encoded[numerical_features] = scaler.fit_transform(train_data_encoded[numerical_features])
val_data_encoded[numerical_features] = scaler.transform(val_data_encoded[numerical_features])
test_data_encoded[numerical_features] = scaler.transform(test_data_encoded[numerical_features])
Конструирование признаков с применением фреймворка Featuretools¶
import featuretools as ft
# Предобработка данных (например, кодирование категориальных признаков, удаление дубликатов)
# Удаление дубликатов по идентификатору
df = df.drop_duplicates(subset='id')
duplicates = train_data_encoded[train_data_encoded['id'].duplicated(keep=False)]
# Удаление дубликатов из столбца "id", сохранив первое вхождение
df_encoded = df_encoded.drop_duplicates(subset='id', keep='first')
print(duplicates)
# Создание EntitySet
es = ft.EntitySet(id='house_data')
# Добавление датафрейма с домами
es = es.add_dataframe(dataframe_name='houses', dataframe=df_encoded, index='id')
# Генерация признаков с помощью глубокой синтезы признаков
feature_matrix, feature_defs = ft.dfs(entityset=es, target_dataframe_name='houses', max_depth=2)
# Выводим первые 5 строк сгенерированного набора признаков
print(feature_matrix.head())
train_data_encoded = train_data_encoded.drop_duplicates(subset='id')
train_data_encoded = train_data_encoded.drop_duplicates(subset='id', keep='first') # or keep='last'
# Определение сущностей (Создание EntitySet)
es = ft.EntitySet(id='house_data')
es = es.add_dataframe(dataframe_name='houses', dataframe=train_data_encoded, index='id')
# Генерация признаков
feature_matrix, feature_defs = ft.dfs(entityset=es, target_dataframe_name='houses', max_depth=2)
# Преобразование признаков для контрольной и тестовой выборок
val_feature_matrix = ft.calculate_feature_matrix(features=feature_defs, entityset=es, instance_ids=val_data_encoded.index)
test_feature_matrix = ft.calculate_feature_matrix(features=feature_defs, entityset=es, instance_ids=test_data_encoded.index)
Оценка качества каждого набора признаков¶
Предсказательная способность Метрики: RMSE, MAE, R²
Методы: Обучение модели на обучающей выборке и оценка на контрольной и тестовой выборках.
Скорость вычисления Методы: Измерение времени выполнения генерации признаков и обучения модели.
Надежность Методы: Кросс-валидация, анализ чувствительности модели к изменениям в данных.
Корреляция Методы: Анализ корреляционной матрицы признаков, удаление мультиколлинеарных признаков.
Цельность Методы: Проверка логической связи между признаками и целевой переменной, интерпретация результатов модели.
import time
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# Разделение данных на обучающую и валидационную выборки. Удаляем целевую переменную
X = feature_matrix.drop('price', axis=1)
y = feature_matrix['price']
# One-hot encoding для категориальных переменных (преобразование категориальных объектов в числовые)
X = pd.get_dummies(X, drop_first=True)
# Проверяем, есть ли пропущенные значения, и заполняем их медианой или другим подходящим значением
X.fillna(X.median(), inplace=True)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# Обучение модели
model = LinearRegression()
# Начинаем отсчет времени
start_time = time.time()
model.fit(X_train, y_train)
# Время обучения модели
train_time = time.time() - start_time
# Предсказания и оценка модели и вычисляем среднеквадратичную ошибку
predictions = model.predict(X_val)
mse = mean_squared_error(y_val, predictions)
print(f'Время обучения модели: {train_time:.2f} секунд')
print(f'Среднеквадратичная ошибка: {mse:.2f}')
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score, mean_absolute_error
from sklearn.model_selection import cross_val_score
# Удаление строк с NaN
feature_matrix = feature_matrix.dropna()
val_feature_matrix = val_feature_matrix.dropna()
test_feature_matrix = test_feature_matrix.dropna()
# Разделение данных на обучающую и тестовую выборки
X_train = feature_matrix.drop('price', axis=1)
y_train = feature_matrix['price']
X_val = val_feature_matrix.drop('price', axis=1)
y_val = val_feature_matrix['price']
X_test = test_feature_matrix.drop('price', axis=1)
y_test = test_feature_matrix['price']
X_test = X_test.reindex(columns=X_train.columns, fill_value=0)
# Кодирования категориальных переменных с использованием одноразового кодирования
X = pd.get_dummies(X, drop_first=True)
# Разобьём тренировочный тест и примерку модели
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Выбор модели
model = RandomForestRegressor(random_state=42)
# Обучение модели
model.fit(X_train, y_train)
# Предсказание и оценка
y_pred = model.predict(X_test)
rmse = mean_squared_error(y_test, y_pred, squared=False)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print()
print(f"RMSE: {rmse}")
print(f"R²: {r2}")
print(f"MAE: {mae} \n")
# Кросс-валидация
scores = cross_val_score(model, X_train, y_train, cv=5, scoring='neg_mean_squared_error')
rmse_cv = (-scores.mean())**0.5
print(f"Кросс-валидация RMSE: {rmse_cv} \n")
# Анализ важности признаков
feature_importances = model.feature_importances_
feature_names = X_train.columns
# Проверка на переобучение
y_train_pred = model.predict(X_train)
rmse_train = mean_squared_error(y_train, y_train_pred, squared=False)
r2_train = r2_score(y_train, y_train_pred)
mae_train = mean_absolute_error(y_train, y_train_pred)
print(f"Train RMSE: {rmse_train}")
print(f"Train R²: {r2_train}")
print(f"Train MAE: {mae_train}")
print()
# Визуализация результатов
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)
plt.xlabel('Фактическая цена')
plt.ylabel('Прогнозируемая цена')
plt.title('Фактическая цена по сравнению с прогнозируемой')
plt.show()
Выводы и итог¶
Модель случайного леса (RandomForestRegressor) показала удовлетворительные результаты при прогнозировании цен на недвижимость. Метрики качества и кросс-валидация позволяют предположить, что модель не сильно переобучена и может быть использована для практических целей.
Точность предсказаний: Модель демонстрирует довольно высокий R² (0.9987), что указывает на большую часть вариации целевого признака (цены недвижимости). Однако, значения RMSE и MAE остаются высоки (12930 и 2495), что свидетельствует о том, что модель не всегда точно предсказывает значения, особенно для объектов с высокими или низкими ценами.
Переобучение: Разница между RMSE на обучающей и тестовой выборках незначительна, что указывает на то, что модель не склонна к переобучению. Однако в будущем стоит следить за этой метрикой при добавлении новых признаков или усложнении модели, чтобы избежать излишней подгонки под тренировочные данные. Также стоит быть осторожным и продолжать мониторинг этого показателя.
Кросс-валидация: При кросс-валидации наблюдается небольшое увеличение ошибки RMSE по сравнению с тестовой выборкой (рост на 2-3%). Это может указывать на небольшую нестабильность модели при использовании разных подвыборок данных. Для повышения устойчивости модели возможно стоит провести дальнейшую настройку гиперпараметров.
Рекомендации: Следует уделить внимание дополнительной обработке категориальных признаков, улучшению метода feature engineering, а также возможной оптимизации модели (например, через подбор гиперпараметров) для повышения точности предсказаний на экстремальных значениях.
Кажется на этом закончили :)