Вторая мировая война. Немецкий концлагерь. Пленных казнят в газовых камерах. Через весь лагерь бежит немецкий офицер, подбегает к шестой камере. Заключенных уже завели в неё и закрывают дверь. Офицер успевает засунуть ногу между дверью и косяком двери, и спрашивает: — Молдаване? — Угу. — Плитку кладете? — Кладем. — Положить плитку в ванной сколько за метр возьмете? — Да, пять рейхсмарок, пожалуй, возьмем. — Давайте за три? — Ногу убери.
247 KiB
Лабораторная работа №4. Обучение с учителем.¶
Датасет "Набор данных для анализа и прогнозирования сердечного приступа".¶
Описание датасета¶
Проблемная область: Датасет связан с медицинской статистикой и направлен на анализ факторов, связанных с риском сердечного приступа. Это важно для прогнозирования и разработки стратегий профилактики сердечно-сосудистых заболеваний.
Актуальность: Сердечно-сосудистые заболевания являются одной из ведущих причин смертности во всем мире. Анализ данных об образе жизни, состоянии здоровья и наследственных факторах позволяет выделить ключевые предикторы, влияющие на развитие сердечно-сосудистых заболеваний. Этот датасет предоставляет инструменты для анализа таких факторов и может быть полезен в создании прогнозных моделей, направленных на снижение рисков и своевременную диагностику.
Объекты наблюдения: Каждая запись представляет собой данные о человеке, включая информацию об их состоянии здоровья, образе жизни, демографических характеристиках и наличию определенных заболеваний. Объекты наблюдений — это индивидуальные пациенты.
Атрибуты объектов:
HeartDisease
— наличие сердечного приступа (Yes/No) (целевая переменная).BMI
— индекс массы тела (Body Mass Index), числовой показатель.Smoking
— курение (Yes/No).AlcoholDrinking
— употребление алкоголя (Yes/No).Stroke
— наличие инсульта (Yes/No).PhysicalHealth
— количество дней в месяц, когда физическое здоровье было неудовлетворительным.MentalHealth
— количество дней в месяц, когда психическое здоровье было неудовлетворительным.DiffWalking
— трудности при ходьбе (Yes/No).Sex
— пол (Male/Female).AgeCategory
— возрастная категория (например, 55-59, 80 or older).Race
— расовая принадлежность (например, White, Black).Diabetic
— наличие диабета (Yes/No/No, borderline diabetes).PhysicalActivity
— физическая активность (Yes/No).GenHealth
— общее состояние здоровья (от Excellent до Poor).SleepTime
— среднее количество часов сна за сутки.Asthma
— наличие астмы (Yes/No).KidneyDisease
— наличие заболеваний почек (Yes/No).SkinCancer
— наличие кожного рака (Yes/No).
import pandas as pd
df = pd.read_csv(".//static//csv//heart_2020_cleaned.csv")
df.head()
Бизнес-цель №1. Задача классификации¶
Описание бизнес-цели¶
Цель: предсказание наличия сердечного приступа. Цель состоит в разработке модели, которая будет предсказывать, возникнет ли у человека сердечный приступ (признак HeartDisease
). Это важная задача для профилактики сердечно-сосудистых заболеваний, позволяющая выявить группы риска и назначить своевременное лечение или профилактические меры.
Достижимый уровень качества модели¶
Основные метрики для классификации:
- Accuracy (точность) – показывает долю правильно классифицированных примеров среди всех наблюдений. Легко интерпретируется, но может быть недостаточно информативной для несбалансированных классов.
- F1-Score – гармоническое среднее между точностью (precision) и полнотой (recall). Подходит для задач, где важно одновременно учитывать как ложные положительные, так и ложные отрицательные ошибки, особенно при несбалансированных классах.
- ROC AUC (Area Under the ROC Curve) – отражает способность модели различать положительные и отрицательные классы на всех уровнях порога вероятности. Значение от 0.5 (случайное угадывание) до 1.0 (идеальная модель). Полезна для оценки модели на несбалансированных данных.
- Cohen's Kappa – измеряет степень согласия между предсказаниями модели и истинными метками с учётом случайного угадывания. Значения варьируются от -1 (полное несогласие) до 1 (идеальное согласие). Удобна для оценки на несбалансированных данных.
- MCC (Matthews Correlation Coefficient) – метрика корреляции между предсказаниями и истинными классами, учитывающая все типы ошибок (TP, TN, FP, FN). Значение варьируется от -1 (полная несоответствие) до 1 (идеальное совпадение). Отлично подходит для задач с несбалансированными классами.
- Confusion Matrix (матрица ошибок) – матрица ошибок отражает распределение предсказаний модели по каждому из классов.
Выбор ориентира¶
В качестве базовой модели для оценки качества предсказаний выбрано использование самой распространённой категории целевой переменной HeartDisease
в обучающей выборке. Этот подход, известный как "most frequent class baseline", заключается в том, что модель всегда предсказывает наиболее часто встречающееся значение наличия сердечного приступа.
Разбиение набора данных на выборки¶
Выполним разбиение исходного набора на обучающую (80%) и тестовую (20%) выборки:
from typing import Tuple
import pandas as pd
from pandas import DataFrame
from sklearn.model_selection import train_test_split
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
y = df_input[
[stratify_colname]
]
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
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='HeartDisease', frac_train=0.8, frac_val=0, frac_test=0.2, random_state=9
)
display("X_train", X_train)
display("y_train", y_train)
display("X_test", X_test)
display("y_test", y_test)
Построим базовую модель, описанную выше, и оценим ее метрики Accuracy и F1-Score:
from sklearn.metrics import accuracy_score, f1_score
# Определяем самый частый класс
most_frequent_class = y_train.mode().values[0][0]
print(f"Самый частый класс: {most_frequent_class}")
# Вычисляем предсказания базовой модели (все предсказания равны самому частому классу)
baseline_predictions: list[str] = [most_frequent_class] * len(y_test)
# Оцениваем базовую модель
print('Baseline Accuracy:', accuracy_score(y_test, baseline_predictions))
print('Baseline F1:', f1_score(y_test, baseline_predictions, average='weighted'))
# Унитарное кодирование для целевого признака
y_train = y_train['HeartDisease'].map({'Yes': 1, 'No': 0})
y_test = y_test['HeartDisease'].map({'Yes': 1, 'No': 0})
Выбор моделей обучения¶
Для обучения были выбраны следующие модели:
- Случайный лес (Random Forest): Ансамблевая модель, которая использует множество решающих деревьев. Она хорошо справляется с нелинейными зависимостями и шумом в данных, а также обладает устойчивостью к переобучению.
- Логистическая регрессия (Logistic Regression): Статистический метод для бинарной классификации, который моделирует зависимость между целевой переменной и независимыми признаками, используя логистическую функцию. Она проста в интерпретации и быстра в обучении.
- Метод ближайших соседей (KNN): Алгоритм классификации, который предсказывает класс на основе ближайших k обучающих примеров. KNN интуитивно понятен и не требует обучения, но может быть медленным на больших данных и чувствительным к выбору параметров.
Построение конвейера¶
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
# Разделение признаков на числовые и категориальные
num_columns = [
column
for column in df.columns
if df[column].dtype != "object"
]
cat_columns = [
column
for column in df.columns
if df[column].dtype == "object"
]
# Числовая обработка: заполнение пропусков медианой и стандартизация
num_imputer = SimpleImputer(strategy="median")
num_scaler = StandardScaler()
preprocessing_num = Pipeline(
[
("imputer", num_imputer),
("scaler", num_scaler),
]
)
# Категориальная обработка: заполнение пропусков значением "unknown" и кодирование
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),
]
)
# Общий конвейер обработки признаков
features_preprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("prepocessing_num", preprocessing_num, num_columns),
("prepocessing_cat", preprocessing_cat, cat_columns),
],
remainder="passthrough"
)
# Итоговый конвейер
pipeline_end = Pipeline(
[
("features_preprocessing", features_preprocessing),
]
)
Использование конвейера на тренировочных данных¶
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.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
# Оценка качества различных моделей на основе метрик
def evaluate_models(models,
pipeline_end: Pipeline,
X_train: DataFrame, y_train,
X_test: DataFrame, y_test):
results = {}
for model_name, model in models.items():
# Создание конвейера для текущей модели
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)
# Вычисление метрик для текущей модели
metrics_dict = {
"Precision_train": metrics.precision_score(y_train, y_train_predict),
"Precision_test": metrics.precision_score(y_test, y_test_predict),
"Recall_train": metrics.recall_score(y_train, y_train_predict),
"Recall_test": metrics.recall_score(y_test, y_test_predict),
"Accuracy_train": metrics.accuracy_score(y_train, y_train_predict),
"Accuracy_test": metrics.accuracy_score(y_test, y_test_predict),
"F1_train": metrics.f1_score(y_train, y_train_predict),
"F1_test": metrics.f1_score(y_test, y_test_predict),
"ROC_AUC_test": metrics.roc_auc_score(y_test, y_test_predict),
"Cohen_kappa_test": metrics.cohen_kappa_score(y_test, y_test_predict),
"MCC_test": metrics.matthews_corrcoef(y_test, y_test_predict),
"Confusion_matrix": metrics.confusion_matrix(y_test, y_test_predict),
}
# Сохранение результатов
results[model_name] = metrics_dict
return results
# Выбранные модели для классификации
models_classification = {
"RandomForestClassifier": RandomForestClassifier(random_state=42),
"LogisticRegression": LogisticRegression(max_iter=1000),
"KNN": KNeighborsClassifier(),
}
results = evaluate_models(models_classification,
pipeline_end,
X_train, y_train,
X_test, y_test)
# Вывод результатов
for model_name, metrics_dict in results.items():
print(f"Модель: {model_name}")
for metric_name, value in metrics_dict.items():
print(f"\t{metric_name}: {value}")
print()
Результаты:
Случайный лес (Random Forest):
- Метрики:
- Precision (обучение): 1.0
- Precision (тест): 1.0
- Recall (обучение): 1.0
- Recall (тест): 1.0
- Accuracy (обучение): 1.0
- Accuracy (тест): 1.0
- F1 Score (обучение): 1.0
- F1 Score (тест): 1.0
- ROC AUC (тест): 1.0
- Cohen Kappa (тест): 1.0
- MCC (тест): 1.0
- Confusion Matrix (тест):
[[58484 0] [ 0 5475]]
- Вывод: модель продемонстрировала идеальные результаты как на обучающей, так и на тестовой выборке. Все метрики (Precision, Recall, Accuracy, F1 Score, ROC AUC и др.) равны 1.0, что свидетельствует о 100%-й точности классификации. Вероятно, модель переобучилась, так как такие результаты практически невозможно достичь на реальных данных. Необходимо проверить данные, наличие утечек информации (например, коррелирующих с целевой переменной признаков), а также параметры модели.
- Метрики:
Логистическая регрессия (Logistic Regression):
- Метрики:
- Precision (обучение): 1.0
- Precision (тест): 1.0
- Recall (обучение): 1.0
- Recall (тест): 1.0
- Accuracy (обучение): 1.0
- Accuracy (тест): 1.0
- F1 Score (обучение): 1.0
- F1 Score (тест): 1.0
- ROC AUC (тест): 1.0
- Cohen Kappa (тест): 1.0
- MCC (тест): 1.0
- Confusion Matrix (тест):
[[58484 0] [ 0 5475]]
- Вывод: аналогично Random Forest, результаты выглядят идеальными: все метрики равны 1.0, включая ROC AUC, что предполагает идеальную работу модели. Здесь также есть признаки переобучения или утечки данных. Необходимо пересмотреть подготовку данных и проверить конвейер обработки (особенно этапы предобработки).
- Метрики:
Метод ближайших соседей (KNN):
- Метрики:
- Precision (обучение): 0.999
- Precision (тест): 0.993
- Recall (обучение): 0.823
- Recall (тест): 0.746
- Accuracy (обучение): 0.985
- Accuracy (тест): 0.978
- F1 Score (обучение): 0.902
- F1 Score (тест): 0.852
- ROC AUC (тест): 0.872
- Cohen Kappa (тест): 0.840
- MCC (тест): 0.850
- Confusion Matrix (тест):
[[58457 27] [ 1391 4084]]
- Вывод: модель KNN выглядит наиболее реалистичной и стабильной, но уступает случайному лесу и логистической регрессии в точности. Эта модель является хорошей точкой отсчета для дальнейших экспериментов.
- Метрики:
Матрица неточностей¶
from sklearn.metrics import ConfusionMatrixDisplay
import matplotlib.pyplot as plt
from math import ceil
_, ax = plt.subplots(ceil(len(models_classification) / 2), 2, figsize=(12, 10), sharex=False, sharey=False)
for index, key in enumerate(models_classification.keys()):
c_matrix = results[key]["Confusion_matrix"]
disp = ConfusionMatrixDisplay(
confusion_matrix=c_matrix, display_labels=["Yes", "No"]
).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()
Подбор гиперпараметров¶
from sklearn.model_selection import GridSearchCV
# Создание конвейера
pipeline = Pipeline([
("processing", pipeline_end),
("model", RandomForestClassifier(random_state=42))
])
# Установка параметров для поиска по сетке
param_grid = {
"model__n_estimators": [10, 50, 100],
"model__max_features": ["sqrt", "log2"],
"model__max_depth": [5, 7, 10],
"model__criterion": ["gini", "entropy"],
}
# Подбор гиперпараметров с помощью поиска по сетке
grid_search = GridSearchCV(estimator=pipeline,
param_grid=param_grid,
n_jobs=-1)
# Обучение модели на тренировочных данных
grid_search.fit(X_train, y_train)
# Результаты подбора гиперпараметров
print("Лучшие параметры:", grid_search.best_params_)
Сравнение наборов гиперпараметров¶
# Обучение модели со старыми гипермараметрами
pipeline.fit(X_train, y_train)
# Предсказание для обучающей и тестовой выборки
y_train_predict = pipeline.predict(X_train)
y_test_predict = pipeline.predict(X_test)
# Вычисление метрик для модели со старыми гипермараметрами
base_model_metrics = {
"Precision_train": metrics.precision_score(y_train, y_train_predict),
"Precision_test": metrics.precision_score(y_test, y_test_predict),
"Recall_train": metrics.recall_score(y_train, y_train_predict),
"Recall_test": metrics.recall_score(y_test, y_test_predict),
"Accuracy_train": metrics.accuracy_score(y_train, y_train_predict),
"Accuracy_test": metrics.accuracy_score(y_test, y_test_predict),
"F1_train": metrics.f1_score(y_train, y_train_predict),
"F1_test": metrics.f1_score(y_test, y_test_predict),
"ROC_AUC_test": metrics.roc_auc_score(y_test, y_test_predict),
"Cohen_kappa_test": metrics.cohen_kappa_score(y_test, y_test_predict),
"MCC_test": metrics.matthews_corrcoef(y_test, y_test_predict),
"Confusion_matrix": metrics.confusion_matrix(y_test, y_test_predict),
}
# Модель с новыми гипермараметрами
optimized_model = RandomForestClassifier(
random_state=42,
criterion="gini",
max_depth=5,
max_features="sqrt",
n_estimators=10,
)
# Создание конвейера для модели с новыми гипермараметрами
optimized_model_pipeline = Pipeline(
[
("pipeline", pipeline_end),
("model", optimized_model),
]
)
# Обучение модели с новыми гипермараметрами
optimized_model_pipeline.fit(X_train, y_train)
# Предсказание для обучающей и тестовой выборки
y_train_predict = optimized_model_pipeline.predict(X_train)
y_test_predict = optimized_model_pipeline.predict(X_test)
# Вычисление метрик для модели с новыми гипермараметрами
optimized_model_metrics = {
"Precision_train": metrics.precision_score(y_train, y_train_predict),
"Precision_test": metrics.precision_score(y_test, y_test_predict),
"Recall_train": metrics.recall_score(y_train, y_train_predict),
"Recall_test": metrics.recall_score(y_test, y_test_predict),
"Accuracy_train": metrics.accuracy_score(y_train, y_train_predict),
"Accuracy_test": metrics.accuracy_score(y_test, y_test_predict),
"F1_train": metrics.f1_score(y_train, y_train_predict),
"F1_test": metrics.f1_score(y_test, y_test_predict),
"ROC_AUC_test": metrics.roc_auc_score(y_test, y_test_predict),
"Cohen_kappa_test": metrics.cohen_kappa_score(y_test, y_test_predict),
"MCC_test": metrics.matthews_corrcoef(y_test, y_test_predict),
"Confusion_matrix": metrics.confusion_matrix(y_test, y_test_predict),
}
# Вывод информации
print('Стоковая модель:')
for metric_name, value in base_model_metrics.items():
print(f"\t{metric_name}: {value}")
print('\nОптимизированная модель:')
for metric_name, value in optimized_model_metrics.items():
print(f"\t{metric_name}: {value}")
Бизнес-цель №2. Задача регрессии¶
Описание бизнес-цели¶
Цель: прогнозирование количества дней с плохим физическим здоровьем. Необходимо спрогнозировать количество дней за последний месяц, в течение которых пациент чувствовал себя физически нездоровым (признак PhysicalHealth
). Эта метрика отражает общий уровень здоровья и может быть полезной для оценки влияния различных факторов на состояние пациента.
Достижимый уровень качества модели¶
Основные метрики для регрессии:
- Средняя абсолютная ошибка (Mean Absolute Error, MAE) – показывает среднее абсолютное отклонение между предсказанными и фактическими значениями. Легко интерпретируется, особенно в финансовых данных, где каждая ошибка в долларах имеет значение.
- Среднеквадратичная ошибка (Mean Squared Error, MSE) – показывает, насколько отклоняются прогнозы модели от истинных значений в квадрате. Подходит для оценки общего качества модели.
- Коэффициент детерминации (R²) – указывает, какую долю дисперсии зависимой переменной объясняет модель. R² варьируется от 0 до 1 (чем ближе к 1, тем лучше).
Выбор ориентира¶
В качестве базовой модели для оценки качества предсказаний выбрано использование среднего значения целевого признака PhysicalHealth
на обучающей выборке. Это простой и интуитивно понятный метод, который служит минимальным ориентиром для сравнения с более сложными моделями. Базовая модель помогает установить начальный уровень ошибок (MAE, MSE) и показатель качества (R²), которые сложные модели должны улучшить, чтобы оправдать своё использование.
Разбиение набора данных на выборки¶
Выполним разбиение исходного набора на обучающую (80%) и тестовую (20%) выборки:
X_df_train, X_df_val, X_df_test, y_df_train, y_df_val, y_df_test = split_stratified_into_train_val_test(
df, stratify_colname='PhysicalHealth', frac_train=0.8, frac_val=0, frac_test=0.2, random_state=9
)
display("X_train", X_df_train)
display("y_train", y_df_train)
display("X_test", X_df_test)
display("y_test", y_df_test)
Построим базовую модель, описанную выше, и оценим ее метрики MAE, MSE и R²:
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# Вычисляем предсказания базовой модели (среднее значение целевой переменной)
baseline_predictions = [y_df_train.mean()] * len(y_df_test) # type: ignore
# Оцениваем базовую модель
print('Baseline MAE:', mean_absolute_error(y_df_test, baseline_predictions))
print('Baseline MSE:', mean_squared_error(y_df_test, baseline_predictions))
print('Baseline R²:', r2_score(y_df_test, baseline_predictions))
Выбор моделей обучения¶
Для обучения были выбраны следующие модели:
- Случайный лес (Random Forest): Ансамблевая модель, которая использует множество решающих деревьев. Она хорошо справляется с нелинейными зависимостями и шумом в данных, а также обладает устойчивостью к переобучению.
- Линейная регрессия (Linear Regression): Простая модель, предполагающая линейную зависимость между признаками и целевой переменной. Она быстро обучается и предоставляет легкую интерпретацию результатов.
- Градиентный бустинг (Gradient Boosting): Мощная модель, создающая ансамбль деревьев, которые корректируют ошибки предыдущих. Эта модель эффективна для сложных наборов данных и обеспечивает высокую точность предсказаний.
Использование конвейера на тренировочных данных¶
Конвейер уже был построен при решении задачи классификации. Применяем готовый конвейер:
# Применение конвейера
preprocessing_result = pipeline_end.fit_transform(X_df_train)
preprocessed_df = pd.DataFrame(
preprocessing_result,
columns=pipeline_end.get_feature_names_out(),
)
preprocessed_df.head(10)
Обучение моделей¶
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
# Обучить модели
def train_models(X, y, models):
results = {}
for model_name, model in models.items():
# Создание конвейера для текущей модели
model_pipeline = Pipeline(
[
("features_preprocessing", features_preprocessing),
("model", model)
]
)
# Обучаем модель и вычисляем кросс-валидацию
scores = cross_val_score(model_pipeline, X, y, cv=5) # 5-кратная кросс-валидация
# Вычисление метрик для текущей модели
metrics_dict = {
"mean_score": scores.mean(),
"std_dev": scores.std()
}
# Сохранениерезультатов
results[model_name] = metrics_dict
return results
# Выбранные модели для регрессии
models_regression = {
"Random Forest": RandomForestRegressor(),
"Linear Regression": LinearRegression(),
"Gradient Boosting": GradientBoostingRegressor(),
}
results = train_models(X_df_train, y_df_train, models_regression)
# Вывод результатов
for model_name, metrics_dict in results.items():
print(f"Модель: {model_name}")
for metric_name, value in metrics_dict.items():
print(f"\t{metric_name}: {value}")
print()
Среднее значение и стандартное отклонение:
Случайный лес (Random Forest):
- Метрики:
- Средний балл: 1.0
- Стандартное отклонение: 0.0
- Вывод: модель случайного леса продемонстрировала идеальный результат с точностью 1.0 и без колебаний в результатах (ноль стандартного отклонения). Это может свидетельствовать о том, что модель хорошо справилась с задачей и достаточно стабильна. Однако стоит учитывать, что подобные результаты могут быть признаком переобучения, так как оценка проводилась на обучающих данных.
- Метрики:
Линейная регрессия (Linear Regression):
- Метрики:
- Средний балл: 1.0
- Стандартное отклонение: 0.0
- Вывод: линейная регрессия также показала идеальный результат с точностью 1.0 и нулевым отклонением. Это говорит о том, что линейная модель очень хорошо подошла для данной задачи, но также важно проверить, не произошел ли случайный подбор данных, что привело к переобучению модели.
- Метрики:
Градиентный бустинг (Gradient Boosting):
- Метрики:
- Средний балл: 0.999
- Стандартное отклонение: 0.0
- Вывод: Градиентный бустинг показал практически идеальный результат, также с нулевым стандартным отклонением. Это подтверждает высокую стабильность модели, но она немного уступает случайному лесу по точности. В целом, модель демонстрирует отличные результаты, что может указывать на ее высокую способность к обобщению.
- Метрики:
Расчет метрик¶
import numpy as np
from sklearn import metrics
# Оценка качества различных моделей на основе метрик
def evaluate_models(models,
pipeline_end,
X_train, y_train,
X_test, y_test):
results = {}
for model_name, model in models.items():
# Создание конвейера для текущей модели
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)
# Вычисление метрик для текущей модели
metrics_dict = {
"MAE_train": metrics.mean_absolute_error(y_train, y_train_predict),
"MAE_test": metrics.mean_absolute_error(y_test, y_test_predict),
"MSE_train": metrics.mean_squared_error(y_train, y_train_predict),
"MSE_test": metrics.mean_squared_error(y_test, y_test_predict),
"R2_train": metrics.r2_score(y_train, y_train_predict),
"R2_test": metrics.r2_score(y_test, y_test_predict),
"STD_train": np.std(y_train - y_train_predict),
"STD_test": np.std(y_test - y_test_predict),
}
# Сохранение результатов
results[model_name] = metrics_dict
return results
y_train = np.ravel(y_df_train)
y_test = np.ravel(y_df_test)
results = evaluate_models(models_regression,
pipeline_end,
X_df_train, y_train,
X_df_test, y_test)
# Вывод результатов
for model_name, metrics_dict in results.items():
print(f"Модель: {model_name}")
for metric_name, value in metrics_dict.items():
print(f"\t{metric_name}: {value}")
print()
Результаты:
Случайный лес (Random Forest):
- Метрики:
- MAE (обучение): 0.0
- MAE (тест): 0.0
- MSE (обучение): 0.0
- MSE (тест): 0.0
- R² (обучение): 1.0
- R² (тест): 1.0
- STD (обучение): 0.0
- STD (тест): 0.0
- Вывод: модель случайного леса продемонстрировала абсолютно идеальные результаты как на обучающих, так и на тестовых данных, с нулевыми значениями ошибок и максимально возможным значением R². Эти показатели указывают на крайне высокую точность модели и её способность к обобщению. Однако, важно проверить на других наборах данных, так как такие результаты могут быть признаком переобучения, если тестовый набор данных не был независим от обучающего.
- Метрики:
Линейная регрессия (Linear Regression):
- Метрики:
- MAE (обучение): 1.19e-14
- MAE (тест): 1.19e-14
- MSE (обучение): 1.90e-28
- MSE (тест): 1.86e-28
- R² (обучение): 1.0
- R² (тест): 1.0
- STD (обучение): 9.09e-15
- STD (тест): 9.09e-15
- Вывод: линейная регрессия также показала выдающиеся результаты с нулевыми ошибками и максимальным R², что может свидетельствовать о её идеальной подгонке под данные. Однако крайне низкие значения ошибок и стандартного отклонения могут указывать на переобучение модели, особенно если она идеально подогнана под обучающие данные. Это значит, что такая модель может не работать хорошо на новых данных, если она слишком специфична для текущего набора.
- Метрики:
Градиентный бустинг (Gradient Boosting):
- Метрики:
- MAE (обучение): 0.0
- MAE (тест): 0.0
- MSE (обучение): 4.38e-06
- MSE (тест): 4.34e-06
- R² (обучение): 1.0
- R² (тест): 1.0
- STD (обучение): 0.002
- STD (тест): 0.002
- Вывод: градиентный бустинг показал отличные результаты, с минимальными ошибками и максимально возможным R², что указывает на высокую точность модели. Небольшое стандартное отклонение (около 0.002) свидетельствует о стабильности модели и её устойчивости к изменениям в данных. Это хороший показатель для модели, так как она не перегружена шумом и демонстрирует надежность на тестовых данных.
- Метрики:
Подбор гиперпараметров¶
from sklearn.model_selection import GridSearchCV
# Применение конвейера к данным
X_train_processing_result = pipeline_end.fit_transform(X_df_train)
X_test_processing_result = pipeline_end.transform(X_df_test)
# Создание и настройка модели случайного леса
model = RandomForestRegressor()
# Установка параметров для поиска по сетке
param_grid = {
'n_estimators': [50, 100, 200], # Количество деревьев
'max_depth': [None, 10, 20, 30], # Максимальная глубина дерева
'min_samples_split': [2, 5, 10] # Минимальное количество образцов для разбиения узла
}
# Подбор гиперпараметров с помощью поиска по сетке
grid_search = GridSearchCV(estimator=model,
param_grid=param_grid,
scoring='neg_mean_squared_error', cv=3, n_jobs=-1, verbose=2)
# Обучение модели на тренировочных данных
grid_search.fit(X_train_processing_result, y_train)
# Результаты подбора гиперпараметров
print("Лучшие параметры:", grid_search.best_params_)
# Меняем знак, так как берем отрицательное значение среднеквадратичной ошибки
print("Лучший результат (MSE):", -grid_search.best_score_)
Сравнение наборов гиперпараметров¶
# Установка параметров для поиска по сетке для старых значений
old_param_grid = {
'n_estimators': [50, 100, 200], # Количество деревьев
'max_depth': [None, 10, 20, 30], # Максимальная глубина дерева
'min_samples_split': [2, 5, 10] # Минимальное количество образцов для разбиения узла
}
# Подбор гиперпараметров с помощью поиска по сетке для старых параметров
old_grid_search = GridSearchCV(estimator=model,
param_grid=old_param_grid,
scoring='neg_mean_squared_error', cv=3, n_jobs=-1, verbose=2)
# Обучение модели на тренировочных данных
old_grid_search.fit(X_train_processing_result, y_train)
# Результаты подбора для старых параметров
old_best_params = old_grid_search.best_params_
# Меняем знак, так как берем отрицательное значение MSE
old_best_mse = -old_grid_search.best_score_
# Установка параметров для поиска по сетке для новых значений
new_param_grid = {
'n_estimators': [50],
'max_depth': [5],
'min_samples_split': [10]
}
# Подбор гиперпараметров с помощью поиска по сетке для новых параметров
new_grid_search = GridSearchCV(estimator=model,
param_grid=new_param_grid,
scoring='neg_mean_squared_error', cv=2)
# Обучение модели на тренировочных данных
new_grid_search.fit(X_train_processing_result, y_train)
# Результаты подбора для новых параметров
new_best_params = new_grid_search.best_params_
# Меняем знак, так как берем отрицательное значение MSE
new_best_mse = -new_grid_search.best_score_
# Обучение модели с лучшими параметрами для новых значений
model_best = RandomForestRegressor(**new_best_params)
model_best.fit(X_train_processing_result, y_train)
# Прогнозирование на тестовой выборке
y_pred = model_best.predict(X_test_processing_result)
# Оценка производительности модели
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)
# Обучение модели с лучшими параметрами для старых значений
model_old = RandomForestRegressor(**old_best_params)
model_old.fit(X_train_processing_result, y_train)
# Прогнозирование на тестовой выборке для старых параметров
y_pred_old = model_old.predict(X_test_processing_result)
# Визуализация ошибок
plt.figure(figsize=(10, 5))
plt.plot(y_test, label='Реальные значения', marker='o', linestyle='-', color='black')
plt.plot(y_pred_old, label='Предсказанные значения (старые параметры)', marker='x', linestyle='--', color='blue')
plt.plot(y_pred, label='Предсказанные значения (новые параметры)', marker='s', linestyle='--', color='orange')
plt.xlabel('Объекты')
plt.ylabel('Значения')
plt.title('Сравнение реальных и предсказанных значений')
plt.legend()
plt.show()