Spec-Zone.ru › scikit-learn

1.11. Ансамбли: градиентный бустинг, случайные леса, бэггинг, голосование, стекинг

Ансамблевые методы объединяют предсказания нескольких базовых оценщиков, построенных с помощью заданного алгоритма обучения, чтобы повысить способность к обобщению / устойчивость по сравнению с одним оценщиком.

Два очень известных примера ансамблевых методов — это деревья с градиентным бустингом и случайные леса.

В более общем случае ансамблевые модели можно применять к любому базовому алгоритму обучения, не только к деревьям, используя методы усреднения, такие как методы бэггинга, стекинг моделей или голосование, либо бустинг, например AdaBoost.

1.11.1. Деревья с градиентным бустингом

Градиентный бустинг деревьев, или деревья решений с градиентным бустингом (GBDT), — это обобщение бустинга на произвольные дифференцируемые функции потерь; см. основополагающую работу [Friedman2001]. GBDT — отличная модель как для регрессии, так и для классификации, особенно для табличных данных.

GradientBoostingClassifier против HistGradientBoostingClassifier

Scikit-learn предоставляет две реализации деревьев с градиентным бустингом: HistGradientBoostingClassifier и GradientBoostingClassifier для классификации, а также соответствующие классы для регрессии. Первая реализация может быть на порядки быстрее второй, если число объектов превышает несколько десятков тысяч.

Версия Hist… изначально поддерживает пропущенные значения и категориальные данные, устраняя необходимость в дополнительной предварительной обработке, такой как импутация.

GradientBoostingClassifier и GradientBoostingRegressor могут быть предпочтительнее при небольшом количестве объектов, поскольку в таких условиях разбиение на интервалы может приводить к слишком приблизительным точкам разделения.

1.11.1.1. Градиентный бустинг на основе гистограмм

В Scikit-learn 0.21 появились две новые реализации деревьев градиентного бустинга: HistGradientBoostingClassifier и HistGradientBoostingRegressor, созданные под влиянием LightGBM (см. [LightGBM]).

Эти оцениватели на основе гистограмм могут быть на порядки быстрее, чем GradientBoostingClassifier и GradientBoostingRegressor, если число образцов превышает несколько десятков тысяч.

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

Сначала эти быстрые оцениватели разбивают входные образцы X на бины со значениями типа integer (обычно 256 бинов). Это значительно сокращает число рассматриваемых точек разбиения и позволяет алгоритму использовать структуры данных на основе целых чисел (гистограммы) вместо отсортированных непрерывных значений при построении деревьев. API этих оценивателей немного отличается, и некоторые возможности из GradientBoostingClassifier и GradientBoostingRegressor пока не поддерживаются, например некоторые функции потерь.

Примеры

  • Графики частичной зависимости и индивидуальных условных ожиданий
  • Сравнение моделей случайного леса и градиентного бустинга на основе гистограмм

1.11.1.1.1. Использование

Большинство параметров не изменились по сравнению с GradientBoostingClassifier и GradientBoostingRegressor. Одно из исключений — параметр max_iter, заменяющий n_estimators и задающий число итераций процесса бустинга:

>>> from sklearn.ensemble import HistGradientBoostingClassifier
>>> from sklearn.datasets import make_hastie_10_2

>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]

>>> clf = HistGradientBoostingClassifier(max_iter=100).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.8965

Для регрессии доступны следующие функции потерь:

  • ‘squared_error’ — функция потерь по умолчанию;
  • ‘absolute_error’ — менее чувствительна к выбросам, чем квадратичная ошибка;
  • ‘gamma’ — хорошо подходит для моделирования строго положительных результатов;
  • ‘poisson’ — хорошо подходит для моделирования счетных данных и частот;
  • ‘quantile’ — позволяет оценивать условный квантиль, который впоследствии можно использовать для получения интервалов предсказания.

Для классификации доступен только вариант ‘log_loss’. В бинарной классификации используется бинарная логарифмическая функция потерь, также известная как биномиальное отклонение или бинарная кросс-энтропия. Для n_classes >= 3 используется многоклассовая логарифмическая функция потерь, также называемая мультиномиальным отклонением или категориальной кросс-энтропией. Подходящий вариант функции потерь выбирается на основе значения y, переданного в fit.

Размер деревьев можно контролировать с помощью параметров max_leaf_nodes, max_depth и min_samples_leaf.

Число бинов, используемых для разбиения данных, задается параметром max_bins. Использование меньшего числа бинов действует как регуляризация. Обычно рекомендуется использовать максимально возможное число бинов (255), установленное по умолчанию.

Параметр l2_regularization служит регуляризатором функции потерь и соответствует \(\lambda\) в следующем выражении (см. уравнение (2) в [XGBoost]):

\[\mathcal{L}(\phi) = \sum_i l(\hat{y}_i, y_i) + \frac12 \sum_k \lambda ||w_k||^2\]
Подробнее о регуляризации l2

Важно отметить, что слагаемое потерь \(l(\hat{y}_i, y_i)\) описывает только половину фактической функции потерь, за исключением pinball loss и абсолютной ошибки.

Индекс \(k\) обозначает k-е дерево в ансамбле деревьев. В случае регрессии и бинарной классификации модели градиентного бустинга на каждой итерации строят по одному дереву, поэтому \(k\) принимает значения до max_iter. В случае задач многоклассовой классификации максимальное значение индекса \(k\) равно n_classes \(\times\) max_iter.

Если \(T_k\) обозначает число листьев в k-м дереве, то \(w_k\) — вектор длины \(T_k\), содержащий значения листьев вида w = -sum_gradient / (sum_hessian + l2_regularization) (см. уравнение (5) в [XGBoost]).

Значения листьев \(w_k\) получаются делением суммы градиентов функции потерь на общую сумму гессианов. Добавление регуляризации к знаменателю штрафует листья с малыми значениями гессиана (плоские области), что приводит к меньшим обновлениям. Эти значения \(w_k\) затем вносят вклад в предсказание модели для входного значения, попавшего в соответствующий лист. Итоговое предсказание представляет собой сумму базового предсказания и вкладов каждого дерева. Затем результат этой суммы преобразуется обратной функцией связи в зависимости от выбранной функции потерь (см. раздел Математическая формулировка).

Обратите внимание, что в исходной статье [XGBoost] вводится слагаемое \(\gamma\sum_k T_k\), штрафующее за число листьев (что делает его сглаженной версией max_leaf_nodes). Здесь оно не представлено, так как не реализовано в scikit-learn; в то же время \(\lambda\) штрафует за величину предсказаний отдельных деревьев до масштабирования с помощью скорости обучения; см. раздел Сжатие с помощью скорости обучения.

Обратите внимание: ранняя остановка включена по умолчанию, если число образцов превышает 10 000. Поведение ранней остановки контролируется параметрами early_stopping, scoring, validation_fraction, n_iter_no_change и tol. Раннюю остановку можно выполнять с помощью произвольной функции оценки или только на основе потерь при обучении либо валидации. Обратите внимание: по техническим причинам использование вызываемого объекта в качестве функции оценки значительно медленнее, чем использование функции потерь. По умолчанию ранняя остановка выполняется, если обучающая выборка содержит не менее 10 000 образцов, и для этого используются потери на валидационной выборке.

1.11.1.1.2. Поддержка пропущенных значений

HistGradientBoostingClassifier и HistGradientBoostingRegressor имеют встроенную поддержку пропущенных значений (NaN).

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

>>> from sklearn.ensemble import HistGradientBoostingClassifier
>>> import numpy as np

>>> X = np.array([0, 1, 2, np.nan]).reshape(-1, 1)
>>> y = [0, 0, 1, 1]

>>> gbdt = HistGradientBoostingClassifier(min_samples_leaf=1).fit(X, y)
>>> gbdt.predict(X)
array([0, 0, 1, 1])

Если закономерность пропусков помогает предсказывать целевое значение, разбиения можно выполнять по признаку наличия или отсутствия значения:

>>> X = np.array([0, np.nan, 1, 2, np.nan]).reshape(-1, 1)
>>> y = [0, 1, 0, 0, 1]
>>> gbdt = HistGradientBoostingClassifier(min_samples_leaf=1,
...                                       max_depth=2,
...                                       learning_rate=1,
...                                       max_iter=1).fit(X, y)
>>> gbdt.predict(X)
array([0, 1, 0, 0, 1])

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

