751 KiB
Лаб работа №4¶
Вариант 6 - Продажа домов в округе кинг
Задача регрессии заключается в предсказании цен на недвижимость, что поможет риэлторам и аналитикам оценить справедливую рыночную стоимость объектов.
Задача классификации предполагает определение вероятности того, что цена дома будет выше или ниже медианы рынка, а также классификацию домов по ценовым категориям (например, низкая, средняя, высокая). Это поможет выявить предпочтения покупателей.
Для оценки регрессионных моделей будут использоваться метрики MAE (средняя абсолютная ошибка) и R² (коэффициент детерминации), с целью достижения MAE менее 10% от средней цены. В классификации основное внимание уделяется метрикам accuracy и F1-score, с целевым значением accuracy около 80%.
Ориентиры для каждой задачи:¶
Регрессия: Медианная цена (price.median()) выбрана как стабильный ориентир.
Классификация: Ориентиром служит средняя вероятность предсказания класса выше медианы.
Анализ алгоритмов машинного обучения:
Регрессия:¶
Линейная регрессия: Подходит для простых линейных зависимостей.
Дерево решений: Учет нелинейных зависимостей и сложных закономерностей.
Случайный лес: Ансамблевый метод, обобщающий данные и эффективно обрабатывающий выбросы.
Классификация:¶
Логистическая регрессия: Простая модель для бинарной классификации.
Метод опорных векторов (SVM): Эффективен на данных с четкими разделениями.
Градиентный бустинг: Подходит для сложных и высокоразмерных данных, обеспечивает высокую точность.
Выбор трех моделей для каждой задачи:¶
Регрессия: Линейная регрессия, Дерево решений, Случайный лес.
Классификация: Логистическая регрессия, Метод опорных векторов (SVM), Градиентный бустинг.
import pandas as pd
from sklearn import set_config
set_config(transform_output="pandas")
random_state = 42
df = pd.read_csv(".//static//csv//kc_house_data.csv")
print(df.columns)
df.head()
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from typing import Tuple
import pandas as pd
from pandas import DataFrame
from sklearn.model_selection import train_test_split
median_price = df['price'].median()
df['above_median_price'] = np.where(df['price'] > median_price, 1, 0)
X = df.drop(columns=['id', 'date', 'price', 'above_median_price'])
y = df['above_median_price']
df['price_category'] = pd.cut(df['price'], bins=[0, 300000, 700000, np.inf], labels=[0, 1, 2])
X = df.drop(columns=['id', 'date', 'price', 'price_category'])
def split_stratified_into_train_val_test(
df_input,
stratify_colname="y",
frac_train=0.6,
frac_val=0.15,
frac_test=0.25,
random_state=None,
) -> Tuple[DataFrame, DataFrame, DataFrame, DataFrame, DataFrame, DataFrame]:
if frac_train + frac_val + frac_test != 1.0:
raise ValueError(
"fractions %f, %f, %f do not add up to 1.0"
% (frac_train, frac_val, frac_test)
)
if stratify_colname not in df_input.columns:
raise ValueError("%s is not a column in the dataframe" % (stratify_colname))
X = df_input # Contains all columns.
y = df_input[
[stratify_colname]
] # Dataframe of just the column on which to stratify.
# Split original dataframe into train and temp dataframes.
df_train, df_temp, y_train, y_temp = train_test_split(
X, y, stratify=y, test_size=(1.0 - frac_train), random_state=random_state
)
if frac_val <= 0:
assert len(df_input) == len(df_train) + len(df_temp)
return df_train, pd.DataFrame(), df_temp, y_train, pd.DataFrame(), y_temp
# Split the temp dataframe into val and test dataframes.
relative_frac_test = frac_test / (frac_val + frac_test)
df_val, df_test, y_val, y_test = train_test_split(
df_temp,
y_temp,
stratify=y_temp,
test_size=relative_frac_test,
random_state=random_state,
)
assert len(df_input) == len(df_train) + len(df_val) + len(df_test)
return df_train, df_val, df_test, y_train, y_val, y_test
X_train, X_val, X_test, y_train, y_val, y_test = split_stratified_into_train_val_test(
df, stratify_colname="above_median_price", frac_train=0.80, frac_val=0, frac_test=0.20, random_state=42
)
display("X_train", X_train)
display("y_train", y_train)
display("X_test", X_test)
display("y_test", y_test)
print(df.dtypes)
plt.figure(figsize=(10, 6))
sns.histplot(df['price'], bins=50, kde=True)
plt.title('Распределение цен на недвижимость')
plt.xlabel('Цена')
plt.ylabel('Частота')
plt.show()
plt.figure(figsize=(10, 6))
sns.boxplot(x='bedrooms', y='price', data=df)
plt.title('Зависимость цены от количества спален')
plt.xlabel('Количество спален')
plt.ylabel('Цена')
plt.show()
Конвейеры предобработки¶
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.compose import ColumnTransformer
from sklearn.discriminant_analysis import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
pipeline_end = StandardScaler()
# Построение конвейеров предобработки
class HouseFeatures(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
# Создание новых признаков
X = X.copy()
X["Living_area_to_Lot_ratio"] = X["sqft_living"] / X["sqft_lot"]
return X
def get_feature_names_out(self, features_in):
# Добавление имен новых признаков
new_features = ["Living_area_to_Lot_ratio"]
return np.append(features_in, new_features, axis=0)
# Обработка числовых данных. Числовой конвейр: заполнение пропущенных значений медианой и стандартизация
preprocessing_num_class = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
preprocessing_cat_class = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
columns_to_drop = ["date"]
numeric_columns = ["sqft_living", "sqft_lot", "above_median_price"]
cat_columns = []
features_preprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("prepocessing_num", preprocessing_num_class, numeric_columns),
("prepocessing_cat", preprocessing_cat_class, cat_columns),
],
remainder="passthrough"
)
drop_columns = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("drop_columns", "drop", columns_to_drop),
],
remainder="passthrough",
)
features_postprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
('preprocessing_cat', preprocessing_cat_class, ["price_category"]),
],
remainder="passthrough",
)
pipeline_end = Pipeline(
[
("features_preprocessing", features_preprocessing),
("custom_features", HouseFeatures()),
("drop_columns", drop_columns),
]
)
preprocessing_result = pipeline_end.fit_transform(X_train)
preprocessed_df = pd.DataFrame(
preprocessing_result,
columns=pipeline_end.get_feature_names_out(),
)
preprocessed_df
Формирование набора моделей для классификации¶
from sklearn import ensemble, linear_model, naive_bayes, neighbors, neural_network, tree, svm
class_models = {
"logistic": {"model": linear_model.LogisticRegression(max_iter=150)}, # логистическая
"ridge": {"model": linear_model.RidgeClassifierCV(cv=5, class_weight="balanced")}, # гребневая регрессия
"ridge": {"model": linear_model.LogisticRegression(max_iter=150, solver='lbfgs', penalty="l2", class_weight="balanced")},
"decision_tree": { # дерево решений
"model": tree.DecisionTreeClassifier(max_depth=5, min_samples_split=10, random_state=random_state)
},
"knn": {"model": neighbors.KNeighborsClassifier(n_neighbors=7)},
"naive_bayes": {"model": naive_bayes.GaussianNB()}, # наивный Байесовский классификатор
# метод градиентного бустинга (набор деревьев решений)
"gradient_boosting": {
"model": ensemble.GradientBoostingClassifier(n_estimators=210)
},
# метод случайного леса (набор деревьев решений)
"random_forest": {
"model": ensemble.RandomForestClassifier(
max_depth=5, class_weight="balanced", random_state=random_state
)
},
# многослойный персептрон (нейронная сеть)
"mlp": {
"model": neural_network.MLPClassifier(
hidden_layer_sizes=(7,),
max_iter=200,
early_stopping=True,
random_state=random_state,
)
},
}
import numpy as np
from sklearn import metrics
for model_name in class_models.keys():
print(f"Model: {model_name}")
model = class_models[model_name]["model"]
model_pipeline = Pipeline([("pipeline", pipeline_end), ("model", model)])
model_pipeline = model_pipeline.fit(X_train, y_train.values.ravel())
y_train_predict = model_pipeline.predict(X_train)
y_test_probs = model_pipeline.predict_proba(X_test)[:, 1]
y_test_predict = np.where(y_test_probs > 0.5, 1, 0)
class_models[model_name]["pipeline"] = model_pipeline
class_models[model_name]["probs"] = y_test_probs
class_models[model_name]["preds"] = y_test_predict
class_models[model_name]["Precision_train"] = metrics.precision_score(
y_train, y_train_predict, zero_division=1
)
class_models[model_name]["Precision_test"] = metrics.precision_score(
y_test, y_test_predict, zero_division=1
)
class_models[model_name]["Recall_train"] = metrics.recall_score(
y_train, y_train_predict
)
class_models[model_name]["Recall_test"] = metrics.recall_score(
y_test, y_test_predict
)
class_models[model_name]["Accuracy_train"] = metrics.accuracy_score(
y_train, y_train_predict
)
class_models[model_name]["Accuracy_test"] = metrics.accuracy_score(
y_test, y_test_predict
)
class_models[model_name]["ROC_AUC_test"] = metrics.roc_auc_score(
y_test, y_test_probs
)
class_models[model_name]["F1_train"] = metrics.f1_score(y_train, y_train_predict)
class_models[model_name]["F1_test"] = metrics.f1_score(y_test, y_test_predict)
class_models[model_name]["MCC_test"] = metrics.matthews_corrcoef(
y_test, y_test_predict
)
class_models[model_name]["Cohen_kappa_test"] = metrics.cohen_kappa_score(
y_test, y_test_predict
)
class_models[model_name]["Confusion_matrix"] = metrics.confusion_matrix(
y_test, y_test_predict
)
from sklearn.metrics import ConfusionMatrixDisplay
import matplotlib.pyplot as plt
_, ax = plt.subplots(int(len(class_models) / 2), 2, figsize=(12, 10), sharex=False, sharey=False)
for index, key in enumerate(class_models.keys()):
c_matrix = class_models[key]["Confusion_matrix"]
disp = ConfusionMatrixDisplay(
confusion_matrix=c_matrix, display_labels=["Less", "More"]
).plot(ax=ax.flat[index])
disp.ax_.set_title(key)
plt.subplots_adjust(top=1, bottom=0, hspace=0.4, wspace=0.1)
plt.show()
class_metrics = pd.DataFrame.from_dict(class_models, "index")[
[
"Precision_train",
"Precision_test",
"Recall_train",
"Recall_test",
"Accuracy_train",
"Accuracy_test",
"F1_train",
"F1_test",
]
]
class_metrics.sort_values(
by="Accuracy_test", ascending=False
).style.background_gradient(
cmap="plasma",
low=0.3,
high=1,
subset=["Accuracy_train", "Accuracy_test", "F1_train", "F1_test"],
).background_gradient(
cmap="viridis",
low=1,
high=0.3,
subset=[
"Precision_train",
"Precision_test",
"Recall_train",
"Recall_test",
],
)
Мы видим, что некоторые модели показывают 100% точность и в последствие начинают плохо работать на новых данных. Поэтому происходит переобучение (overfitting) модели .
class_metrics = pd.DataFrame.from_dict(class_models, "index")[
[
"Accuracy_test",
"F1_test",
"ROC_AUC_test",
"Cohen_kappa_test",
"MCC_test",
]
]
class_metrics.sort_values(by="ROC_AUC_test", ascending=False).style.background_gradient(
cmap="plasma",
low=0.3,
high=1,
subset=[
"ROC_AUC_test",
"MCC_test",
"Cohen_kappa_test",
],
).background_gradient(
cmap="viridis",
low=1,
high=0.3,
subset=[
"Accuracy_test",
"F1_test",
],
)
best_model = str(class_metrics.sort_values(by="MCC_test", ascending=False).iloc[0].name)
display(best_model)
preprocessing_result = pipeline_end.transform(X_test)
preprocessed_df = pd.DataFrame(
preprocessing_result,
columns=pipeline_end.get_feature_names_out(),
)
model = class_models[best_model]["pipeline"]
example_id = 6863
test = pd.DataFrame(X_test.loc[example_id, :]).T
test_preprocessed = pd.DataFrame(preprocessed_df.loc[example_id, :]).T
display(test)
display(test_preprocessed)
result_proba = model.predict_proba(test)[0]
result = model.predict(test)[0]
real = int(y_test.loc[example_id].values[0])
display(f"predicted: {result} (proba: {result_proba})")
display(f"real: {real}")
Новые гиперпараметры¶
from sklearn.model_selection import GridSearchCV
optimized_model_type = "random_forest"
random_forest_model = class_models[optimized_model_type]["pipeline"]
param_grid = {
"model__n_estimators": [10, 50, 100],
"model__max_features": ["sqrt", "log2"],
"model__max_depth": [5, 7, 10],
"model__criterion": ["gini", "entropy"],
}
gs_optomizer = GridSearchCV(
estimator=random_forest_model, param_grid=param_grid, n_jobs=-1
)
gs_optomizer.fit(X_train, y_train.values.ravel())
gs_optomizer.best_params_
optimized_model = ensemble.RandomForestClassifier(
random_state=random_state,
criterion="gini",
max_depth=5,
max_features="log2",
n_estimators=10,
)
result = {}
result["pipeline"] = Pipeline([("pipeline", pipeline_end), ("model", optimized_model)]).fit(X_train, y_train.values.ravel())
result["train_preds"] = result["pipeline"].predict(X_train)
result["probs"] = result["pipeline"].predict_proba(X_test)[:, 1]
result["preds"] = np.where(result["probs"] > 0.5, 1, 0)
result["Precision_train"] = metrics.precision_score(y_train, result["train_preds"])
result["Precision_test"] = metrics.precision_score(y_test, result["preds"])
result["Recall_train"] = metrics.recall_score(y_train, result["train_preds"])
result["Recall_test"] = metrics.recall_score(y_test, result["preds"])
result["Accuracy_train"] = metrics.accuracy_score(y_train, result["train_preds"])
result["Accuracy_test"] = metrics.accuracy_score(y_test, result["preds"])
result["ROC_AUC_test"] = metrics.roc_auc_score(y_test, result["probs"])
result["F1_train"] = metrics.f1_score(y_train, result["train_preds"])
result["F1_test"] = metrics.f1_score(y_test, result["preds"])
result["MCC_test"] = metrics.matthews_corrcoef(y_test, result["preds"])
result["Cohen_kappa_test"] = metrics.cohen_kappa_score(y_test, result["preds"])
result["Confusion_matrix"] = metrics.confusion_matrix(y_test, result["preds"])
optimized_metrics = pd.DataFrame(columns=list(result.keys()))
optimized_metrics.loc[len(optimized_metrics)] = pd.Series(
data=class_models[optimized_model_type]
)
optimized_metrics.loc[len(optimized_metrics)] = pd.Series(
data=result
)
optimized_metrics.insert(loc=0, column="Name", value=["Old", "New"])
optimized_metrics = optimized_metrics.set_index("Name")
optimized_metrics[
[
"Accuracy_test",
"F1_test",
"ROC_AUC_test",
"Cohen_kappa_test",
"MCC_test",
]
].style.background_gradient(
cmap="plasma",
low=0.3,
high=1,
subset=[
"ROC_AUC_test",
"MCC_test",
"Cohen_kappa_test",
],
).background_gradient(
cmap="viridis",
low=1,
high=0.3,
subset=[
"Accuracy_test",
"F1_test",
],
)
Мы видим изумительную точность новой модели. Модели не допускают никаких ошибок в предсказании.
Задача регресии: предсказание цены дома (price)¶
import pandas as pd
from sklearn import set_config
set_config(transform_output="pandas")
random_state = 42
average_price = df['sqft_living'].mean()
print(f"Среднее значение поля: {average_price}")
# Создание новой колонки, указывающей, выше или ниже среднего значение цена закрытия
df['average_price'] = (df['sqft_living'] > average_price).astype(int)
# Удаление последней строки, где нет значения для следующего дня
df.dropna(inplace=True)
print(df.head())
print("Статистическое описание DataFrame:")
print(df.describe())
from typing import Tuple
from pandas import DataFrame
from sklearn.model_selection import train_test_split
def split_into_train_test(
df_input: DataFrame,
target_colname: str = "average_price",
frac_train: float = 0.8,
random_state: int = None,
) -> Tuple[DataFrame, DataFrame, DataFrame, DataFrame]:
if not (0 < frac_train < 1):
raise ValueError("Fraction must be between 0 and 1.")
# Проверка наличия целевого признака
if target_colname not in df_input.columns:
raise ValueError(f"{target_colname} is not a column in the DataFrame.")
# Разделяем данные на признаки и целевую переменную
X = df_input.drop(columns=[target_colname]) # Признаки
y = df_input[[target_colname]] # Целевая переменная
# Разделяем данные на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=(1.0 - frac_train),
random_state=random_state
)
return X_train, X_test, y_train, y_test
# Применение функции для разделения данных
X_train, X_test, y_train, y_test = split_into_train_test(
df,
target_colname="average_price",
frac_train=0.8,
random_state=42 # Убедитесь, что вы задали нужное значение random_state
)
display("X_train", X_train)
display("y_train", y_train)
display("X_test", X_test)
display("y_test", y_test)
Формирование конвейера для решения задачи регрессии¶
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.ensemble import RandomForestRegressor # Пример регрессионной модели
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
class HouseFeatures(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
# Создание новых признаков
X = X.copy()
X["Square"] = X["sqft_living"] / X["sqft_lot"]
return X
def get_feature_names_out(self, features_in):
# Добавление имен новых признаков
new_features = ["Square"]
return np.append(features_in, new_features, axis=0)
# Указываем столбцы, которые нужно удалить и обрабатывать
columns_to_drop = ["date"]
num_columns = ["bathrooms", "floors", "waterfront", "view"]
cat_columns = []
# Определяем предобработку для численных данных
num_imputer = SimpleImputer(strategy="median")
num_scaler = StandardScaler()
preprocessing_num = Pipeline(
[
("imputer", num_imputer),
("scaler", num_scaler),
]
)
# Определяем предобработку для категориальных данных
cat_imputer = SimpleImputer(strategy="constant", fill_value="unknown")
cat_encoder = OneHotEncoder(handle_unknown="ignore", sparse_output=False, drop="first")
preprocessing_cat = Pipeline(
[
("imputer", cat_imputer),
("encoder", cat_encoder),
]
)
# Подготовка признаков с использованием ColumnTransformer
features_preprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("preprocessing_num", preprocessing_num, num_columns),
("preprocessing_cat", preprocessing_cat, cat_columns),
],
remainder="passthrough"
)
# Удаление нежелательных столбцов
drop_columns = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("drop_columns", "drop", columns_to_drop),
],
remainder="passthrough",
)
# Постобработка признаков
features_postprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("preprocessing_cat", preprocessing_cat, ["price_category"]),
],
remainder="passthrough",
)
# Создание окончательного конвейера
pipeline = Pipeline(
[
("features_preprocessing", features_preprocessing),
("drop_columns", drop_columns),
("custom_features", HouseFeatures()),
("model", RandomForestRegressor()) # Выбор модели для обучения
]
)
# Использование конвейера
def train_pipeline(X, y):
pipeline.fit(X, y)
import numpy as np
from sklearn import metrics
from sklearn.pipeline import Pipeline
# Проверка наличия необходимых переменных
if 'class_models' not in locals():
raise ValueError("class_models is not defined")
if 'X_train' not in locals() or 'X_test' not in locals() or 'y_train' not in locals() or 'y_test' not in locals():
raise ValueError("Train/test data is not defined")
y_train = np.ravel(y_train)
y_test = np.ravel(y_test)
# Инициализация списка для хранения результатов
results = []
# Проход по моделям и оценка их качества
for model_name in class_models.keys():
print(f"Model: {model_name}")
# Извлечение модели из словаря
model = class_models[model_name]["model"]
# Создание пайплайна
model_pipeline = Pipeline([("pipeline", pipeline_end), ("model", model)])
# Обучение модели
model_pipeline.fit(X_train, y_train)
# Предсказание для обучающей и тестовой выборки
y_train_predict = model_pipeline.predict(X_train)
y_test_predict = model_pipeline.predict(X_test)
# Сохранение пайплайна и предсказаний
class_models[model_name]["pipeline"] = model_pipeline
class_models[model_name]["preds"] = y_test_predict
# Вычисление метрик для регрессии
class_models[model_name]["MSE_train"] = metrics.mean_squared_error(y_train, y_train_predict)
class_models[model_name]["MSE_test"] = metrics.mean_squared_error(y_test, y_test_predict)
class_models[model_name]["MAE_train"] = metrics.mean_absolute_error(y_train, y_train_predict)
class_models[model_name]["MAE_test"] = metrics.mean_absolute_error(y_test, y_test_predict)
class_models[model_name]["R2_train"] = metrics.r2_score(y_train, y_train_predict)
class_models[model_name]["R2_test"] = metrics.r2_score(y_test, y_test_predict)
# Дополнительные метрики
class_models[model_name]["STD_train"] = np.std(y_train - y_train_predict)
class_models[model_name]["STD_test"] = np.std(y_test - y_test_predict)
# Вывод результатов для текущей модели
print(f"MSE (train): {class_models[model_name]['MSE_train']}")
print(f"MSE (test): {class_models[model_name]['MSE_test']}")
print(f"MAE (train): {class_models[model_name]['MAE_train']}")
print(f"MAE (test): {class_models[model_name]['MAE_test']}")
print(f"R2 (train): {class_models[model_name]['R2_train']}")
print(f"R2 (test): {class_models[model_name]['R2_test']}")
print(f"STD (train): {class_models[model_name]['STD_train']}")
print(f"STD (test): {class_models[model_name]['STD_test']}")
print("-" * 40) # Разделитель для разных моделей
Пример использования обученной модели (конвейера регрессии) для предсказания
Подбор гиперпараметров методом поиска по сетке
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
# Convert the date column to a datetime object and extract numeric features
df['date'] = pd.to_datetime(df['date'], errors='coerce') # Coerce invalid dates to NaT
df.dropna(subset=['date'], inplace=True) # Drop rows with invalid dates
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
# Prepare predictors and target
X = df[['yr_built', 'year', 'month', 'day', 'price', 'price_category']]
y = df['average_price']
# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Define model and parameter grid
model = RandomForestRegressor()
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10]
}
# Hyperparameter tuning with GridSearchCV
grid_search = GridSearchCV(estimator=model, param_grid=param_grid,
scoring='neg_mean_squared_error', cv=5, n_jobs=-1, verbose=2)
# Fit the model
grid_search.fit(X_train, y_train)
# Output the best parameters and score
print("Best parameters:", grid_search.best_params_)
print("Best MSE:", -grid_search.best_score_)
import pandas as pd
import numpy as np
from sklearn import metrics
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split, GridSearchCV
import matplotlib.pyplot as plt
# 1. Настройка параметров для старых значений
old_param_grid = {
'n_estimators': [50, 100, 200], # Количество деревьев
'max_depth': [None, 10, 20, 30], # Максимальная глубина дерева
'min_samples_split': [2, 10, 15] # Минимальное количество образцов для разбиения узла
}
# Подбор гиперпараметров с помощью Grid Search для старых параметров
old_grid_search = GridSearchCV(estimator=RandomForestRegressor(),
param_grid=old_param_grid, scoring='neg_mean_squared_error', cv=5, n_jobs=-1, verbose=2)
# Обучение модели на тренировочных данных
old_grid_search.fit(X_train, y_train)
# 2. Результаты подбора для старых параметров
old_best_params = old_grid_search.best_params_
old_best_mse = -old_grid_search.best_score_ # Меняем знак, так как берем отрицательное значение MSE
# 3. Настройка параметров для новых значений
new_param_grid = {
'n_estimators': [200],
'max_depth': [10],
'min_samples_split': [10]
}
# Подбор гиперпараметров с помощью Grid Search для новых параметров
new_grid_search = GridSearchCV(estimator=RandomForestRegressor(),
param_grid=new_param_grid, scoring='neg_mean_squared_error', cv=2)
# Обучение модели на тренировочных данных
new_grid_search.fit(X_train, y_train)
# 4. Результаты подбора для новых параметров
new_best_params = new_grid_search.best_params_
new_best_mse = -new_grid_search.best_score_ # Меняем знак, так как берем отрицательное значение MSE
# 5. Обучение модели с лучшими параметрами для новых значений
model_best = RandomForestRegressor(**new_best_params)
model_best.fit(X_train, y_train)
# Прогнозирование на тестовой выборке
y_pred = model_best.predict(X_test)
# Оценка производительности модели
mse = metrics.mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
# Вывод результатов
print("Старые параметры:", old_best_params)
print("Лучший результат (MSE) на старых параметрах:", old_best_mse)
print("\nНовые параметры:", new_best_params)
print("Лучший результат (MSE) на новых параметрах:", new_best_mse)
print("Среднеквадратическая ошибка (MSE) на тестовых данных:", mse)
print("Корень среднеквадратичной ошибки (RMSE) на тестовых данных:", rmse)
# Визуализация ошибок
plt.figure(figsize=(10, 5))
plt.bar(['Старые параметры', 'Новые параметры'], [old_best_mse, new_best_mse], color=['blue', 'orange'])
plt.xlabel('Подбор параметров')
plt.ylabel('Среднеквадратическая ошибка (MSE)')
plt.title('Сравнение MSE для старых и новых параметров')
plt.show()
Сравнение старых и новых параметров модели показывает, что старые настройки обеспечивают меньшую среднеквадратичную ошибку (MSE), что свидетельствует о более точном прогнозировании по сравнению с новыми параметрами.
Основные факторы, подтверждающие хорошее обучение модели:
Согласованность MSE: Значения MSE на тренировочных (0.159) и тестовых данных (0.1589) очень близки, что указывает на отсутствие переобучения и недообучения. Модель успешно обобщает данные, что является желаемым результатом.
Эффективность старых параметров: Старые параметры демонстрируют наилучшие результаты, подтверждая способность модели достигать высокой точности при оптимальных гиперпараметрах.
Анализ влияния новых параметров: Эксперименты с новыми параметрами позволили оценить реакцию модели на изменения и выявить, что увеличение max_depth и уменьшение min_samples_split улучшают результаты. Этот процесс оптимизации является важной частью улучшения модели.
В целом, модель обучена хорошо, но возможны дальнейшие незначительные улучшения за счет тонкой настройки гиперпараметров.
plt.figure(figsize=(10, 5))
plt.scatter(range(len(y_test)), y_test, label="Актуальные значения", color="black", alpha=0.5)
plt.scatter(range(len(y_test)), y_pred, label="Предсказанные(новые параметры)", color="blue", alpha=0.5)
plt.scatter(range(len(y_test)), y_test_predict, label="Предсказанные(старые параметры)", color="red", alpha=0.5)
plt.xlabel("Выборка")
plt.ylabel("Значения")
plt.legend()
plt.title("Актуальные значения vs Предсказанные значения (Новые and Старые Параметры)")
plt.show()