534 KiB
Начало лабораторной¶
Цены на кофе - https://www.kaggle.com/datasets/mayankanand2701/starbucks-stock-price-dataset
Атрибуты¶
Date — Дата
Open — Открытие
High — Макс. цена
Low — Мин. цена
Close — Закрытие
Adj Close — Скорректированная цена закрытия
Volume — Объем торгов
Бизнес-цели¶
1. Оценка волатильности акций:
Описание: Прогнозировать волатильность акций на основе изменений в ценах открытий, максимума, минимума и объема торгов. Целевая переменная: Разница между высокой и низкой ценой (High - Low). (среднее значение)
2. Прогнозирование цены закрытия акций:
Описание: Оценить, какая будет цена закрытия акций Starbucks на следующий день или через несколько дней на основе исторических данных. Целевая переменная: Цена закрытия (Close). (среднее значение)
Определение достижимого уровня качества модели для первой задачи¶
Подготовка данных
Загрузка данных и создание целевой переменной
import pandas as pd
from sklearn import set_config
# Установим параметры для вывода
set_config(transform_output="pandas")
# Загружаем набор данных
df = pd.read_csv(".//static//csv//Starbucks Dataset.csv")
# Устанавливаем случайное состояние
random_state = 42
# Рассчитываем среднее значение объема
average_volume = df['Volume'].mean()
print(f"Среднее значение поля 'Volume': {average_volume}")
# Создаем новую переменную, указывающую, превышает ли объем средний
df['above_average_volume'] = (df['Volume'] > average_volume).astype(int)
# Рассчитываем волатильность (разницу между высокими и низкими значениями)
df['volatility'] = df['High'] - df['Low']
# Выводим первые строки измененной таблицы для проверки
print(df.head())
Разделение набора данных на обучающую и тестовые выборки (80/20) для задачи классификации¶
Целевой признак -- above_average_close
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 # 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_average_volume", frac_train=0.80, frac_val=0, frac_test=0.20, random_state=random_state
)
display("X_train", X_train)
display("y_train", y_train)
display("X_test", X_test)
display("y_test", y_test)
Формирование конвейера для классификации данных¶
preprocessing_num -- конвейер для обработки числовых данных: заполнение пропущенных значений и стандартизация
preprocessing_cat -- конвейер для обработки категориальных данных: заполнение пропущенных данных и унитарное кодирование
features_preprocessing -- трансформер для предобработки признаков
features_engineering -- трансформер для конструирования признаков
drop_columns -- трансформер для удаления колонок
pipeline_end -- основной конвейер предобработки данных и конструирования признаков
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.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
class StarbucksFeatures(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X["Length_to_Width_Ratio"] = X["x"] / X["y"]
return X
def get_feature_names_out(self, features_in):
return np.append(features_in, ["Length_to_Width_Ratio"], axis=0)
columns_to_drop = ["Date"]
num_columns = ["Close", "Open", "Adj Close", "High", "Low", "Volume", "above_average_volume"]
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),
]
)
features_preprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("prepocessing_num", preprocessing_num, num_columns),
("prepocessing_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=[
("prepocessing_cat", preprocessing_cat, ["Cabin_type"]),
],
remainder="passthrough",
)
pipeline_end = Pipeline(
[
("features_preprocessing", features_preprocessing),
("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
Формирование набора моделей для классификации¶
logistic -- логистическая регрессия
ridge -- гребневая регрессия
decision_tree -- дерево решений
knn -- k-ближайших соседей
naive_bayes -- наивный Байесовский классификатор
gradient_boosting -- метод градиентного бустинга (набор деревьев решений)
random_forest -- метод случайного леса (набор деревьев решений)
mlp -- многослойный персептрон (нейронная сеть)
from sklearn import ensemble, linear_model, naive_bayes, neighbors, neural_network, tree
class_models = {
"logistic": {"model": linear_model.LogisticRegression()},
# "ridge": {"model": linear_model.RidgeClassifierCV(cv=5, class_weight="balanced")},
"ridge": {"model": linear_model.LogisticRegression(penalty="l2", class_weight="balanced")},
"decision_tree": {
"model": tree.DecisionTreeClassifier(max_depth=7, 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=11, class_weight="balanced", random_state=random_state
)
},
"mlp": {
"model": neural_network.MLPClassifier(
hidden_layer_sizes=(7,),
max_iter=500,
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
)
class_models[model_name]["Precision_test"] = metrics.precision_score(
y_test, y_test_predict
)
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()
1045: Это количество истинных положительных диагнозов (True Positives), где модель правильно определила объекты как "More".
563: Это количество ложных отрицательных диагнозов (False Negatives), где модель неправильно определила объекты, которые на самом деле принадлежат к классу "More", отнесёнными к классу "Less".
Исходя из значений True Positives и False Negatives, можно сказать, что модель имеет высокую точность при предсказании класса "More". Однако, высокий уровень ложных отрицательных результатов (563) указывает на то, что существует значительное количество примеров, которые модель пропускает. Это может означать, что в некоторых случаях она не распознаёт объекты, которые должны быть классифицированы как "More".
Точность, полнота, верность (аккуратность), F-мера
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",
],
)
Все модели в данной выборке — логистическая регрессия, ридж-регрессия, дерево решений, KNN, наивный байесовский классификатор, градиентный бустинг, случайный лес и многослойный перцептрон (MLP) — демонстрируют идеальные значения по всем метрикам на обучающих и тестовых наборах данных. Это достигается, поскольку все модели показали значения, равные 1.0 для Precision, Recall, Accuracy и F1-меры, что указывает на то, что модель безошибочно классифицирует все примеры.
Модель MLP, хотя и имеет немного более низкие значения Recall (0.994) и F1-на тестовом наборе (0.997) по сравнению с другими, по-прежнему остается высокоэффективной. Тем не менее, она не снижает показатели классификации до такого уровня, что может вызвать обеспокоенность, и остается на уровне, близком к идеальному.
ROC-кривая, каппа Коэна, коэффициент корреляции Мэтьюса
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",
],
)
Все модели, включая логистическую регрессию, ридж-регрессию, дерево решений, KNN, наивный байесовский классификатор, градиентный бустинг и случайный лес, продемонстрировали идеальные значения по всем метрикам: Accuracy, F1, ROC AUC, Cohen's Kappa и MCC, достигнув максимальных значений, равных 1. Это подчеркивает их эффективность в контексте анализа и классификации данных.
Модель MLP, хотя и показала очень высокие результаты, несколько уступает конкурентам по показателям Accuracy (0.998) и F1 (0.997). Несмотря на это, она достигает оптимального значения ROC AUC (1.000), что указывает на ее способность к выделению классов. Показатели Cohen's Kappa (0.996) и MCC (0.996) также находятся на высоком уровне, что говорит о хорошей согласованности и строгости классификации.
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(),
)
y_pred = class_models[best_model]["preds"]
error_index = y_test[y_test["above_average_volume"] != y_pred].index.tolist()
display(f"Error items count: {len(error_index)}")
error_predicted = pd.Series(y_pred, index=y_test.index).loc[error_index]
error_df = X_test.loc[error_index].copy()
error_df.insert(loc=1, column="Predicted", value=error_predicted)
error_df.sort_index()
Пример использования обученной модели (конвейера) для предсказания¶
model = class_models[best_model]["pipeline"]
example_id = 6621
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_
Обучение модели с новыми гиперпараметрами
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
import numpy as np
from sklearn import metrics
import pandas as pd
# Определяем числовые признаки
numeric_features = X_train.select_dtypes(include=['float64', 'int64']).columns.tolist()
# Установка random_state
random_state = 42
# Определение трансформера
pipeline_end = ColumnTransformer([
('numeric', StandardScaler(), numeric_features),
# Добавьте другие трансформеры, если требуется
])
# Объявление модели
optimized_model = RandomForestClassifier(
random_state=random_state,
criterion="gini",
max_depth=5,
max_features="sqrt",
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[
[
"Precision_train",
"Precision_test",
"Recall_train",
"Recall_test",
"Accuracy_train",
"Accuracy_test",
"F1_train",
"F1_test",
]
].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",
],
)
Обе модели, как "Old", так и "New", демонстрируют идеальную производительность по всем ключевым метрикам: Precision, Recall, Accuracy и F1 как на обучающей (train), так и на тестовой (test) выборках. Все значения равны 1.000000, что указывает на отсутствие ошибок в классификации и максимальную точность.
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",
],
)
Обе модели, как "Old", так и "New", показали идеальные результаты по всем выбранным метрикам: Accuracy, F1, ROC AUC, Cohen's kappa и MCC. Все метрики имеют значение 1.000000 как на тестовой выборке, что указывает на безошибочную классификацию и максимальную эффективность обеих моделей.
_, ax = plt.subplots(1, 2, figsize=(10, 4), sharex=False, sharey=False
)
for index in range(0, len(optimized_metrics)):
c_matrix = optimized_metrics.iloc[index]["Confusion_matrix"]
disp = ConfusionMatrixDisplay(
confusion_matrix=c_matrix, display_labels=["Less", "More"]
).plot(ax=ax.flat[index])
plt.subplots_adjust(top=1, bottom=0, hspace=0.4, wspace=0.3)
plt.show()
В желтом квадрате мы видим значение 1049, что обозначает количество правильно классифицированных объектов, отнесенных к классу "Less". Это свидетельствует о том, что модель успешно идентифицирует объекты этого класса, минимизируя количество ложных положительных срабатываний.
В зеленом квадрате значение 558 указывает на количество правильно классифицированных объектов, отнесенных к классу "More". Это также является показателем высокой точности модели в определении объектов данного класса.
Определение достижимого уровня качества модели для второй задачи (добавляю конвейер для решения задачи регрессии)¶
Подготовка данных
Загрузка данных и создание целевой переменной
import pandas as pd
from sklearn import set_config
set_config(transform_output="pandas")
# Загрузка данных о ценах акций Starbucks из CSV файла
df = pd.read_csv(".//static//csv//Starbucks Dataset.csv")
# Опция для настройки генерации случайных чисел (если это нужно для других частей кода)
random_state = 42
# Вычисление среднего значения поля "Close"
average_close = df['Close'].mean()
print(f"Среднее значение поля 'Close': {average_close}")
# Создание новой колонки, указывающей, выше или ниже среднего значение цена закрытия
df['above_average_close'] = (df['Close'] > average_close).astype(int)
# Создание целевой переменной для прогнозирования (цена закрытия на следующий день)
df['Close_Next_Day'] = df['Close'].shift(-1)
# Удаление последней строки, где нет значения для следующего дня
df.dropna(inplace=True)
# Вывод DataFrame с новой колонкой
print(df.head())
# Примерный анализ данных
print("Статистическое описание DataFrame:")
print(df.describe())
Разделение набора данных на обучающую и тестовые выборки (80/20) для задачи классификации¶
Целевой признак -- above_average_close
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: DataFrame,
stratify_colname: str = "y",
frac_train: float = 0.6,
frac_val: float = 0.15,
frac_test: float = 0.25,
random_state: int = None,
) -> Tuple[DataFrame, DataFrame, DataFrame, DataFrame, DataFrame, DataFrame]:
if not (0 < frac_train < 1) or not (0 <= frac_val <= 1) or not (0 <= frac_test <= 1):
raise ValueError("Fractions must be between 0 and 1 and the sum must equal 1.")
if not (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(f"{stratify_colname} is not a column in the DataFrame.")
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:
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="above_average_close", frac_train=0.80, frac_val=0.0, frac_test=0.20, random_state=random_state
)
display("X_train", X_train)
display("y_train", y_train)
display("X_test", X_test)
display("y_test", y_test)
Формирование конвейера для классификации данных¶
preprocessing_num -- конвейер для обработки числовых данных: заполнение пропущенных значений и стандартизация
preprocessing_cat -- конвейер для обработки категориальных данных: заполнение пропущенных данных и унитарное кодирование
features_preprocessing -- трансформер для предобработки признаков
features_engineering -- трансформер для конструирования признаков
drop_columns -- трансформер для удаления колонок
pipeline_end -- основной конвейер предобработки данных и конструирования признаков
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.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
class StarbucksFeatures(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X["Length_to_Width_Ratio"] = X["x"] / X["y"]
return X
def get_feature_names_out(self, features_in):
return np.append(features_in, ["Length_to_Width_Ratio"], axis=0)
columns_to_drop = ["Date"]
num_columns = ["Close", "Open", "Adj Close", "High", "Low", "Volume", "above_average_close"]
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),
]
)
features_preprocessing = ColumnTransformer(
verbose_feature_names_out=False,
transformers=[
("prepocessing_num", preprocessing_num, num_columns),
("prepocessing_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=[
("prepocessing_cat", preprocessing_cat, ["Cabin_type"]),
],
remainder="passthrough",
)
pipeline_end = Pipeline(
[
("features_preprocessing", features_preprocessing),
("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
Формирование набора моделей для классификации¶
logistic -- логистическая регрессия
ridge -- гребневая регрессия
decision_tree -- дерево решений
knn -- k-ближайших соседей
naive_bayes -- наивный Байесовский классификатор
gradient_boosting -- метод градиентного бустинга (набор деревьев решений)
random_forest -- метод случайного леса (набор деревьев решений)
mlp -- многослойный персептрон (нейронная сеть)
from sklearn import ensemble, linear_model, naive_bayes, neighbors, neural_network, tree
class_models = {
"logistic": {"model": linear_model.LogisticRegression()},
"ridge": {"model": linear_model.RidgeClassifierCV(cv=5, class_weight="balanced")},
"ridge": {"model": linear_model.LogisticRegression(penalty="l2", class_weight="balanced")},
"decision_tree": {
"model": tree.DecisionTreeClassifier(max_depth=7, 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=11, class_weight="balanced", random_state=random_state
)
},
"mlp": {
"model": neural_network.MLPClassifier(
hidden_layer_sizes=(7,),
max_iter=500,
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
)
class_models[model_name]["Precision_test"] = metrics.precision_score(
y_test, y_test_predict
)
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()
Значение 1049 в желтом квадрате представляет собой количество объектов, относимых к классу "Less", которые модель правильно классифицировала. Это свидетельствует о высоком уровне точности в идентификации этого класса. Значение 558 в зеленом квадрате указывает на количество правильно классифицированных объектов класса "More". Хотя это также является положительным результатом, мы можем заметить, что он ниже, чем для класса "Less".
Точность, полнота, верность (аккуратность), F-мера
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",
],
)
Все модели, включая логистическую регрессию, ридж-регрессию, KNN, наивный байесовский классификатор, многослойную перцептронную сеть, случайный лес, дерево решений и градиентный бустинг, демонстрируют 100% точность (1.000000) на обучающей выборке. Это указывает на то, что модели смогли полностью подстроиться под обучающие данные, что может стремительно указывать на возможное переобучение.
ROC-кривая, каппа Коэна, коэффициент корреляции Мэтьюса
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",
],
)
Почти все модели, включая логистическую регрессию, ридж-регрессию, KNN, наивный байесовский классификатор, случайный лес и многослойную перцептронную сеть, достигли показателя ROC AUC равного 1.000000. Это говорит о том, что они идеально разделяют классы. Градиентный бустинг и дерево решений немного уступили в значениях ROC AUC, составив 0.999378, что говорит о высокой, но не идеальной способности к классификации.
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(),
)
y_pred = class_models[best_model]["preds"]
error_index = y_test[y_test["above_average_close"] != y_pred].index.tolist()
display(f"Error items count: {len(error_index)}")
error_predicted = pd.Series(y_pred, index=y_test.index).loc[error_index]
error_df = X_test.loc[error_index].copy()
error_df.insert(loc=1, column="Predicted", value=error_predicted)
error_df.sort_index()
Пример использования обученной модели (конвейера) для предсказания¶
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[
[
"Precision_train",
"Precision_test",
"Recall_train",
"Recall_test",
"Accuracy_train",
"Accuracy_test",
"F1_train",
"F1_test",
]
].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",
],
)
Как для обучающей (Precision_train), так и для тестовой (Precision_test) выборки обе модели достигли идеальных значений 1.000000. Это указывает на то, что модели очень точно классифицируют положительные образцы, не пропуская их.
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",
],
)
Оба варианта модели продемонстрировали безупречную точность классификации, достигнув значения 1.000000. Это свидетельствует о том, что модели точно классифицировали все тестовые примеры, не допустив никаких ошибок в предсказаниях.
_, ax = plt.subplots(1, 2, figsize=(10, 4), sharex=False, sharey=False
)
for index in range(0, len(optimized_metrics)):
c_matrix = optimized_metrics.iloc[index]["Confusion_matrix"]
disp = ConfusionMatrixDisplay(
confusion_matrix=c_matrix, display_labels=["Less", "More"]
).plot(ax=ax.flat[index])
plt.subplots_adjust(top=1, bottom=0, hspace=0.4, wspace=0.3)
plt.show()
В желтом квадрате мы видим значение 1049, что обозначает количество правильно классифицированных объектов, отнесенных к классу "Less". Это свидетельствует о том, что модель успешно идентифицирует объекты этого класса, минимизируя количество ложных положительных срабатываний.
В зеленом квадрате значение 558 указывает на количество правильно классифицированных объектов, отнесенных к классу "More". Это также является показателем высокой точности модели в определении объектов данного класса.
Определение достижимого уровня качества модели для второй задачи (задача регрессии)¶
2. Прогнозирование цены закрытия акций:
Описание: Оценить, какая будет цена закрытия акций Starbucks на следующий день или через несколько дней на основе исторических данных. Целевая переменная: Цена закрытия (Close). (среднее значение)
Загрузка данных и создание целевой переменной
import pandas as pd
from sklearn import set_config
set_config(transform_output="pandas")
# Загрузка данных о ценах акций Starbucks из CSV файла
df = pd.read_csv(".//static//csv//Starbucks Dataset.csv")
# Опция для настройки генерации случайных чисел (если это нужно для других частей кода)
random_state = 42
# Вычисление среднего значения поля "Close"
average_close = df['Close'].mean()
print(f"Среднее значение поля 'Close': {average_close}")
# Создание новой колонки, указывающей, выше или ниже среднего значение цена закрытия
df['above_average_close'] = (df['Close'] > average_close).astype(int)
# Создание целевой переменной для прогнозирования (цена закрытия на следующий день)
df['Close_Next_Day'] = df['Close'].shift(-1)
# Удаление последней строки, где нет значения для следующего дня
df.dropna(inplace=True)
# Вывод DataFrame с новой колонкой
print(df.head())
# Примерный анализ данных
print("Статистическое описание DataFrame:")
print(df.describe())
Разделение набора данных на обучающую и тестовые выборки (80/20) для задачи регрессии¶
Целевой признак -- above_average_close
from typing import Tuple
import pandas as pd
from pandas import DataFrame
from sklearn.model_selection import train_test_split
def split_into_train_test(
df_input: DataFrame,
target_colname: str = "above_average_close",
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="above_average_close",
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 StarbucksFeatures(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X["Length_to_Width_Ratio"] = X["x"] / X["y"]
return X
def get_feature_names_out(self, features_in):
return np.append(features_in, ["Length_to_Width_Ratio"], axis=0)
# Указываем столбцы, которые нужно удалить и обрабатывать
columns_to_drop = ["Date"]
num_columns = ["Close", "Open", "Adj Close", "High", "Low", "Volume"]
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, ["Cabin_type"]),
],
remainder="passthrough",
)
# Создание окончательного конвейера
pipeline = Pipeline(
[
("features_preprocessing", features_preprocessing),
("drop_columns", drop_columns),
("model", RandomForestRegressor()) # Выбор модели для обучения
]
)
# Использование конвейера
def train_pipeline(X, y):
pipeline.fit(X, y)
Формирование набора моделей для регрессии
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.svm import SVR
from sklearn.model_selection import cross_val_score
def train_multiple_models(X, y, models):
results = {}
for model_name, model in models.items():
# Создаем конвейер для каждой модели
model_pipeline = Pipeline(
[
("features_preprocessing", features_preprocessing),
("drop_columns", drop_columns),
("model", model) # Используем текущую модель
]
)
# Обучаем модель и вычисляем кросс-валидацию
scores = cross_val_score(model_pipeline, X, y, cv=5) # 5-кратная кросс-валидация
results[model_name] = {
"mean_score": scores.mean(),
"std_dev": scores.std()
}
return results
models = {
"Random Forest": RandomForestRegressor(),
"Linear Regression": LinearRegression(),
"Gradient Boosting": GradientBoostingRegressor(),
"Support Vector Regression": SVR()
}
results = train_multiple_models(X_train, y_train, models)
# Вывод результатов
for model_name, scores in results.items():
print(f"{model_name}: Mean Score = {scores['mean_score']}, Standard Deviation = {scores['std_dev']}")
Лидирующие модели: Линейная регрессия проявила наилучшие результаты, за ней следует градиентный бустинг и Random Forest. Они продемонстрировали высокую эффективность в предсказании закрытия акций. Проблемы SVR: Резкое отличие в результатах SVR выявляет необходимость более тщательной настройки или выбора других подходов к решению задачи, поскольку текущие параметры не обеспечили адекватного уровня прогноза.
Обучение моделей на обучающем наборе данных и оценка на тестовом для регрессии
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 pandas as pd
import numpy as np
from sklearn import metrics
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor # пример модели
from sklearn.preprocessing import StandardScaler
# 1. Загрузка данных
data = pd.read_csv(".//static//csv//Starbucks Dataset.csv")
data['Date'] = pd.to_datetime(data['Date'])
data.set_index('Date', inplace=True)
# 2. Подготовка данных для прогноза
data['Close_shifted'] = data['Close'].shift(-1) # Смещение на 1 день для предсказания
data.dropna(inplace=True) # Удаление NaN, возникших из-за смещения
# Вычисляем среднее значение закрытия
average_close = data['Close'].mean()
data['above_average_close'] = (data['Close_shifted'] > average_close).astype(int) # 1, если выше среднего, иначе 0
# Предикторы и целевая переменная
X = data[['Open', 'High', 'Low', 'Close', 'Volume']]
y = data['above_average_close']
# 3. Инициализация модели и пайплайна
class_models = {
"RandomForest": {
"model": RandomForestRegressor(n_estimators=100, random_state=42),
}
}
pipeline_end = StandardScaler()
results = []
# 4. Обучение модели и оценка
for model_name in class_models.keys():
print(f"Model: {model_name}")
model = class_models[model_name]["model"]
model_pipeline = Pipeline([("scaler", 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]["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)
# Вывод результатов
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("-" * 40)
# Прогнозирование выше среднего для следующего дня
latest_data = X_test.iloc[-1:].copy()
predicted_above_average = model_pipeline.predict(latest_data)
predicted_above_average = 1 if predicted_above_average[0] > 0.5 else 0 # Преобразуем в бинарный выход
if predicted_above_average == 1:
print("Прогноз: Цена закроется выше среднего значения завтрашнего дня.")
else:
print("Прогноз: Цена закроется ниже среднего значения завтрашнего дня.")
Подбор гиперпараметров методом поиска по сетке
import pandas as pd
import numpy as np
from sklearn import metrics
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestRegressor # Используем регрессор
from sklearn.preprocessing import StandardScaler
# 1. Подготовка данных для прогноза
data['above_average_close'] = data['Close'].shift(-1) # Смещение на 1 день для предсказания
data.dropna(inplace=True) # Удаление NaN, возникших из-за смещения
# Предикторы и целевая переменная
X = data[['Open', 'High', 'Low', 'Close', 'Volume']]
y = data['above_average_close'] # Целевая переменная для регрессии
# Делим данные на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. Создание и настройка модели случайного леса
model = RandomForestRegressor() # Изменяем на регрессор
# Установка параметров для поиска по сетке
param_grid = {
'n_estimators': [50, 100, 200], # Количество деревьев
'max_depth': [None, 10, 20, 30], # Максимальная глубина дерева
'min_samples_split': [2, 5, 10] # Минимальное количество образцов для разбиения узла
}
# 3. Подбор гиперпараметров с помощью Grid Search
grid_search = GridSearchCV(estimator=model, param_grid=param_grid,
scoring='neg_mean_squared_error', cv=5, n_jobs=-1, verbose=2)
# Обучение модели на тренировочных данных
grid_search.fit(X_train, y_train)
# 4. Результаты подбора гиперпараметров
print("Лучшие параметры:", grid_search.best_params_)
print("Лучший результат (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, 5, 10] # Минимальное количество образцов для разбиения узла
}
# Подбор гиперпараметров с помощью 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()
# надеюсь, все...
Сравнив результаты с использованием старых и новых параметров, наблюдается, что новые параметры модели позволили добиться меньшей среднеквадратической ошибки, что указывает на более эффективное предсказание по сравнению со старыми настройками. Значение RMSE на тестовых данных также подтверждает улучшение качества модели, так как оно стало меньше и указывает на более точные прогнозы по сравнению с предыдущими настройками.