Примеры

  • Признаки в деревьях градиентного бустинга на основе гистограмм

1.11.1.1.3. Поддержка весов образцов

HistGradientBoostingClassifier и HistGradientBoostingRegressor поддерживают веса образцов во время обучения.

Следующий простой пример показывает, что образцы с нулевым весом игнорируются:

>>> X = [[1, 0],
...      [1, 0],
...      [1, 0],
...      [0, 1]]
>>> y = [0, 0, 1, 0]
>>> # ignore the first 2 training samples by setting their weight to 0
>>> sample_weight = [0, 0, 1, 1]
>>> gb = HistGradientBoostingClassifier(min_samples_leaf=1)
>>> gb.fit(X, y, sample_weight=sample_weight)
HistGradientBoostingClassifier(...)
>>> gb.predict([[1, 0]])
array([1])
>>> gb.predict_proba([[1, 0]])[0, 1]
np.float64(0.999)

Как видите, [1, 0] уверенно классифицируется как 1, поскольку первые два образца игнорируются из-за назначенных им весов.

Подробности реализации: учет весов образцов сводится к умножению градиентов (и гессианов) на веса образцов. Обратите внимание, что на этапе разбиения на бины (в частности, при вычислении квантилей) веса не учитываются.

1.11.1.1.4. Поддержка категориальных признаков

HistGradientBoostingClassifier и HistGradientBoostingRegressor имеют встроенную поддержку категориальных признаков: они могут выполнять разбиения по неупорядоченным категориальным данным.

Для наборов данных с категориальными признаками часто лучше использовать встроенную поддержку категориальных данных, чем полагаться на унитарное кодирование (OneHotEncoder), поскольку для достижения эквивалентных разбиений унитарное кодирование требует большей глубины дерева. Кроме того, обычно лучше использовать встроенную поддержку категориальных данных, а не рассматривать категориальные признаки как непрерывные (порядковые), как это происходит при порядковом кодировании категориальных данных: категории являются номинальными величинами, для которых порядок не имеет значения.

Чтобы включить поддержку категориальных данных, параметру categorical_features можно передать булеву маску, указывающую, какие признаки являются категориальными. В следующем примере первый признак рассматривается как категориальный, а второй — как числовой:

>>> gbdt = HistGradientBoostingClassifier(categorical_features=[True, False])

Вместо этого можно передать список целых чисел с индексами категориальных признаков:

>>> gbdt = HistGradientBoostingClassifier(categorical_features=[0])

Если входные данные представлены в виде DataFrame, можно также передать список названий столбцов:

>>> gbdt = HistGradientBoostingClassifier(categorical_features=["site", "manufacturer"])

Наконец, при использовании DataFrame можно указать categorical_features="from_dtype"; в этом случае все столбцы с категориальным dtype будут рассматриваться как категориальные признаки.

Кардинальность каждого категориального признака должна быть меньше значения параметра max_bins. Пример использования градиентного бустинга на основе гистограмм с категориальными признаками см. в разделе Поддержка категориальных признаков в градиентном бустинге.

Если во время обучения присутствуют пропущенные значения, они будут рассматриваться как отдельная категория. Если во время обучения пропущенных значений нет, то при предсказании они направляются в дочерний узел с наибольшим числом образцов (как и для непрерывных признаков). Категории, не встречавшиеся во время обучения, при предсказании будут считаться пропущенными значениями.

Поиск разбиений для категориальных признаков

Стандартный способ рассмотрения категориальных разбиений в дереве — перебрать все \(2^{K - 1} - 1\) разбиения, где \(K\) — число категорий. При больших значениях \(K\) это быстро становится непрактичным. К счастью, поскольку деревья градиентного бустинга всегда являются деревьями регрессии (даже в задачах классификации), существует более быстрая стратегия, позволяющая получать эквивалентные разбиения. Сначала категории признака сортируются по дисперсии целевого значения для каждой категории k. После сортировки категорий можно рассматривать непрерывные разбиения, то есть считать категории упорядоченными непрерывными значениями (формальное доказательство см. у Fisher [Fisher1958]). В результате достаточно рассмотреть только \(K - 1\) разбиений вместо \(2^{K - 1} - 1\). Первоначальная сортировка имеет сложность \(\mathcal{O}(K \log(K))\), поэтому общая сложность составляет \(\mathcal{O}(K \log(K) + K)\span>, а не \(\mathcal{O}(2^K)\).

Примеры

  • Поддержка категориальных признаков в градиентном бустинге

1.11.1.1.5. Монотонные ограничения

В зависимости от решаемой задачи у вас могут быть априорные знания о том, что определенный признак в общем случае должен положительно (или отрицательно) влиять на целевое значение. Например, при прочих равных условиях более высокий кредитный рейтинг должен повышать вероятность одобрения кредита. Монотонные ограничения позволяют учитывать такие априорные знания в модели.

Для предиктора \(F\) с двумя признаками:

  • ограничение на монотонное возрастание имеет следующий вид:

    \[x_1 \leq x_1' \implies F(x_1, x_2) \leq F(x_1', x_2)\]
  • ограничение на монотонное убывание имеет следующий вид:

    \[x_1 \leq x_1' \implies F(x_1, x_2) \geq F(x_1', x_2)\]

Для каждого признака можно задать монотонное ограничение с помощью параметра monotonic_cst. Значение 0 означает отсутствие ограничений, а значения 1 и -1 указывают соответственно на ограничение монотонного возрастания и монотонного убывания:

>>> from sklearn.ensemble import HistGradientBoostingRegressor

... # monotonic increase, monotonic decrease, and no constraint on the 3 features
>>> gbdt = HistGradientBoostingRegressor(monotonic_cst=[1, -1, 0])

В задаче бинарной классификации наложение ограничения на монотонное возрастание (убывание) означает, что более высокие значения признака должны положительно (отрицательно) влиять на вероятность принадлежности образцов к положительному классу.

Однако монотонные ограничения лишь частично ограничивают влияние признаков на выход модели. Например, ограничения на монотонное возрастание и убывание нельзя использовать для выполнения следующего условия моделирования:

