203 KiB
Лабораторная работа №3¶
Определение бизнес-целей и технических целей проекта¶
Вариант задания: Набор данных о ценах на акции Starbucks.
Бизнес-цель: Создать модель машинного обучения для предсказания объема продаж акций компании Starbucks на основе таких характеристик, как цена открытия и цена закрытия.
Технические цели проекта:
Удаление пропусков, выбросов и дублированных записей для повышения качества данных.
Кодирование категориальных признаков в числовые значения.
Разделение набора данных на обучающую, контрольную и тестовую выборки для оценки модели.
Столбцы датасета и их пояснение:
Date - Дата, на которую относятся данные. Эта характеристика указывает конкретный день, в который происходила торговля акциями Starbucks.
Open - Цена открытия. Стоимость акций Starbucks в начале торгового дня. Это важный показатель, который показывает, по какой цене начались торги в конкретный день, и часто используется для сравнения с ценой закрытия для определения дневного тренда.
High - Максимальная цена за день. Наибольшая цена, достигнутая акциями Starbucks в течение торгового дня. Эта характеристика указывает, какой была самая высокая стоимость акций за день.
Low - Минимальная цена за день. Наименьшая цена, по которой торговались акции Starbucks в течение дня.
Close - Цена закрытия. Стоимость акций Starbucks в конце торгового дня. Цена закрытия — один из основных показателей, используемых для анализа акций, так как она отображает итоговую стоимость акций за день и часто используется для расчета дневных изменений и трендов на длительных временных периодах.
Adj Close - Скорректированная цена закрытия. Цена закрытия, скорректированная с учетом всех корпоративных действий.
Volume - Объем торгов. Количество акций Starbucks, проданных и купленных в течение дня.
Получим очищенный и структурированный набор данных
import pandas as pn
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.ticker as ticker
from datetime import datetime
import matplotlib.dates as md
df = pn.read_csv("..//static//csv//StarbucksDataset.csv")
print(df.columns)
df["date"] = df.apply(lambda row: datetime.strptime(row["Date"], "%Y-%m-%d"), axis=1)
df.info()
Разбиение на обучающую, контрольную и тестовую выборки¶
Разделим набор данных на обучающую, контрольную и тестовую выборки для предотвращения утечки данных. Для начала разделим данные на обучающую и тестовую выборки, а затем обучающую выборку на обучающую и контрольную.
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(df, test_size=0.2, random_state=42)
train_data, val_data = train_test_split(train_data, test_size=0.2, random_state=42)
print("Размер обучающей выборки:", len(train_data))
print("Размер контрольной выборки:", len(val_data))
print("Размер тестовой выборки:", len(test_data))
Создание диаграмм¶
Создадим три диаграммы(гистограммы) отображающие распределение объёма торгов в разных выборках данных: обучающей, контрольной и тестовой.
import seaborn as sns
import matplotlib.pyplot as plt
sns.histplot(train_data["Volume"], kde=True, color="blue")
plt.title('Распределение объема в обучающей выборке')
plt.xlabel('Объем')
plt.ylabel('Частота')
plt.show()
sns.histplot(val_data["Volume"], kde=True, color="red")
plt.title('Распределение объема в контрольной выборке')
plt.xlabel('Объем')
plt.ylabel('Частота')
plt.show()
sns.histplot(test_data["Volume"], kde=True, color="green")
plt.title('Распределение объема в тестовой выборке')
plt.xlabel('Объем')
plt.ylabel('Частота')
plt.show()
print("Средний объем торгов в обучающей выборке: ", train_data['Volume'].mean())
print("Средний объем торгов в контрольной выборке: ", val_data['Volume'].mean())
print("Средний объем торгов в тестовой выборке: ", test_data['Volume'].mean())
Процесс конструирования признаков¶
Теперь приступим к конструированию признаков для решения бизнес задачи.
Унитарное кодирование
Унитарное кодирование категориальных признаков (one-hot encoding). Преобразование категориальных признаков в бинарные векторы.
Дискретизация числовых признаков
Процесс преобразования непрерывных числовых значений в дискретные категории или интервалы (бины).
Ручной синтез
Создание новых признаков на основе экспертных знаний и логики предметной области.
Масштабирование признаков
Процесс преобразования числовых признаков таким образом, чтобы они имели одинаковый масштаб. Это важно для многих алгоритмов машинного обучения, которые чувствительны к масштабу признаков, таких как линейная регрессия, метод опорных векторов (SVM) и нейронные сети.
One-hot encoding:
import pandas as pd
# Пример категориальных признаков
categorical_features = [
"Date",
"date"
]
# Применение one-hot encoding
train_data_encoded = pd.get_dummies(train_data, columns=categorical_features)
val_data_encoded = pd.get_dummies(val_data, columns=categorical_features)
test_data_encoded = pd.get_dummies(test_data, columns=categorical_features)
Дискретизация числовых признаков:
import pandas as pd
import numpy as np
labels = ["Low hight value", "Medium hight value", "Very hight value"]
num_bins = 3
# Создаем числовые интервалы и метки
hist, bins = np.histogram(df["High_filled"], bins=num_bins)
df["High_bin"] = pd.cut(df["High_filled"], bins=bins)
df["High_category"] = pd.cut(df["High_filled"], bins=bins, labels=labels)
combined_table = df[["High", "High_bin", "High_category"]]
print(combined_table.head(20))
Ручной синтез:
# Пример синтеза признака среднего значения в максимальной и минимальной цене
train_data_encoded["medium"] = train_data_encoded["High"] / train_data_encoded["Low"]
val_data_encoded["medium"] = val_data_encoded["High"] / val_data_encoded["Low"]
test_data_encoded["medium"] = test_data_encoded["High"] / test_data_encoded["Low"]
Масштабирование признаков:
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Пример масштабирования числовых признаков
numerical_features = ["Open", "Close"]
scaler = StandardScaler()
train_data_encoded[numerical_features] = scaler.fit_transform(train_data_encoded[numerical_features])
val_data_encoded[numerical_features] = scaler.transform(val_data_encoded[numerical_features])
test_data_encoded[numerical_features] = scaler.transform(test_data_encoded[numerical_features])
Конструирование признаков с применением фреймворка Featuretools:
import featuretools as ft
es = ft.EntitySet(id='starbucks_data')
es = es.add_dataframe(dataframe_name='starbucks', dataframe=train_data_encoded, index='id')
# Генерация признаков
feature_matrix, feature_defs = ft.dfs(
entityset=es,
target_dataframe_name="starbucks",
max_depth=2
)
# Преобразование признаков для контрольной и тестовой выборок
val_feature_matrix = ft.calculate_feature_matrix(features=feature_defs, entityset=es, instance_ids=val_data_encoded.index)
test_feature_matrix = ft.calculate_feature_matrix(features=feature_defs, entityset=es, instance_ids=test_data_encoded.index)
print(feature_matrix.head())
Оценка качества каждого набора признаков¶
Предсказательная способность
Метрики: RMSE, MAE, R²
Методы: Обучение модели на обучающей выборке и оценка на контрольной и тестовой выборках.
Скорость вычисления
Методы: Измерение времени выполнения генерации признаков и обучения модели.
Надежность
Методы: Кросс-валидация, анализ чувствительности модели к изменениям в данных.
Корреляция
Методы: Анализ корреляционной матрицы признаков, удаление мультиколлинеарных признаков.
Цельность
Методы: Проверка логической связи между признаками и целевой переменной, интерпретация результатов модели.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import seaborn as sns
# Удаление строк с NaN
feature_matrix = feature_matrix.dropna()
val_feature_matrix = val_feature_matrix.dropna()
test_feature_matrix = test_feature_matrix.dropna()
X_train = feature_matrix.drop("Volume", axis=1)
y_train = feature_matrix["Volume"]
X_val = val_feature_matrix.drop("Volume", axis=1)
y_val = val_feature_matrix["Volume"]
X_test = test_feature_matrix.drop("Volume", axis=1)
y_test = test_feature_matrix["Volume"]
# Выбор модели
model = RandomForestRegressor(random_state=42)
# Обучение модели
model.fit(X_train, y_train)
# Предсказание и оценка
y_pred = model.predict(X_test)
rmse = mean_squared_error(y_test, y_pred, squared=False)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f"RMSE: {rmse}")
print(f"R²: {r2}")
print(f"MAE: {mae}")
# Кросс-валидация
scores = cross_val_score(model, X_train, y_train, cv=5, scoring='neg_mean_squared_error')
rmse_cv = (-scores.mean())**0.5
print(f"Cross-validated RMSE: {rmse_cv}")
# Анализ важности признаков
feature_importances = model.feature_importances_
feature_names = X_train.columns
print(f"=====================================")
# Проверка на переобучение
y_train_pred = model.predict(X_train)
rmse_train = mean_squared_error(y_train, y_train_pred, squared=False)
r2_train = r2_score(y_train, y_train_pred)
mae_train = mean_absolute_error(y_train, y_train_pred)
print(f"Метрика Train RMSE: {rmse_train}")
print(f"Метрика Train R²: {r2_train}")
print(f"Метрика Train MAE: {mae_train}")
# Визуализация результатов
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)
plt.xlabel("Фактический объем продаж акций")
plt.ylabel("Предсказанный объем продаж акций")
plt.title("Фактический объем / Предсказанный объем")
plt.show()
Вывод и итог¶
Качество предсказаний: Модель демонстрирует впечатляющий коэффициент детерминации R² на уровне 0.9975, что свидетельствует о ее способности эффективно объяснять изменения в распродажах. Низкие значения RMSE и MAE подтверждают, что модель предсказывает цены с высокой степенью точности.
Проблема переобучения: Разница в значениях RMSE между обучающей и тестовой выборками относительно мала, что говорит о минимальных рисках переобучения. Тем не менее, важно оставаться внимательным и продолжать следить за этим аспектом.