Примечание
Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.
Сравнение случайных лесов и моделей гистограммного градиентного бустинга
В этом примере мы сравним качество моделей случайного леса (RF) и гистограммного градиентного бустинга (HGBT) с точки зрения оценки и времени вычислений на наборе данных для регрессии, хотя все представленные здесь понятия применимы и к классификации.
Сравнение проводится путём изменения параметров, определяющих количество деревьев для каждого оценщика:
-
n_estimatorsопределяет количество деревьев в лесу. Это фиксированное число. -
max_iter— максимальное число итераций в модели, основанной на градиентном бустинге. Число итераций соответствует числу деревьев для задач регрессии и бинарной классификации. Кроме того, фактическое число деревьев, необходимое модели, зависит от критерия остановки.
HGBT использует градиентный бустинг, чтобы итеративно улучшать качество модели, подбирая каждое дерево под отрицательный градиент функции потерь относительно предсказанного значения. RF, напротив, основаны на бэггинге и используют голосование большинством для предсказания результата.
Дополнительную информацию о моделях ансамблей см. в Руководстве пользователя, а пример с демонстрацией других возможностей моделей HGBT — в разделе Возможности деревьев гистограммного градиентного бустинга.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Загрузка набора данных
from sklearn.datasets import fetch_california_housing X, y = fetch_california_housing(return_X_y=True, as_frame=True) n_samples, n_features = X.shape
HGBT использует алгоритм на основе гистограмм и сгруппированных значений признаков, который эффективно обрабатывает большие наборы данных (десятки тысяч объектов или больше) с большим количеством признаков (см. раздел Почему он работает быстрее). Реализация RF в scikit-learn не использует группировку и опирается на точное разделение, которое может требовать значительных вычислительных ресурсов.
print(f"The dataset consists of {n_samples} samples and {n_features} features")
The dataset consists of 20640 samples and 8 features
Вычисление оценки и времени вычислений
Обратите внимание, что многие части реализации HistGradientBoostingClassifier и HistGradientBoostingRegressor по умолчанию выполняются параллельно.
Реализации RandomForestRegressor и RandomForestClassifier также можно запускать на нескольких ядрах, используя параметр n_jobs, которому здесь задано значение, соответствующее числу физических ядер на компьютере. Дополнительную информацию см. в разделе Параллелизм.
import joblib
N_CORES = joblib.cpu_count(only_physical_cores=True)
print(f"Number of physical cores: {N_CORES}")
Number of physical cores: 3
В отличие от RF, модели HGBT поддерживают раннюю остановку (см. раздел Ранняя остановка в градиентном бустинге), позволяющую не добавлять новые ненужные деревья. Алгоритм использует отложенную выборку, чтобы оценивать способность модели к обобщению после добавления каждого дерева. Поэтому, если качество обобщения не улучшается на протяжении более чем n_iter_no_change итераций, добавление деревьев прекращается.
Другие параметры обеих моделей были подобраны, но эта процедура здесь не приводится, чтобы сохранить простоту примера.
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor, RandomForestRegressor
from sklearn.model_selection import GridSearchCV, KFold
models = {
"Random Forest": RandomForestRegressor(
min_samples_leaf=5, random_state=0, n_jobs=N_CORES
),
"Hist Gradient Boosting": HistGradientBoostingRegressor(
max_leaf_nodes=15, random_state=0, early_stopping=False
),
}
param_grids = {
"Random Forest": {"n_estimators": [10, 20, 50, 100]},
"Hist Gradient Boosting": {"max_iter": [10, 20, 50, 100, 300, 500]},
}
cv = KFold(n_splits=4, shuffle=True, random_state=0)
results = []
for name, model in models.items():
grid_search = GridSearchCV(
estimator=model,
param_grid=param_grids[name],
return_train_score=True,
cv=cv,
).fit(X, y)
result = {"model": name, "cv_results": pd.DataFrame(grid_search.cv_results_)}
results.append(result)
Примечание
Настройка параметра n_estimators для RF обычно приводит к напрасной трате вычислительных ресурсов. На практике достаточно убедиться, что его значение достаточно велико, чтобы его удвоение не приводило к существенному улучшению оценки на тестовой выборке.
Построение графика результатов
Для визуализации компромисса между временем вычислений и средней оценкой на тестовой выборке можно использовать plotly.express.scatter. При наведении курсора на точку отображаются соответствующие параметры. Полосы погрешностей соответствуют одному стандартному отклонению, рассчитанному по разным разбиениям при перекрёстной проверке.
import plotly.colors as colors
import plotly.express as px
from plotly.subplots import make_subplots
fig = make_subplots(
rows=1,
cols=2,
shared_yaxes=True,
subplot_titles=["Train time vs score", "Predict time vs score"],
)
model_names = [result["model"] for result in results]
colors_list = colors.qualitative.Plotly * (
len(model_names) // len(colors.qualitative.Plotly) + 1
)
for idx, result in enumerate(results):
cv_results = result["cv_results"].round(3)
model_name = result["model"]
param_name = next(iter(param_grids[model_name].keys()))
cv_results[param_name] = cv_results["param_" + param_name]
cv_results["model"] = model_name
scatter_fig = px.scatter(
cv_results,
x="mean_fit_time",
y="mean_test_score",
error_x="std_fit_time",
error_y="std_test_score",
hover_data=param_name,
color="model",
)
line_fig = px.line(
cv_results,
x="mean_fit_time",
y="mean_test_score",
)
scatter_trace = scatter_fig["data"][0]
line_trace = line_fig["data"][0]
scatter_trace.update(marker=dict(color=colors_list[idx]))
line_trace.update(line=dict(color=colors_list[idx]))
fig.add_trace(scatter_trace, row=1, col=1)
fig.add_trace(line_trace, row=1, col=1)
scatter_fig = px.scatter(
cv_results,
x="mean_score_time",
y="mean_test_score",
error_x="std_score_time",
error_y="std_test_score",
hover_data=param_name,
)
line_fig = px.line(
cv_results,
x="mean_score_time",
y="mean_test_score",
)
scatter_trace = scatter_fig["data"][0]
line_trace = line_fig["data"][0]
scatter_trace.update(marker=dict(color=colors_list[idx]))
line_trace.update(line=dict(color=colors_list[idx]))
fig.add_trace(scatter_trace, row=1, col=2)
fig.add_trace(line_trace, row=1, col=2)
fig.update_layout(
xaxis=dict(title="Train time (s) - lower is better"),
yaxis=dict(title="Test R2 score - higher is better"),
xaxis2=dict(title="Predict time (s) - lower is better"),
legend=dict(x=0.72, y=0.05, traceorder="normal", borderwidth=1),
title=dict(x=0.5, text="Speed-score trade-off of tree-based ensembles"),
)
Качество моделей HGBT и RF улучшается с увеличением числа деревьев в ансамбле. Однако оценки выходят на плато, после которого добавление деревьев лишь замедляет обучение и вычисление оценок. Модель RF достигает такого плато раньше и не может достичь оценки на тестовой выборке, полученной лучшей моделью HGBDT.
Обратите внимание, что результаты на графике выше могут незначительно меняться при каждом запуске и ещё сильнее — при запуске на других компьютерах. Попробуйте запустить этот пример на своём компьютере.
В целом обычно можно ожидать, что модели гистограммного градиентного бустинга будут неизменно превосходить модели случайного леса по компромиссу «оценка на тестовой выборке — скорость обучения» (кривая HGBDT должна располагаться выше и левее кривой RF, не пересекаясь с ней). Компромисс «оценка на тестовой выборке — скорость предсказания» может быть менее однозначным, но чаще всего он также складывается в пользу HGBDT. Всегда полезно проверить оба типа моделей (с настройкой гиперпараметров) и сравнить их качество на конкретной задаче, чтобы определить наиболее подходящую модель, однако HGBT почти всегда обеспечивает более выгодный компромисс между скоростью и точностью, чем RF — как с гиперпараметрами по умолчанию, так и с учётом затрат на их настройку.
Однако есть одно исключение из этого практического правила: при обучении модели многоклассовой классификации с большим числом возможных классов HGBDT на каждой итерации бустинга обучает внутри модели по одному дереву для каждого класса, тогда как деревья в моделях RF изначально поддерживают многоклассовую классификацию. В таком случае это может улучшить компромисс между скоростью и точностью моделей RF.
Общее время выполнения скрипта: (0 минут 32.231 секунды)
Связанные примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/ensemble/plot_forest_hist_grad_boosting_comparison.html