\[x_1 \leq x_1' \implies F(x_1, x_2) \leq F(x_1', x_2')\]

Кроме того, монотонные ограничения не поддерживаются для многоклассовой классификации.

Практическую реализацию монотонных ограничений в градиентном бустинге на основе гистограмм, в том числе описание того, как они могут улучшить обобщающую способность при наличии предметных знаний, см. в разделе Монотонные ограничения.

Примечание

Поскольку категории являются неупорядоченными величинами, задавать монотонные ограничения для категориальных признаков нельзя.

Примеры

  • Признаки в деревьях градиентного бустинга на основе гистограмм

1.11.1.1.6. Ограничения на взаимодействия

По умолчанию деревьям градиентного бустинга на основе гистограмм разрешено использовать любые признаки для разделения узла на дочерние узлы. Это создает так называемые взаимодействия между признаками, то есть использование разных признаков для разбиения на одной ветви. Иногда требуется ограничить возможные взаимодействия; см. [Mayer2022]. Это можно сделать с помощью параметра interaction_cst, задав индексы признаков, которым разрешено взаимодействовать. Например, если всего имеется 3 признака, interaction_cst=[{0}, {1}, {2}] запрещает все взаимодействия. Ограничения [{0, 1}, {1, 2}] задают две группы признаков, которым разрешено взаимодействовать. Признаки 0 и 1 могут взаимодействовать друг с другом, как и признаки 1 и 2. Однако взаимодействие признаков 0 и 2 запрещено. На следующем рисунке показано дерево и возможные разбиения в нем:

   1      <- Both constraint groups could be applied from now on
  / \
 1   2    <- Left split still fulfills both constraint groups.
/ \ / \      Right split at feature 2 has only group {1, 2} from now on.

LightGBM использует ту же логику для перекрывающихся групп.

Обратите внимание, что признаки, не перечисленные в interaction_cst, автоматически помещаются в отдельную группу взаимодействия. Если снова взять 3 признака, то [{0}] эквивалентно [{0}, {1, 2}].

Примеры

  • Графики частичной зависимости и индивидуальных условных ожиданий

Литература

[Mayer2022]

M. Mayer, S.C. Bourassa, M. Hoesli и D.F. Scognamiglio. 2022. Применение машинного обучения для оценки земельных участков и сооружений. Journal of Risk and Financial Management 15, № 5: 193

1.11.1.1.7. Низкоуровневый параллелизм

HistGradientBoostingClassifier и HistGradientBoostingRegressor используют OpenMP для распараллеливания с помощью Cython. Дополнительные сведения об управлении числом потоков см. в примечаниях о параллелизме.

Параллельно выполняются следующие этапы:

  • сопоставление образцов с действительными значениями и бинов с целочисленными значениями (поиск порогов бинов, однако, выполняется последовательно)
  • построение гистограмм распараллелено по признакам
  • поиск наилучшей точки разбиения в узле распараллелен по признакам
  • во время обучения сопоставление образцов с левыми и правыми дочерними узлами распараллелено по образцам
  • вычисление градиентов и гессианов распараллелено по образцам
  • предсказание распараллелено по образцам

1.11.1.1.8. Почему это быстрее

Узкое место процесса градиентного бустинга — построение деревьев решений. Для построения традиционного дерева решений (как в других реализациях GBDT: GradientBoostingClassifier и GradientBoostingRegressor) требуется сортировать образцы в каждом узле (для каждого признака). Сортировка нужна для эффективного вычисления потенциального выигрыша в точке разбиения. Поэтому сложность разбиения одного узла составляет \(\mathcal{O}(n_\text{features} \times n \log(n)), где \(n\) — число образцов в узле.

В отличие от них, HistGradientBoostingClassifier и HistGradientBoostingRegressor не требуют сортировки значений признаков, а вместо этого используют структуру данных, называемую гистограммой, в которой образцы упорядочены неявно. Построение гистограммы имеет сложность \(\mathcal{O}(n), поэтому сложность процедуры разбиения узла составляет \(\mathcal{O}(n_\text{features} \times n), что намного меньше предыдущей. Кроме того, вместо рассмотрения \(n\) точек разбиения мы рассматриваем только max_bins точек, что может быть значительно меньше.

Для построения гистограмм входные данные X необходимо разбить на бины со значениями типа integer. Эта процедура разбиения на бины требует сортировки значений признаков, но выполняется только один раз, в самом начале процесса бустинга (а не в каждом узле, как в GradientBoostingClassifier и GradientBoostingRegressor).

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

Наконец, многие части реализации HistGradientBoostingClassifier и HistGradientBoostingRegressor распараллелены.

Литература

[XGBoost] (1,2,3)

Tianqi Chen, Carlos Guestrin, «XGBoost: масштабируемая система бустинга деревьев»

[LightGBM]

Ke и др. «LightGBM: высокоэффективное дерево решений с градиентным бустингом»

[Fisher1958]

Fisher, W.D. (1958). «О группировке для достижения максимальной однородности». Journal of the American Statistical Association, 53, 789–798.

1.11.1.2. GradientBoostingClassifier и GradientBoostingRegressor

Использование и параметры GradientBoostingClassifier и GradientBoostingRegressor описаны ниже. Два наиболее важных параметра этих оценивателей — n_estimators и learning_rate.

Классификация

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

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]

>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
...     max_depth=1, random_state=0).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.913

Количество слабых моделей (то есть деревьев регрессии) задаётся параметром n_estimators; Размер каждого дерева можно контролировать, задавая глубину дерева с помощью max_depth или количество листовых узлов с помощью max_leaf_nodes. learning_rate — это гиперпараметр из диапазона (0.0, 1.0], который позволяет контролировать переобучение посредством сжатия.

Примечание

Для классификации более чем по 2 классам на каждой итерации требуется построить n_classes деревьев регрессии, поэтому общее количество построенных деревьев равно n_classes * n_estimators. Для наборов данных с большим количеством классов мы настоятельно рекомендуем использовать HistGradientBoostingClassifier вместо GradientBoostingClassifier.

Регрессия

GradientBoostingRegressor поддерживает несколько функций потерь для регрессии, которые можно задать с помощью аргумента loss; функция потерь по умолчанию для регрессии — квадратичная ошибка ('squared_error').

>>> import numpy as np
>>> from sklearn.metrics import mean_squared_error
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.ensemble import GradientBoostingRegressor

>>> X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
>>> X_train, X_test = X[:200], X[200:]
>>> y_train, y_test = y[:200], y[200:]
>>> est = GradientBoostingRegressor(
...     n_estimators=100, learning_rate=0.1, max_depth=1, random_state=0,
...     loss='squared_error'
... ).fit(X_train, y_train)
>>> mean_squared_error(y_test, est.predict(X_test))
5.00

На рисунке ниже показаны результаты применения GradientBoostingRegressor с методом наименьших квадратов и 500 базовыми моделями к набору данных о диабете (sklearn.datasets.load_diabetes). На графике отображена ошибка на обучающей и тестовой выборках на каждой итерации. Ошибка на обучающей выборке на каждой итерации хранится в атрибуте train_score_ модели градиентного бустинга. Ошибку на тестовой выборке на каждой итерации можно получить с помощью метода staged_predict, который возвращает генератор, выдающий прогнозы на каждом этапе. Такие графики можно использовать для определения оптимального количества деревьев (то есть n_estimators) с помощью ранней остановки.

../_images/sphx_glr_plot_gradient_boosting_regression_001.png

Примеры

  • Градиентный бустинг для регрессии
  • Оценки градиентного бустинга вне обучающей выборки

1.11.1.2.1. Добавление слабых моделей

И GradientBoostingRegressor, и GradientBoostingClassifier поддерживают warm_start=True, позволяющий добавлять оцениватели в уже обученную модель.

>>> import numpy as np
>>> from sklearn.metrics import mean_squared_error
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.ensemble import GradientBoostingRegressor

>>> X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
>>> X_train, X_test = X[:200], X[200:]
>>> y_train, y_test = y[:200], y[200:]
>>> est = GradientBoostingRegressor(
...     n_estimators=100, learning_rate=0.1, max_depth=1, random_state=0,
...     loss='squared_error'
... )
>>> est = est.fit(X_train, y_train)  # fit with 100 trees
>>> mean_squared_error(y_test, est.predict(X_test))
5.00
>>> _ = est.set_params(n_estimators=200, warm_start=True)  # set warm_start and increase num of trees
>>> _ = est.fit(X_train, y_train) # fit additional 100 trees to est
>>> mean_squared_error(y_test, est.predict(X_test))
3.84

1.11.1.2.2. Контроль размера дерева

Размер базовых деревьев регрессии определяет уровень взаимодействия переменных, который может учитывать модель градиентного бустинга. В общем случае дерево глубины h может учитывать взаимодействия порядка h. Существует два способа контролировать размер отдельных деревьев регрессии.

Если задать max_depth=h, будут построены полные бинарные деревья глубины h. Такие деревья будут иметь не более 2**h листовых узлов и 2**h - 1 узлов разбиения.

Также можно контролировать размер дерева, задав количество листовых узлов с помощью параметра max_leaf_nodes. В этом случае деревья будут строиться методом поиска по принципу «сначала лучший»: сначала расширяются узлы с наибольшим снижением неоднородности. Дерево с max_leaf_nodes=k имеет k - 1 узлов разбиения и, следовательно, может моделировать взаимодействия вплоть до порядка max_leaf_nodes - 1.

Мы обнаружили, что max_leaf_nodes=k даёт результаты, сопоставимые с max_depth=k-1, но обучается значительно быстрее, хотя ошибка на обучающей выборке немного выше. Параметр max_leaf_nodes соответствует переменной J в главе о градиентном бустинге в [Friedman2001] и связан с параметром interaction.depth в пакете gbm для R, где max_leaf_nodes == interaction.depth + 1.

1.11.1.2.3. Математическая формулировка

Сначала рассмотрим GBRT для регрессии, а затем подробно разберём случай классификации.

Регрессия

Регрессоры GBRT — это аддитивные модели, прогноз \(\hat{y}_i\) которых для заданного входа \(x_i\) имеет следующий вид:

\[\hat{y}_i = F_M(x_i) = \sum_{m=1}^{M} h_m(x_i)\]

где \(h_m\) — оцениватели, называемые слабыми моделями в контексте бустинга. Градиентный бустинг на деревьях использует деревья решений для регрессии фиксированного размера в качестве слабых моделей. Константа M соответствует параметру n_estimators.

Как и другие алгоритмы бустинга, GBRT строится жадным образом:

\[F_m(x) = F_{m-1}(x) + h_m(x),\]

где новое дерево \(h_m\) обучается для минимизации суммы потерь \(L_m\) с учётом предыдущего ансамбля \(F_{m-1}\):

\[h_m = \arg\min_{h} L_m = \arg\min_{h} \sum_{i=1}^{n} l(y_i, F_{m-1}(x_i) + h(x_i)),\]

где \(l(y_i, F(x_i))\) определяется параметром loss, который подробно описан в следующем разделе.

По умолчанию начальная модель \(F_{0}\) выбирается как константа, минимизирующая функцию потерь: для функции потерь на основе метода наименьших квадратов это среднее целевых значений. Начальную модель также можно задать с помощью аргумента init.

Используя разложение Тейлора первого порядка, значение \(l\) можно приближённо представить следующим образом:

\[l(y_i, F_{m-1}(x_i) + h_m(x_i)) \approx l(y_i, F_{m-1}(x_i)) + h_m(x_i) \left[ \frac{\partial l(y_i, F(x_i))}{\partial F(x_i)} \right]_{F=F_{m - 1}}.\]

Примечание

Кратко, разложение Тейлора первого порядка утверждает, что \(l(z) \approx l(a) + (z - a) \frac{\partial l}{\partial z}(a)\). Здесь \(z\) соответствует \(F_{m - 1}(x_i) + h_m(x_i)\), а \(a\) соответствует \(F_{m-1}(x_i)\)

Величина \(\left[ \frac{\partial l(y_i, F(x_i))}{\partial F(x_i)} \right]_{F=F_{m - 1}}\) — это производная функции потерь по её второму параметру, вычисленная в точке \(F_{m-1}(x)\). Её легко вычислить в замкнутой форме для любого заданного \(F_{m - 1}(x_i)\), поскольку функция потерь дифференцируема. Обозначим её через \(g_i\).

Отбросив постоянные слагаемые, получим:

\[h_m \approx \arg\min_{h} \sum_{i=1}^{n} h(x_i) g_i\]

Минимум достигается, если \(h(x_i)\) обучено предсказывать значение, пропорциональное отрицательному градиенту \(-g_i\). Следовательно, на каждой итерации оцениватель \(h_m\) обучается предсказывать отрицательные градиенты объектов. Градиенты обновляются на каждой итерации. Это можно рассматривать как своего рода градиентный спуск в функциональном пространстве.

Примечание

Для некоторых функций потерь, например 'absolute_error', где градиенты равны \(\pm 1\), значения, предсказанные обученным \(h_m\), недостаточно точны: дерево может выдавать только целые значения. Поэтому после обучения дерева значения в его листьях \(h_m\) изменяются так, чтобы минимизировать потери \(L_m\). Способ обновления зависит от функции потерь: для абсолютной ошибки значение листа заменяется медианой объектов в этом листе.

Классификация

Градиентный бустинг для классификации очень похож на случай регрессии. Однако сумма деревьев \(F_M(x_i) = \sum_m h_m(x_i)\) не соответствует прогнозу: она не может быть классом, поскольку деревья предсказывают непрерывные значения.

Преобразование значения \(F_M(x_i)\) в класс или вероятность зависит от функции потерь. Для логарифмической функции потерь вероятность принадлежности \(x_i\) к положительному классу моделируется как \(p(y_i = 1 | x_i) = \sigma(F_M(x_i))\), где \(\sigma\) — сигмоидная функция, или функция expit.

Для многоклассовой классификации на каждой из \(M\) итераций строятся K деревьев (для K классов). Вероятность того, что \(x_i\) принадлежит классу k, моделируется с помощью функции softmax от значений \(F_{M,k}(x_i)\).

Обратите внимание: даже при решении задачи классификации подоцениватель \(h_m\) остаётся регрессором, а не классификатором. Это связано с тем, что подоцениватели обучаются предсказывать (отрицательные) градиенты, которые всегда являются непрерывными величинами.

1.11.1.2.4. Функции потерь

Поддерживаются следующие функции потерь; их можно задать с помощью параметра loss:

Регрессия
  • Квадратичная ошибка ('squared_error'): естественный выбор для регрессии благодаря эффективным вычислениям. Начальная модель задаётся средним целевых значений.
  • Абсолютная ошибка ('absolute_error'): устойчивая функция потерь для регрессии. Начальная модель задаётся медианой целевых значений.
  • Функция потерь Хьюбера ('huber'): ещё одна устойчивая функция потерь, сочетающая метод наименьших квадратов и метод наименьших абсолютных отклонений; используйте alpha для настройки чувствительности к выбросам (подробнее см. [Friedman2001]).
  • Квантильная функция потерь ('quantile'): функция потерь для квантильной регрессии. Используйте 0 < alpha < 1, чтобы задать квантиль. Эту функцию потерь можно использовать для построения интервалов прогнозирования (см. Интервалы прогнозирования для регрессии с градиентным бустингом).
Классификация
  • Бинарная логарифмическая функция потерь ('log-loss'): отрицательная логарифмическая функция правдоподобия для биномиального распределения, используемая в бинарной классификации. Она позволяет оценивать вероятности. Начальная модель задаётся логарифмом отношения шансов.
  • Многоклассовая логарифмическая функция потерь ('log-loss'): отрицательная логарифмическая функция правдоподобия для мультиномиального распределения, используемая в многоклассовой классификации с n_classes взаимоисключающими классами. Она позволяет оценивать вероятности. Начальная модель задаётся априорной вероятностью каждого класса. На каждой итерации необходимо строить n_classes деревьев регрессии, что делает GBRT довольно неэффективным для наборов данных с большим количеством классов.
  • Экспоненциальная функция потерь ('exponential'): та же функция потерь, что и в AdaBoostClassifier. Менее устойчива к неправильно размеченным примерам, чем 'log-loss'; может использоваться только для бинарной классификации.

1.11.1.2.5. Сжатие с помощью скорости обучения

В работе [Friedman2001] предложена простая стратегия регуляризации, которая масштабирует вклад каждой слабой модели постоянным коэффициентом \(\nu\):

\[F_m(x) = F_{m-1}(x) + \nu h_m(x)\]

Параметр \(\nu\) также называют скоростью обучения, поскольку он масштабирует длину шага процедуры градиентного спуска; его можно задать параметром learning_rate.

Параметр learning_rate сильно взаимодействует с параметром n_estimators, задающим количество обучаемых слабых моделей. При меньших значениях learning_rate для сохранения постоянной ошибки на обучающей выборке требуется больше слабых моделей. Эмпирические данные показывают, что малые значения learning_rate способствуют снижению ошибки на тестовой выборке. В [HTF] рекомендуется задать небольшую постоянную скорость обучения (например, learning_rate <= 0.1) и выбрать достаточно большое значение n_estimators, чтобы можно было использовать раннюю остановку. Подробнее о взаимодействии learning_rate и n_estimators см. Ранняя остановка в градиентном бустинге и [R2007].

1.11.1.2.6. Подвыборка

В работе [Friedman2002] предложен стохастический градиентный бустинг, сочетающий градиентный бустинг с усреднением по бутстрэп-выборкам (бэггингом). На каждой итерации базовый классификатор обучается на доле subsample доступных обучающих данных. Подвыборка формируется без возвращения. Типичное значение subsample — 0.5.

На рисунке ниже показано влияние сжатия и подвыборки на качество подгонки модели. Хорошо видно, что сжатие эффективнее, чем отсутствие сжатия. Подвыборка в сочетании со сжатием может дополнительно повысить точность модели. Подвыборка без сжатия, напротив, даёт плохие результаты.

../_images/sphx_glr_plot_gradient_boosting_regularization_001.png

Ещё один способ уменьшить дисперсию — выполнять подвыборку признаков, аналогично случайному выбору при разбиениях в RandomForestClassifier. Количество признаков в подвыборке можно контролировать с помощью параметра max_features.

Примечание

Небольшое значение max_features может значительно сократить время выполнения.

Стохастический градиентный бустинг позволяет вычислять оценки тестового девианса вне обучающей выборки, измеряя улучшение девианса на примерах, не включённых в бутстрэп-выборку (то есть на примерах вне обучающей выборки). Улучшения хранятся в атрибуте oob_improvement_. oob_improvement_[i] содержит улучшение функции потерь на примерах вне обучающей выборки при добавлении i-го этапа к текущим прогнозам. Такие оценки можно использовать для выбора модели, например для определения оптимального количества итераций. Оценки вне обучающей выборки обычно очень пессимистичны, поэтому мы рекомендуем использовать вместо них кросс-валидацию и прибегать к оценкам вне обучающей выборки, только если кросс-валидация занимает слишком много времени.

Примеры

  • Регуляризация градиентного бустинга
  • Оценки градиентного бустинга вне обучающей выборки
  • Ошибки вне обучающей выборки для случайных лесов

1.11.1.2.7. Интерпретация с помощью важности признаков

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

Часто признаки вносят неодинаковый вклад в прогноз целевого отклика; во многих ситуациях большинство признаков фактически несущественны. При интерпретации модели обычно в первую очередь задаются вопросом: какие признаки важны и как они влияют на прогноз целевого отклика?

Отдельные деревья решений автоматически выполняют отбор признаков, выбирая подходящие точки разбиения. Эту информацию можно использовать для измерения важности каждого признака. Основная идея такова: чем чаще признак используется в точках разбиения дерева, тем он важнее. Это понятие важности можно распространить на ансамбли деревьев решений, просто усреднив важность признаков, основанную на неоднородности, для каждого дерева (подробнее см. Оценка важности признаков).

Оценки важности признаков обученной модели градиентного бустинга доступны через свойство feature_importances_:

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
...     max_depth=1, random_state=0).fit(X, y)
>>> clf.feature_importances_
array([0.107, 0.105, 0.113, 0.0987, 0.0947,
       0.107, 0.0916, 0.0972, 0.0958, 0.0906])

Обратите внимание, что данное вычисление важности признаков основано на энтропии и отличается от sklearn.inspection.permutation_importance, которое основано на перестановке признаков.

Примеры

  • Градиентный бустинг для регрессии

Литература

[Friedman2001] (1,2,3,4)

Friedman, J.H. (2001). Greedy function approximation: A gradient boosting machine. Annals of Statistics, 29, 1189-1232.

[Friedman2002]

Friedman, J.H. (2002). Stochastic gradient boosting.. Computational Statistics & Data Analysis, 38, 367-378.

[R2007]

G. Ridgeway (2006). Generalized Boosted Models: A guide to the gbm package

1.11.2. Случайные леса и другие ансамбли рандомизированных деревьев

Модуль sklearn.ensemble включает два алгоритма усреднения, основанных на рандомизированных деревьях решений: алгоритм RandomForest и метод Extra-Trees. Оба алгоритма представляют собой методы возмущения и комбинирования [B1998], специально разработанные для деревьев. Это означает, что разнообразный набор классификаторов создается путем внесения случайности в построение классификатора. Предсказание ансамбля вычисляется как усредненное предсказание отдельных классификаторов.

Как и другие классификаторы, классификаторы на основе лесов обучаются на двух массивах: разреженном или плотном массиве X формы (n_samples, n_features), содержащем обучающие образцы, и массиве Y формы (n_samples,), содержащем целевые значения (метки классов) обучающих образцов:

>>> from sklearn.ensemble import RandomForestClassifier
>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = RandomForestClassifier(n_estimators=10)
>>> clf = clf.fit(X, Y)

Как и деревья решений, леса деревьев также применимы к задачам с несколькими выходами (если Y — массив формы (n_samples, n_outputs)).

1.11.2.1. Случайные леса

В случайных лесах (см. классы RandomForestClassifier и RandomForestRegressor) каждое дерево ансамбля строится на выборке с возвращением (то есть на бутстрэп-выборке) из обучающего набора.

При построении каждого дерева в лесу рассматривается случайное подмножество признаков. Размер этого подмножества задается параметром max_features; оно может включать все входные признаки или случайное подмножество признаков (подробнее см. рекомендации по настройке параметров).

Цель этих двух источников случайности (бутстрэп-выборки образцов и случайный выбор признаков при каждом разбиении) — уменьшить дисперсию оценщика на основе леса. Действительно, отдельные деревья решений обычно обладают высокой дисперсией и склонны к переобучению. Внесение случайности в леса приводит к тому, что ошибки предсказания деревьев решений становятся в некоторой степени независимыми. При усреднении этих предсказаний некоторые ошибки могут взаимно компенсироваться. Случайные леса снижают дисперсию за счет объединения разнообразных деревьев, иногда ценой небольшого увеличения смещения. На практике снижение дисперсии часто бывает значительным, что позволяет получить более качественную модель в целом.

При выращивании каждого дерева в лесу «наилучшее» разбиение (то есть такое, которое соответствует передаче splitter="best" базовым деревьям решений) выбирается согласно критерию нечистоты. Подробнее см. математическую формулировку CART.

В отличие от исходной публикации [B2001], реализация scikit-learn объединяет классификаторы путем усреднения их вероятностных предсказаний, а не путем голосования каждого классификатора за один класс.

Конкурентной альтернативой случайным лесам являются модели градиентного бустинга на основе гистограмм (HGBT):

  • Построение деревьев: случайные леса обычно используют глубокие деревья (которые по отдельности переобучаются), что требует значительных вычислительных ресурсов, поскольку необходимо выполнять множество разбиений и оценивать кандидаты на разбиение. Модели бустинга строят неглубокие деревья (которые по отдельности недообучаются), обучение и предсказание с помощью которых выполняются быстрее.
  • Последовательный бустинг: в HGBT деревья решений строятся последовательно, причем каждое дерево обучается исправлять ошибки предыдущих. Это позволяет итеративно улучшать качество модели, используя сравнительно небольшое количество деревьев. В отличие от этого, случайные леса используют голосование большинства для предсказания результата, и для достижения такой же точности может потребоваться больше деревьев.
  • Эффективное разбиение на интервалы: HGBT использует эффективный алгоритм разбиения на интервалы, который позволяет работать с большими наборами данных с большим количеством признаков. Этот алгоритм может предварительно обработать данные, ускорив последующее построение деревьев (см. почему это быстрее). В отличие от этого, реализация случайных лесов в scikit-learn не использует разбиение на интервалы и выполняет точное разбиение, что может требовать значительных вычислительных затрат.

В целом вычислительная стоимость HGBT по сравнению со случайными лесами зависит от конкретных характеристик набора данных и задачи моделирования. Рекомендуется попробовать обе модели и сравнить их качество и вычислительную эффективность на конкретной задаче, чтобы определить, какая из них подходит лучше.

Примеры

  • Сравнение случайных лесов и моделей градиентного бустинга на основе гистограмм

1.11.2.2. Сверхрандомизированные деревья

В сверхрандомизированных деревьях (см. классы ExtraTreesClassifier и ExtraTreesRegressor) случайность используется еще активнее при вычислении разбиений. Как и в случайных лесах, используется случайное подмножество признаков-кандидатов, но вместо поиска наиболее разделяющих порогов для каждого признака-кандидата случайным образом выбираются пороги, а правилом разбиения становится лучший из этих случайно сгенерированных порогов. Обычно это позволяет еще немного снизить дисперсию модели ценой несколько большего увеличения смещения:

>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import make_blobs
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.tree import DecisionTreeClassifier

>>> X, y = make_blobs(n_samples=10000, n_features=10, centers=100,
...     random_state=0)

>>> clf = DecisionTreeClassifier(max_depth=None, min_samples_split=2,
...     random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
np.float64(0.98)

>>> clf = RandomForestClassifier(n_estimators=10, max_depth=None,
...     min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
np.float64(0.999)

>>> clf = ExtraTreesClassifier(n_estimators=10, max_depth=None,
...     min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean() > 0.999
np.True_
../_images/sphx_glr_plot_forest_iris_001.png

1.11.2.3. Параметры

Основные параметры, которые следует настраивать при использовании этих методов, — n_estimators и max_features. Первый — это количество деревьев в лесу. Чем оно больше, тем лучше, однако тем больше времени займет вычисление. Кроме того, следует учитывать, что после достижения критического количества деревьев качество результатов перестает существенно улучшаться. Второй параметр задает размер случайных подмножеств признаков, рассматриваемых при разбиении узла. Чем он меньше, тем сильнее снижается дисперсия, но тем больше увеличивается смещение. Эмпирически хорошие значения по умолчанию — max_features=1.0 или, что эквивалентно, max_features=None (всегда используются все признаки, а не случайное подмножество) для задач регрессии и max_features="sqrt" (используется случайное подмножество размера sqrt(n_features)) для задач классификации (где n_features — количество признаков в данных). Значение max_features=1.0 по умолчанию соответствует деревьям с бэггингом; увеличить случайность можно, задав меньшие значения (например, 0.3 — типичное значение по умолчанию в литературе). Хороших результатов часто удается добиться, если задать max_depth=None в сочетании с min_samples_split=2 (то есть полностью вырастить деревья). Однако имейте в виду, что эти значения обычно не являются оптимальными и могут привести к созданию моделей, потребляющих много оперативной памяти. Наилучшие значения параметров всегда следует выбирать с помощью кросс-валидации. Кроме того, следует учитывать, что в случайных лесах по умолчанию используются бутстрэп-выборки (bootstrap=True), тогда как стратегия по умолчанию для Extra-Trees — использование всего набора данных (bootstrap=False). При использовании бутстрэп-выборки ошибку обобщения можно оценить на оставшихся вне выборки образцах, или образцах out-of-bag. Для этого задайте oob_score=True.

Примечание

Размер модели с параметрами по умолчанию составляет \(O( M * N * log (N) )\), где \(M\) — количество деревьев, а \(N\) — количество образцов. Чтобы уменьшить размер модели, можно изменить следующие параметры: min_samples_split, max_leaf_nodes, max_depth и min_samples_leaf.

1.11.2.4. Параллельные вычисления

Наконец, этот модуль поддерживает параллельное построение деревьев и параллельное вычисление предсказаний с помощью параметра n_jobs. Если задано n_jobs=k, вычисления разбиваются на k задач, которые выполняются на k ядрах компьютера. Если задано n_jobs=-1, используются все доступные ядра компьютера. Обратите внимание, что из-за накладных расходов на межпроцессное взаимодействие ускорение может быть не линейным (то есть использование k задач, к сожалению, не сделает вычисления в k раз быстрее). Тем не менее значительного ускорения можно добиться при построении большого количества деревьев или если построение одного дерева занимает достаточно много времени (например, на больших наборах данных).

Примеры

  • Визуализация разделяющих поверхностей ансамблей деревьев на наборе данных ирисов
  • Восстановление лиц с помощью оценщиков с несколькими выходами

Ссылки

[B2001]
  1. Breiman, “Random Forests”, Machine Learning, 45(1), 5-32, 2001.
[B1998]
  1. Breiman, “Arcing Classifiers”, Annals of Statistics 1998.
  • P. Geurts, D. Ernst., and L. Wehenkel, “Extremely randomized trees”, Machine Learning, 63(1), 3-42, 2006.

1.11.2.5. Оценка важности признаков

Относительный ранг (то есть глубину) признака, используемого в качестве узла решения в дереве, можно применять для оценки относительной важности этого признака с точки зрения предсказуемости целевой переменной. Признаки, используемые в верхней части дерева, участвуют в принятии окончательного решения о предсказании для большей доли входных образцов. Поэтому ожидаемую долю образцов, в обработке которых они участвуют, можно использовать для оценки относительной важности признаков. В scikit-learn доля образцов, в обработке которых участвует признак, объединяется с уменьшением нечистоты в результате их разбиения, чтобы получить нормированную оценку предсказательной способности этого признака.

Усреднение оценок предсказательной способности по нескольким рандомизированным деревьям позволяет уменьшить дисперсию такой оценки и использовать ее для отбора признаков. Этот показатель называется средним уменьшением нечистоты (MDI). Подробнее о MDI и оценке важности признаков с помощью случайных лесов см. [L2014].

Предупреждение

Важность признаков на основе нечистоты, вычисленная для моделей на основе деревьев, имеет два недостатка, которые могут привести к неверным выводам. Во-первых, она вычисляется на основе статистики обучающего набора данных и поэтому не обязательно показывает, какие признаки наиболее важны для получения хороших предсказаний на отложенном наборе данных. Во-вторых, она отдает предпочтение признакам с высокой кардинальностью, то есть признакам с большим количеством уникальных значений. Важность признаков на основе перестановок — альтернатива важности признаков на основе нечистоты, лишенная этих недостатков. Сравнение этих двух методов оценки важности признаков рассматривается в примере Важность на основе перестановок и важность признаков случайного леса (MDI).

На практике эти оценки сохраняются в атрибуте feature_importances_ обученной модели. Это массив формы (n_features,) с положительными значениями, сумма которых равна 1.0. Чем выше значение, тем важнее вклад соответствующего признака в функцию предсказания.

Примеры

  • Важность признаков в лесу деревьев

Ссылки

[L2014]

G. Louppe, “Understanding Random Forests: From Theory to Practice”, докторская диссертация, U. of Liege, 2014.

1.11.2.6. Встраивание с помощью полностью случайных деревьев

RandomTreesEmbedding реализует неконтролируемое преобразование данных. Используя лес полностью случайных деревьев, RandomTreesEmbedding кодирует данные с помощью индексов листьев, в которые попадает точка данных. Затем этот индекс кодируется по принципу «один из K», что приводит к разреженному двоичному кодированию высокой размерности. Такое кодирование можно вычислить очень эффективно, а затем использовать в качестве основы для других задач обучения. На размер и разреженность кодирования можно влиять, задавая количество деревьев и максимальную глубину каждого дерева. Для каждого дерева ансамбля кодирование содержит одну единицу. Размер кодирования не превышает n_estimators * 2 ** max_depth — максимального количества листьев в лесу.

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

Примеры

  • Хеширующее преобразование признаков с помощью полностью случайных деревьев
  • Обучение многообразий на рукописных цифрах: локально-линейное встраивание, Isomap… — сравнение методов нелинейного снижения размерности на рукописных цифрах.
  • Преобразование признаков с помощью ансамблей деревьев — сравнение контролируемых и неконтролируемых преобразований признаков на основе деревьев.

См. также

Методы обучения многообразий также могут быть полезны для получения нелинейных представлений пространства признаков; кроме того, эти подходы также ориентированы на снижение размерности.

1.11.2.7. Добавление деревьев

Оценщики RandomForest, Extra-Trees и RandomTreesEmbedding поддерживают параметр warm_start=True, позволяющий добавлять деревья в уже обученную модель.

>>> from sklearn.datasets import make_classification
>>> from sklearn.ensemble import RandomForestClassifier

>>> X, y = make_classification(n_samples=100, random_state=1)
>>> clf = RandomForestClassifier(n_estimators=10)
>>> clf = clf.fit(X, y)  # fit with 10 trees
>>> len(clf.estimators_)
10
>>> # set warm_start and increase num of estimators
>>> _ = clf.set_params(n_estimators=20, warm_start=True)
>>> _ = clf.fit(X, y) # fit additional 10 trees
>>> len(clf.estimators_)
20

Если также задан random_state, внутреннее состояние генератора случайных чисел сохраняется между вызовами fit. Это означает, что однократное обучение модели с n оценщиками эквивалентно итеративному построению модели с помощью нескольких вызовов fit, при котором итоговое количество оценщиков равно n.

>>> clf = RandomForestClassifier(n_estimators=20)  # set `n_estimators` to 10 + 10
>>> _ = clf.fit(X, y)  # fit `estimators_` will be the same as `clf` above

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

1.11.3. Метаоценщик бэггинга

В ансамблевых алгоритмах методы бэггинга образуют класс алгоритмов, которые строят несколько экземпляров оценщика типа «черный ящик» на случайных подмножествах исходного обучающего набора, а затем агрегируют отдельные предсказания для получения итогового предсказания. Эти методы позволяют снизить дисперсию базового оценщика (например, дерева решений), внося случайность в процедуру его построения, а затем формируя из него ансамбль. Во многих случаях методы бэггинга представляют собой очень простой способ улучшить результаты по сравнению с отдельной моделью без необходимости адаптировать лежащий в ее основе алгоритм. Поскольку они позволяют уменьшить переобучение, методы бэггинга лучше всего работают с сильными и сложными моделями (например, полностью выращенными деревьями решений), в отличие от методов бустинга, которые обычно лучше работают со слабыми моделями (например, неглубокими деревьями решений).

Существует множество разновидностей методов бэггинга, которые в основном отличаются способом формирования случайных подмножеств обучающего набора:

  • Если случайные подмножества набора данных формируются как случайные подмножества образцов, такой алгоритм называется Pasting [B1999].
  • Если образцы выбираются с возвращением, метод называется Bagging [B1996].
  • Если случайные подмножества набора данных формируются как случайные подмножества признаков, метод называется Random Subspaces [H1998].
  • Наконец, если базовые оценщики строятся на подмножествах как образцов, так и признаков, метод называется Random Patches [LG2012].

В scikit-learn методы бэггинга представлены в виде универсального метаоценщика BaggingClassifier (соответственно, BaggingRegressor), которому передаются выбранный пользователем оценщик и параметры, задающие стратегию формирования случайных подмножеств. В частности, max_samples и max_features задают размер подмножеств (по количеству образцов и признаков), а bootstrap и bootstrap_features определяют, выбираются ли образцы и признаки с возвращением или без него. Если используется подмножество доступных образцов, точность обобщения можно оценить на образцах out-of-bag, задав oob_score=True. В качестве примера приведенный ниже фрагмент кода показывает, как создать ансамбль бэггинга из оценщиков KNeighborsClassifier, каждый из которых обучается на случайных подмножествах, содержащих 50% образцов и 50% признаков.

>>> from sklearn.ensemble import BaggingClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> bagging = BaggingClassifier(KNeighborsClassifier(),
...                             max_samples=0.5, max_features=0.5)

Примеры

  • Отдельный оценщик и бэггинг: разложение смещения и дисперсии

Ссылки

[B1999]

L. Breiman, “Pasting small votes for classification in large databases and on-line”, Machine Learning, 36(1), 85-103, 1999.

[B1996]

L. Breiman, “Bagging predictors”, Machine Learning, 24(2), 123-140, 1996.

[H1998]

T. Ho, “The random subspace method for constructing decision forests”, Pattern Analysis and Machine Intelligence, 20(8), 832-844, 1998.

[LG2012]

G. Louppe and P. Geurts, “Ensembles on Random Patches”, Machine Learning and Knowledge Discovery in Databases, 346-361, 2012.

1.11.4. Классификатор голосования

Идея VotingClassifier заключается в объединении концептуально разных классификаторов машинного обучения и использовании голосования большинства или усредненных предсказанных вероятностей (мягкого голосования) для предсказания меток классов. Такой классификатор может быть полезен для набора моделей с одинаково хорошим качеством, чтобы сбалансировать их индивидуальные недостатки.

1.11.4.1. Метки классов большинства (голосование большинством/жесткое голосование)

При голосовании большинством предсказанной меткой класса для конкретного образца становится метка класса, соответствующая большинству (моде) меток, предсказанных отдельными классификаторами.

Например, если предсказания для заданного образца следующие:

  • классификатор 1 -> класс 1
  • классификатор 2 -> класс 1
  • классификатор 3 -> класс 2

VotingClassifier (с voting='hard') отнесет образец к «классу 1» на основании большинства голосов.

При равенстве голосов VotingClassifier выберет класс в соответствии с сортировкой по возрастанию. Например, в следующей ситуации:

  • классификатор 1 -> класс 2
  • классификатор 2 -> класс 1

образцу будет присвоена метка класса 1.

1.11.4.2. Использование

В следующем примере показано, как обучить классификатор с правилом большинства:

>>> from sklearn import datasets
>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.naive_bayes import GaussianNB
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import VotingClassifier

>>> iris = datasets.load_iris()
>>> X, y = iris.data[:, 1:3], iris.target

>>> clf1 = LogisticRegression(random_state=1)
>>> clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
>>> clf3 = GaussianNB()

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='hard')

>>> for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random Forest', 'naive Bayes', 'Ensemble']):
...     scores = cross_val_score(clf, X, y, scoring='accuracy', cv=5)
...     print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
Accuracy: 0.95 (+/- 0.04) [Logistic Regression]
Accuracy: 0.94 (+/- 0.04) [Random Forest]
Accuracy: 0.91 (+/- 0.04) [naive Bayes]
Accuracy: 0.95 (+/- 0.04) [Ensemble]

1.11.4.3. Взвешенное среднее вероятностей (мягкое голосование)

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

Каждому классификатору можно назначить определенный вес с помощью параметра weights. Если веса заданы, предсказанные вероятности классов для каждого классификатора собираются, умножаются на вес классификатора и усредняются. Затем окончательная метка класса определяется как метка класса с наибольшей средней вероятностью.

Для простоты предположим, что у нас есть 3 классификатора и задача классификации на 3 класса, причем всем классификаторам назначены одинаковые веса: w1=1, w2=1, w3=1.

Тогда взвешенное среднее вероятностей для образца вычисляется следующим образом:

классификатор

класс 1

класс 2

класс 3

классификатор 1

w1 * 0.2

w1 * 0.5

w1 * 0.3

классификатор 2

w2 * 0.6

w2 * 0.3

w2 * 0.1

классификатор 3

w3 * 0.3

w3 * 0.4

w3 * 0.3

взвешенное среднее

0.37

0.4

0.23

В данном случае предсказанная метка класса — 2, поскольку у нее наибольшая средняя предсказанная вероятность. Демонстрацию того, как получить предсказанную метку класса из взвешенного среднего предсказанных вероятностей, см. в примере Визуализация вероятностных предсказаний VotingClassifier.

На следующем рисунке показано, как могут изменяться области решений при обучении мягкого VotingClassifier с весами для трех линейных моделей:

../_images/sphx_glr_plot_voting_decision_regions_002.png

1.11.4.4. Использование

Чтобы предсказывать метки классов на основе предсказанных вероятностей классов, оценщики scikit-learn в VotingClassifier должны поддерживать метод predict_proba:

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft'
... )

При желании отдельным классификаторам можно задать веса:

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft', weights=[2,5,1]
... )
Использование VotingClassifier с GridSearchCV

VotingClassifier также можно использовать вместе с GridSearchCV для настройки гиперпараметров отдельных оценщиков:

>>> from sklearn.model_selection import GridSearchCV
>>> clf1 = LogisticRegression(random_state=1)
>>> clf2 = RandomForestClassifier(random_state=1)
>>> clf3 = GaussianNB()
>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft'
... )

