питон

Познакомьтесь с HistGradientBoostingClassifier

Более гибкий и масштабируемый GradientBoostingClassifier

GradientBoostingClassifier от Scikit-learn (далее GBM) — один из самых популярных ансамблевых алгоритмов, который хорошо работает со многими наборами данных. HistGradientBoostingClassifier (далее HGBM), основанная на гистограмме альтернативная реализация GBM, была представлена ​​в v0.21.0 в качестве экспериментальной оценки. Начиная с v1.0.0, этот оценщик стал стабильным оценщиком. В этом посте мы рассмотрим два основных преимущества использования HGBM по сравнению с GBM.

Существует также эквивалент регрессии: HistGradientBoostingRegressor. Однако мы не будем освещать его, чтобы избежать повторения, поскольку применяется та же логика.

📦 1. Обрабатывает отсутствующие данные

Этот оценщик может работать с отсутствующими данными, поскольку он имеет встроенную поддержку отсутствующих значений. Давайте посмотрим на это в действии. Мы начнем с импорта библиотек и создания примера данных с отсутствующими значениями:

import numpy as np
import pandas as pd
from time import perf_counter
pd.options.display.max_columns = 6
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import (GradientBoostingClassifier, 
                              HistGradientBoostingClassifier)
from sklearn.metrics import accuracy_score, roc_auc_score, f1_score
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid', context='talk', palette='rainbow')
n = 10**4
X, y = make_classification(n, random_state=42)
X = pd.DataFrame(X, columns=[f'feature{i}' for i in range(X.shape[1])])
# Randomly add missing data for all columns
for i, col in enumerate(X.columns):
    np.random.seed(i)
    X.loc[np.random.choice(range(n), 1000, replace=False), col] = np.nan
print(f"Target shape: {y.shape}")
print(f"Features shape: {X.shape}")
X.head()

Теперь мы разделим данные и попробуем подобрать GBM:

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
print("========== Training data ========== ")
print(f"Features: {X_train.shape} | Target:{y_train.shape}")
print("========== Test data ========== ")
print(f"Features: {X_test.shape} | Target:{y_test.shape}")
gbm = GradientBoostingClassifier(random_state=42)
gbm.fit(X_train, y_train)
gbm.score(X_test, y_test)

Как и в большинстве средств оценки Scikit-learn, попытка подогнать модель под данные с отсутствующими значениями вызовет ValueError: Input contains NaN, infinity or a value too large for dtype('float32').

Теперь давайте посмотрим, что произойдет, если мы используем HGBM:

hgbm = HistGradientBoostingClassifier(random_state=42)
hgbm.fit(X_train, y_train)
hgbm.score(X_test, y_test)

Удивительно, это работает отлично, так как оценщик может изначально обрабатывать недостающие данные. Это одно из преимуществ, которое HGBM предлагает по сравнению с GBM.

📊 2. Хорошо масштабируется с большими данными

HGBM является более быстрой реализацией GBM и хорошо масштабируется с большими наборами данных. Давайте посмотрим, как обе оценки сравниваются на выборочных данных с разными размерами:

n_samples = 10**np.arange(2,7)
tuples = [*zip(np.repeat(n_samples,2), np.tile(['gbm', 'hgbm'], 2))]
summary = pd.DataFrame(
    index=pd.MultiIndex.from_tuples(tuples, 
                                    names=["n_records", "model"])
)
models = [('gbm', GradientBoostingClassifier(random_state=42)), 
          ('hgbm', HistGradientBoostingClassifier(random_state=42))]
for n in n_samples:
    X, y = make_classification(n, random_state=42)
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, random_state=42
    )
    
    for name, model in models:
        start = perf_counter()
        model.fit(X_train, y_train)
        end = perf_counter()
        summary.loc[(n, name), 'fit_time'] = end-start
start = perf_counter()
        y_proba = model.predict_proba(X_test)[:,1]
        end = perf_counter()
        summary.loc[(n, name), 'score_time'] = end-start
        
        summary.loc[(n, name), 'roc_auc'] = roc_auc_score(y_test, 
                                                          y_proba)
        y_pred = np.round(y_proba)
        summary.loc[(n, name), 'accuracy'] = accuracy_score(y_test, 
                                                            y_pred)
        summary.loc[(n, name), 'f1'] = f1_score(y_test, y_pred)
summary

Здесь 75% всех записей используются для обучения, а оставшиеся 25% записей используются для тестирования. Мы видим, что время обучения намного быстрее с HGBM по мере роста данных обучения. Чем больше данных, тем более впечатляющая скорость HGBM. HGBM достигает своей удивительной скорости за счет огрубления данных в бинарные функции. Давайте посмотрим на резюме немного внимательнее:

fig, ax = plt.subplots(2, 1, figsize=(9,6), sharex=True)
sns.lineplot(data=summary['fit_time'].reset_index(), 
             x='n_records', y='fit_time', hue='model', ax=ax[0])
ax[0].legend(loc='upper right', bbox_to_anchor=(1.3, 1))
sns.lineplot(data=summary['score_time'].reset_index(), 
             x='n_records', y='score_time', hue='model', 
             legend=False, ax=ax[1])
ax[1].set_xscale('log')
fig.tight_layout();

Время обучения значительно увеличивается с GBM по мере увеличения количества обучающих примеров, тогда как с HGBM оно по-прежнему относительно быстрое на больших наборах данных. Время подсчета очков довольно близко между ними.

fig, ax = plt.subplots(3, 1, figsize=(9,9), sharex=True)
sns.lineplot(data=summary['roc_auc'].reset_index(), 
             x='n_records', y='roc_auc', hue='model', ax=ax[0])
ax[0].legend(loc='upper right', bbox_to_anchor=(1.3, 1))
sns.lineplot(data=summary['accuracy'].reset_index(), 
             x='n_records', y='accuracy', hue='model', 
             legend=False, ax=ax[1])
sns.lineplot(data=summary['f1'].reset_index(), 
             x='n_records', y='f1', hue='model', 
             legend=False, ax=ax[2])
ax[2].set_xscale('log')
fig.tight_layout();

В целом, прогностическая эффективность между ними очень похожа, хотя есть небольшая разница, когда обучающие данные меньше на 75 и 750.

Как вы уже заметили, второе преимущество HGBM заключается в том, что он очень хорошо масштабируется с большими наборами данных по сравнению с GBM.

Вот и все! Надеюсь, вам понравилось знакомство с этим гибким и масштабируемым оценщиком, и вы с нетерпением ждете его дальнейшего изучения. Если вы хотите узнать больше, HGBM также имеет встроенную поддержку категориальных функций. Эта документация показывает несколько отличных примеров использования этой функции.

Хотели бы вы получить доступ к большему содержанию, подобному этому? Участники Medium получают неограниченный доступ к любым статьям на Medium. Если вы станете участником, используя мою реферальную ссылку, часть вашего членского взноса пойдет непосредственно на мою поддержку.

Спасибо, что прочитали эту статью. Если интересно, вот ссылки на некоторые другие мои посты:
◼️️ От модели ML к ML Pipeline
◼️️ Объяснение моделей Scikit-learn с помощью SHAP
◼️️ 4 простых совета по построению нескольких графиков в Python
◼️ Приведение в порядок фреймов данных pandas
Простые способы визуализации данных в Python, которые вам пригодятся
◼️ 6 простых советов, как сделать красивее и индивидуальные графики в Seaborn (Python)

Пока пока 🏃 💨