Занятие 6
Лабораторная 6. Градиентный бустинг.¶
# используемые библиотеки
from sklearn.model_selection import cross_val_score, KFold
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import optuna
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
import numpy as np
import pandas as pd
from catboost import CatBoostClassifier, Pool
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
import pandas as pd
from catboost import CatBoostRegressor, Pool
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
1. Гиперпараметры¶
1.1 Кросс-валидация¶
Кросс-валидация (cross-validation) — это метод оценки производительности модели машинного обучения, который позволяет избежать переобучения и получить более надежную оценку её качества. Вместо разделения данных на одну обучающую и одну тестовую выборки, как в случае с обычной проверкой на тестовых данных, кросс-валидация использует несколько различных разбиений данных для обучения и тестирования.
K-кратная кросс-валидация (K-fold cross-validation):
- Данные делятся на K равных частей (фолдов).
- Модель обучается K раз: каждый раз одна из частей используется как тестовая выборка, а остальные K-1 части — как обучающая.
- Результаты усредняются для получения окончательной оценки.
Предположим, у нас есть набор данных с 1000 объектами, и мы хотим оценить качество логистической регрессии для задачи бинарной классификации.
# Генерируем синтетические данные
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
# Создаем модель логистической регрессии
model = LogisticRegression()
# Инициализируем K-кратную кросс-валидацию с 5 фолдами
kf = KFold(n_splits=5, shuffle=True, random_state=42)
# Выполняем кросс-валидацию
scores = cross_val_score(model, X, y, cv=kf, scoring='accuracy')
# Выводим результаты
print("Оценки точности на каждом фолде:", scores)
print("Средняя точность:", scores.mean())
Плюсы:
- Меньший риск переобучения : Поскольку модель тестируется на нескольких подмножествах данных, вероятность переобучения снижается.
- Более эффективное использование данных : Все данные используются как для обучения, так и для тестирования.
- Устойчивость к случайным разбиениям : Усреднение результатов по нескольким фолдам делает оценку более стабильной.
Минусы:
- Высокая вычислительная сложность : Требуется обучить модель несколько раз.
- Зависимость от размера фолдов : Если фолды слишком маленькие, оценка может быть неточной.
1.2 Grid Search¶
Grid Search (или "поиск по сетке") — это метод подбора гиперпараметров модели, при котором мы задаем множество возможных значений для каждого гиперпараметра и перебираем все возможные комбинации этих значений. Для каждой комбинации модель обучается на обучающих данных, а затем оценивается на тестовых или валидационных данных. После этого выбирается та комбинация гиперпараметров, которая дает лучший результат.
# Загружаем данные
data = load_wine()
X, y = data.data, data.target
# Разделяем данные на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Определяем модель
rf = RandomForestClassifier(random_state=42)
# Задаем сетку гиперпараметров для перебора
param_grid = {
'n_estimators': [50, 100, 200], # Количество деревьев
'max_depth': [None, 10, 20, 30], # Максимальная глубина дерева
'min_samples_split': [2, 5, 10], # Минимальное количество образцов для разделения узла
'min_samples_leaf': [1, 2, 4] # Минимальное количество образцов в листе
}
# Инициализируем GridSearchCV с использованием кросс-валидации
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, scoring='accuracy', n_jobs=-1)
# Обучаем модель на обучающей выборке
grid_search.fit(X_train, y_train)
# Выводим лучшие параметры
print("Лучшие параметры:", grid_search.best_params_)
print("Лучшая точность на кросс-валидации:", grid_search.best_score_)
# Оцениваем качество модели на тестовой выборке
best_model = grid_search.best_estimator_
test_accuracy = best_model.score(X_test, y_test)
print("Точность на тестовой выборке:", test_accuracy)
# Дополнительно: оцениваем качество модели с помощью кросс-валидации на всех данных
cv_scores = cross_val_score(best_model, X, y, cv=5, scoring='accuracy')
print("Средняя точность по кросс-валидации на всех данных:", cv_scores.mean())
Плюсы:
- Простота реализации : Алгоритм простой и понятный.
- Полный перебор : Все возможные комбинации гиперпараметров проверяются, что гарантирует нахождение оптимального решения (если сетка достаточно плотная).
Минусы:
- Высокая вычислительная сложность : Если количество гиперпараметров велико или их диапазоны широки, число комбинаций может стать огромным.
- Неэффективность : Многие комбинации могут быть неинтересными или бессмысленными, но они всё равно проверяются.
1.3 Optuna¶
Optuna — это современная библиотека для подбора гиперпараметров, которая использует Bayesian Optimization и другие продвинутые методы для эффективного поиска оптимальных значений гиперпараметров. В отличие от Grid Search или Randomized Search, которые перебирают значения из заранее заданных сеток или случайно выбирают их, Optuna адаптивно находит лучшие комбинации гиперпараметров, учитывая предыдущие результаты.
- Optuna использует алгоритмы, такие как Tree-structured Parzen Estimator (TPE) и Bayesian Optimization, что делает её более эффективной, особенно для сложных задач.
- Optuna может автоматически прерывать вычисления для неперспективных наборов гиперпараметров (early stopping).
- Optuna легко интегрируется с популярными фреймворками машинного обучения, такими как scikit-learn, TensorFlow, PyTorch и др.
- Optuna поддерживает параллельный поиск гиперпараметров, что позволяет использовать несколько ядер процессора или даже распределенные системы.
Дан датасет, со следующими признаками (скачать файл Loan.csv).
- ApplicationDate: Loan application date
- Age: Applicant's age
- AnnualIncome: Yearly income
- CreditScore: Creditworthiness score
- EmploymentStatus: Job situation
- EducationLevel: Highest education attained
- Experience: Work experience
- LoanAmount: Requested loan size
- LoanDuration: Loan repayment period
- MaritalStatus: Applicant's marital state
- NumberOfDependents: Number of dependents
- HomeOwnershipStatus: Homeownership type
- MonthlyDebtPayments: Monthly debt obligations
- CreditCardUtilizationRate: Credit card usage percentage
- NumberOfOpenCreditLines: Active credit lines
- NumberOfCreditInquiries: Credit checks count
- DebtToIncomeRatio: Debt to income proportion
- BankruptcyHistory: Bankruptcy records
- LoanPurpose: Reason for loan
- PreviousLoanDefaults: Prior loan defaults
- PaymentHistory: Past payment behavior
- LengthOfCreditHistory: Credit history duration
- SavingsAccountBalance: Savings account amount
- CheckingAccountBalance: Checking account funds
- TotalAssets: Total owned assets
- TotalLiabilities: Total owed debts
- MonthlyIncome: Income per month
- UtilityBillsPaymentHistory: Utility payment record
- JobTenure: Job duration
- NetWorth: Total financial worth
- BaseInterestRate: Starting interest rate
- InterestRate: Applied interest rate
- MonthlyLoanPayment: Monthly loan payment
- TotalDebtToIncomeRatio: Total debt against income
Также датсет содержит информацию:
- LoanApproved: Loan approval status - будет ли кредит одобрен (для задачи классификации).
- RiskScore: Risk assessment score - оценка риска (для задачи регрессии).
Задача 1 (3 балла)¶
Давайте решим задачу бинарной классификации (будет выдан кредит или нет).
Не забудьте удалить столбец RiskScore!
- Разбейте выборку на обучающую и тестовую.
- Подберите оптимальные гиперпараметры с помощью кросс-валидации и optuna на обучающей выборке.
- Расчитайте F1-score на тестовой выборке.
2. Catboost¶
2.1 CatboostClassifier¶
CatBoostClassifier — это мощный алгоритм машинного обучения из библиотеки CatBoost , разработанной компанией Yandex. Он является частью фреймворка CatBoost, который специализируется на обработке категориальных признаков без необходимости их предварительного кодирования (например, с помощью One-Hot Encoding). CatBoost использует градиентный бустинг над деревьями решений и показывает высокую производительность на задачах классификации. Основные особенности CatboostClassifier:
- Автоматическая обработка категориальных признаков : CatBoost может работать с категориальными признаками напрямую.
- Снижение переобучения : CatBoost использует методы, такие как перестановочный тест и порядковое целевое кодирование.
- Высокая скорость обучения : Библиотека оптимизирована для быстрого обучения даже на больших объемах данных.
- Поддержка многозадачности : CatBoost может обучаться на нескольких задачах одновременно.
- Встроенная кросс-валидация и подбор гиперпараметров .
# Генерация синтетического датасета
np.random.seed(42)
# Числовые признаки
num_feature_1 = np.random.normal(5, 2, 1000) # Признак 1: нормальное распределение
num_feature_2 = np.random.uniform(0, 10, 1000) # Признак 2: равномерное распределение
# Категориальные признаки
cat_feature_1 = np.random.choice(['A', 'B', 'C'], size=1000) # Категориальный признак 1
cat_feature_2 = np.random.choice(['X', 'Y'], size=1000) # Категориальный признак 2
# Целевая переменная (зависимость от признаков)
target = []
for i in range(1000):
if num_feature_1[i] > 6 and cat_feature_1[i] in ['A', 'B']: # Правило для класса 1
target.append(1)
elif num_feature_2[i] < 5 and cat_feature_2[i] == 'X': # Правило для класса 1
target.append(1)
else:
target.append(0)
# Создание DataFrame
data = pd.DataFrame({
'NumFeature1': num_feature_1,
'NumFeature2': num_feature_2,
'CatFeature1': cat_feature_1,
'CatFeature2': cat_feature_2,
'Target': target
})
# Разделение на признаки и целевую переменную
X = data.drop(columns=['Target'])
y = data['Target']
# Указание категориальных признаков
categorical_features = ['CatFeature1', 'CatFeature2']
# Разделение данных на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Создание объектов Pool для CatBoost
train_pool = Pool(data=X_train, label=y_train, cat_features=categorical_features)
test_pool = Pool(data=X_test, label=y_test, cat_features=categorical_features)
# Инициализация модели CatBoostClassifier
model = CatBoostClassifier(
iterations=100, # Количество итераций (деревьев)
depth=6, # Максимальная глубина дерева
learning_rate=0.1, # Скорость обучения
loss_function='Logloss', # Функция потерь для бинарной классификации
verbose=10 # Вывод информации каждые 10 итераций
)
# Обучение модели
model.fit(train_pool)
# Предсказания на тестовой выборке
predictions = model.predict(test_pool)
# Оценка качества модели
accuracy = accuracy_score(y_test, predictions)
print(f"Точность модели: {accuracy:.4f}")
# Важность признаков
feature_importances = model.get_feature_importance()
for feature, importance in zip(X.columns, feature_importances):
print(f"{feature}: {importance:.4f}")
Задача 2 (3 балла)¶
Решите предыдущую задачу, используя CatboostClassifier.
2.2 CatboostRegressor¶
CatBoostRegressor — это алгоритм регрессии из библиотеки CatBoost , разработанной компанией Yandex. Он является частью фреймворка CatBoost, который специализируется на градиентном бустинге над деревьями решений и поддерживает как числовые, так и категориальные признаки без необходимости их предварительного кодирования (например, One-Hot Encoding). CatBoostRegressor используется для решения задач регрессии, где целевая переменная является непрерывной. Основные особенности CatBoostRegressor:
- Автоматическая обработка категориальных признаков : CatBoost может работать с категориальными признаками напрямую.
- Снижение переобучения : CatBoost использует методы, такие как перестановочный тест и порядковое целевое кодирование.
- Высокая скорость обучения : Библиотека оптимизирована для быстрого обучения даже на больших объемах данных.
- Поддержка многозадачности : CatBoost может обучаться на нескольких задачах одновременно.
- Встроенная кросс-валидация и подбор гиперпараметров .
# Генерация синтетического датасета
np.random.seed(42)
# Числовые признаки
area = np.random.uniform(50, 200, 1000) # Площадь дома (в квадратных метрах)
num_rooms = np.random.randint(1, 6, 1000) # Количество комнат
age = np.random.randint(0, 50, 1000) # Возраст дома (в годах)
# Категориальные признаки
location = np.random.choice(['City', 'Suburb', 'Rural'], size=1000) # Местоположение
# Целевая переменная (зависимость от признаков)
price = 50000 + area * 1000 - age * 500 + np.random.normal(0, 10000, 1000) # Цена дома
# Создание DataFrame
data = pd.DataFrame({
'Area': area,
'NumRooms': num_rooms,
'Age': age,
'Location': location,
'Price': price
})
# Разделение на признаки и целевую переменную
X = data.drop(columns=['Price'])
y = data['Price']
# Указание категориальных признаков
categorical_features = ['Location']
# Разделение данных на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Создание объектов Pool для CatBoost
train_pool = Pool(data=X_train, label=y_train, cat_features=categorical_features)
test_pool = Pool(data=X_test, label=y_test, cat_features=categorical_features)
# Инициализация модели CatBoostRegressor
model = CatBoostRegressor(
iterations=100, # Количество итераций (деревьев)
depth=6, # Максимальная глубина дерева
learning_rate=0.1, # Скорость обучения
loss_function='RMSE', # Функция потерь для регрессии (Root Mean Squared Error)
verbose=10 # Вывод информации каждые 10 итераций
)
# Обучение модели
model.fit(train_pool)
# Предсказания на тестовой выборке
predictions = model.predict(test_pool)
# Оценка качества модели
mse = mean_squared_error(y_test, predictions)
rmse = np.sqrt(mse)
print(f"RMSE: {rmse:.2f}")
# Важность признаков
feature_importances = model.get_feature_importance()
for feature, importance in zip(X.columns, feature_importances):
print(f"{feature}: {importance:.4f}")
Задача 3 (3 балла)¶
Решите предыдущую задачу, используя CatBoostRegressor. В качестве прогнозируемого значения используйте столбец RiskScore.
3. Стекинг¶
Стекинг (stacking) — это продвинутый метод ансамблевого обучения, при котором несколько базовых моделей ("базовые оценщики") объединяются для создания более точной модели. Стекинг включает два основных этапа:
Обучение базовых моделей: На этом этапе несколько различных алгоритмов машинного обучения (например, логистическая регрессия, случайный лес, градиентный бустинг и т.д.) обучаются на обучающих данных.
Обучение мета-модели: Предсказания базовых моделей используются как входные данные для второй модели (мета-модели), которая учится комбинировать их предсказания для получения финального результата.
Пусть у нас есть $ M $ базовых моделей $ f_1(x), f_2(x), \dots, f_M(x) $, где каждая модель принимает на вход признаки $ x $ и выдает предсказание. Например: $$ f_i(x) = \hat{y}_i, \quad i = 1, 2, \dots, M $$
Здесь $ \hat{y}_i $ — предсказание $ i $-ой базовой модели.
Каждая базовая модель обучается на обучающем наборе данных $ D_{\text{train}} $. Для этого можно использовать любые алгоритмы машинного обучения, такие как линейная регрессия, деревья решений, градиентный бустинг и т.д.
После обучения базовых моделей мы создаем новый набор данных, где каждый объект представляет собой вектор предсказаний всех базовых моделей для данного объекта. Например, если у нас есть $ N $ объектов в обучающей выборке, то новый набор данных будет иметь размерность $ N \times M $, где $ M $ — количество базовых моделей.
Для объекта $ x_j $ новое представление будет выглядеть так: $$ z_j = [f_1(x_j), f_2(x_j), \dots, f_M(x_j)] $$
Где $ z_j $ — вектор предсказаний для $ j $-го объекта.
Мета-модель (например, линейная регрессия, решающее дерево или нейронная сеть) обучается на новом наборе данных $ Z = \{z_1, z_2, \dots, z_N\} $ и соответствующих истинных значениях целевой переменной $ y $.
Мета-модель пытается найти функцию $ g(z) $, которая минимизирует ошибку между предсказанными значениями и истинными значениями: $$ g(Z) = \arg\min_g \sum_{j=1}^N L(y_j, g(z_j)) $$
Где $ L $ — функция потерь (например, среднеквадратичная ошибка для задач регрессии или кросс-энтропия для задач классификации).
Для нового объекта $ x_{\text{new}} $:
- Каждая базовая модель делает свое предсказание: $ \hat{y}_1, \hat{y}_2, \dots, \hat{y}_M $.
- Эти предсказания формируют вектор $ z_{\text{new}} = [\hat{y}_1, \hat{y}_2, \dots, \hat{y}_M] $.
- Мета-модель делает финальное предсказание: $ \hat{y}_{\text{final}} = g(z_{\text{new}}) $.
Задача 4 (1 балл)¶
Решите предыдущую задачу используя стекинг моделей.