>>> params = {'lr__C': [1.0, 100.0], 'rf__n_estimators': [20, 200]}

>>> grid = GridSearchCV(estimator=eclf, param_grid=params, cv=5)
>>> grid = grid.fit(iris.data, iris.target)

1.11.5. Регрессор голосования

Идея, лежащая в основе VotingRegressor, заключается в объединении концептуально различных регрессоров машинного обучения и возвращении среднего значения предсказаний. Такой регрессор может быть полезен для набора моделей с одинаково хорошими результатами, чтобы компенсировать их индивидуальные слабые стороны.

1.11.5.1. Использование

В следующем примере показано, как обучить VotingRegressor:

>>> from sklearn.datasets import load_diabetes
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> from sklearn.ensemble import RandomForestRegressor
>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.ensemble import VotingRegressor

>>> # Loading some example data
>>> X, y = load_diabetes(return_X_y=True)

>>> # Training classifiers
>>> reg1 = GradientBoostingRegressor(random_state=1)
>>> reg2 = RandomForestRegressor(random_state=1)
>>> reg3 = LinearRegression()
>>> ereg = VotingRegressor(estimators=[('gb', reg1), ('rf', reg2), ('lr', reg3)])
>>> ereg = ereg.fit(X, y)
../_images/sphx_glr_plot_voting_regressor_001.png

Примеры

  • Визуализация отдельных прогнозов регрессии и прогнозов голосования

1.11.6. Стекинг (обобщение с помощью стекинга)

Стекинг — это метод объединения оценивателей для уменьшения их смещения [W1992] [HTF]. Точнее, предсказания каждого отдельного оценивателя объединяются и используются в качестве входных данных для итогового оценивателя, вычисляющего предсказание. Этот итоговый оцениватель обучается с помощью перекрёстной проверки.

StackingClassifier и StackingRegressor реализуют такие стратегии, применимые к задачам классификации и регрессии.

Параметр estimators соответствует списку оценивателей, которые параллельно объединяются на входных данных. Его следует передать в виде списка имён и оценивателей:

>>> from sklearn.linear_model import RidgeCV, LassoCV
>>> from sklearn.neighbors import KNeighborsRegressor
>>> estimators = [('ridge', RidgeCV()),
...               ('lasso', LassoCV(random_state=42)),
...               ('knr', KNeighborsRegressor(n_neighbors=20,
...                                           metric='euclidean'))]

final_estimator будет использовать предсказания estimators в качестве входных данных. При использовании StackingClassifier или StackingRegressor соответственно он должен быть классификатором или регрессором:

>>> from sklearn.ensemble import GradientBoostingRegressor
>>> from sklearn.ensemble import StackingRegressor
>>> final_estimator = GradientBoostingRegressor(
...     n_estimators=25, subsample=0.5, min_samples_leaf=25, max_features=1,
...     random_state=42)
>>> reg = StackingRegressor(
...     estimators=estimators,
...     final_estimator=final_estimator)

Чтобы обучить estimators и final_estimator, необходимо вызвать метод fit на обучающих данных:

>>> from sklearn.datasets import load_diabetes
>>> X, y = load_diabetes(return_X_y=True)
>>> from sklearn.model_selection import train_test_split
>>> X_train, X_test, y_train, y_test = train_test_split(X, y,
...                                                     random_state=42)
>>> reg.fit(X_train, y_train)
StackingRegressor(...)

Во время обучения estimators настраиваются на всём наборе обучающих данных X_train. Они будут использоваться при вызове predict или predict_proba. Чтобы обеспечить обобщение и избежать переобучения, final_estimator обучается на вневыборочных данных с помощью внутреннего вызова sklearn.model_selection.cross_val_predict.

Для StackingClassifier обратите внимание: выходные данные estimators задаются параметром stack_method, который вызывается каждым оценивателем. Этот параметр может быть строкой с именем метода оценивателя или 'auto', который автоматически выберет доступный метод в зависимости от его наличия, проверяя варианты в порядке предпочтения: predict_proba, decision_function и predict.

StackingRegressor и StackingClassifier можно использовать как любой другой регрессор или классификатор; они предоставляют методы predict, predict_proba или decision_function, например:

>>> y_pred = reg.predict(X_test)
>>> from sklearn.metrics import r2_score
>>> print('R2 score: {:.2f}'.format(r2_score(y_test, y_pred)))
R2 score: 0.53

Обратите внимание, что выходные данные стекинговых estimators также можно получить с помощью метода transform:

>>> reg.transform(X_test[:5])
array([[142, 138, 146],
       [179, 182, 151],
       [139, 132, 158],
       [286, 292, 225],
       [126, 124, 164]])

На практике предсказатель со стекингом работает не хуже лучшего предсказателя базового уровня и иногда даже превосходит его, объединяя различные сильные стороны этих предсказателей. Однако обучение предсказателя со стекингом требует значительных вычислительных затрат.

Примечание

Для StackingClassifier при использовании stack_method_='predict_proba' первый столбец отбрасывается, если решается задача бинарной классификации. Дело в том, что два столбца вероятностей, предсказанные каждым оценивателем, полностью коллинеарны.

Примечание

Можно создать несколько уровней стекинга, присвоив final_estimator объекту StackingClassifier или StackingRegressor:

>>> final_layer_rfr = RandomForestRegressor(
...     n_estimators=10, max_features=1, max_leaf_nodes=5,random_state=42)
>>> final_layer_gbr = GradientBoostingRegressor(
...     n_estimators=10, max_features=1, max_leaf_nodes=5,random_state=42)
>>> final_layer = StackingRegressor(
...     estimators=[('rf', final_layer_rfr),
...                 ('gbrt', final_layer_gbr)],
...     final_estimator=RidgeCV()
...     )
>>> multi_layer_regressor = StackingRegressor(
...     estimators=[('ridge', RidgeCV()),
...                 ('lasso', LassoCV(random_state=42)),
...                 ('knr', KNeighborsRegressor(n_neighbors=20,
...                                             metric='euclidean'))],
...     final_estimator=final_layer
... )
>>> multi_layer_regressor.fit(X_train, y_train)
StackingRegressor(...)
>>> print('R2 score: {:.2f}'
...       .format(multi_layer_regressor.score(X_test, y_test)))
R2 score: 0.53

Примеры

  • Объединение предсказателей с помощью стекинга

Литература

[W1992]

Wolpert, David H. «Стекинг (обобщение с помощью стекинга)». Neural networks 5.2 (1992): 241–259.

1.11.7. AdaBoost

Модуль sklearn.ensemble включает популярный алгоритм бустинга AdaBoost, представленный Фройндом и Шапире в 1995 году [FS1995].

Основной принцип AdaBoost заключается в последовательном обучении слабых обучающихся алгоритмов (то есть моделей, лишь немного превосходящих случайное угадывание, например небольших деревьев решений) на многократно изменяемых версиях данных. Затем предсказания всех алгоритмов объединяются с помощью взвешенного голосования большинством (или суммирования), чтобы получить итоговое предсказание. Изменение данных на каждой так называемой итерации бустинга состоит в применении весов \(w_1\), \(w_2\), …, \(w_N\) к каждому обучающему образцу. Изначально все веса равны \(w_i = 1/N\), поэтому на первом шаге слабый обучающий алгоритм просто обучается на исходных данных. На каждой следующей итерации веса отдельных образцов изменяются, а алгоритм обучения повторно применяется к данным с новыми весами. На данном шаге веса обучающих примеров, которые бустинговая модель, полученная на предыдущем шаге, предсказала неверно, увеличиваются, а веса правильно предсказанных примеров уменьшаются. По мере выполнения итераций примеры, предсказание которых затруднено, получают всё больший вес. Таким образом, каждый следующий слабый обучающий алгоритм вынужден сосредоточиться на примерах, пропущенных предыдущими алгоритмами в последовательности [HTF].

../_images/sphx_glr_plot_adaboost_multiclass_001.png

AdaBoost можно использовать как для задач классификации, так и для задач регрессии:

  • Для многоклассовой классификации AdaBoostClassifier реализует AdaBoost.SAMME [ZZRH2009].
  • Для регрессии AdaBoostRegressor реализует AdaBoost.R2 [D1997].

1.11.7.1. Использование

В следующем примере показано, как обучить классификатор AdaBoost со 100 слабыми обучающими алгоритмами:

>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import load_iris
>>> from sklearn.ensemble import AdaBoostClassifier

>>> X, y = load_iris(return_X_y=True)
>>> clf = AdaBoostClassifier(n_estimators=100)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
np.float64(0.95)

Количество слабых обучающих алгоритмов задаётся параметром n_estimators. Параметр learning_rate определяет вклад слабых обучающих алгоритмов в итоговое объединение. По умолчанию слабые обучающие алгоритмы — это пни решений. Другие слабые обучающие алгоритмы можно задать с помощью параметра estimator. Основные параметры, которые следует настраивать для получения хороших результатов, — это n_estimators и сложность базовых оценивателей (например, их глубина max_depth или минимальное необходимое количество образцов для рассмотрения разделения min_samples_split).

Примеры

  • Многоклассовые деревья решений с AdaBoost демонстрирует эффективность AdaBoost в задаче многоклассовой классификации.
  • Двухклассовая классификация с AdaBoost показывает границу решений и значения функции принятия решения для нелинейно разделимой задачи двухклассовой классификации с использованием AdaBoost-SAMME.
  • Регрессия на основе дерева решений с AdaBoost демонстрирует регрессию с алгоритмом AdaBoost.R2.

Литература

[FS1995]

Y. Freund и R. Schapire. «Теоретико-решенческое обобщение онлайн-обучения и применение к бустингу», 1997.

[ZZRH2009]
  1. Zhu, H. Zou, S. Rosset, T. Hastie. «Многоклассовый AdaBoost», 2009.
[D1997]
  1. Drucker. «Улучшение регрессоров с помощью методов бустинга», 1997.
[HTF] (1,2,3)

T. Hastie, R. Tibshirani и J. Friedman. «Основы статистического обучения. 2-е изд.», Springer, 2009.

© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/modules/ensemble.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API