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

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

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

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

1.11.1. Градиентный бустинг деревьев решений

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

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

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

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

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

Эти быстрые модели сначала объединяют входные выборки X в целочисленные ячейки (обычно 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’, которая менее чувствительна к выбросам, и ‘poisson’, которая хорошо подходит для моделирования подсчетов и частот. Для классификации единственным вариантом является ‘log_loss’. Для бинарной классификации используется бинарный log loss, также известный как биномиальная дисперсия или бинарная кросс-энтропия. Для n_classes >= 3 используется многоклассовая функция логарифмических потерь (log loss), альтернативные названия которой - мультиномиальная дисперсия и категориальная кросс-энтропия. Соответствующая версия потерь выбирается на основе y, переданного в fit.

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

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

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

Обратите внимание, что ранняя остановка включена по умолчанию, если количество выборок превышает 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 поддерживают выборочные веса во время fit.

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

>>> 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]
0.99...

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

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

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

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

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

Чтобы включить категориальную поддержку, в параметр 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. Пример использования градиентного бустинга на основе гистограммы для категориальных признаков см. Categorical Feature Support in Gradient Boosting.

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

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

... # монотонное увеличение, монотонное убывание и отсутствие ограничений на 3х признаках
>>> 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      <- Обе группы ограничений могут применяться с этого момента.
  / \
 1   2    <- Левое разделение по-прежнему соответствует обеим группам ограничений.
/ \ / \      Правое разделение на объекте 2 теперь имеет только группу {1, 2}.

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

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

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

HistGradientBoostingClassifier и HistGradientBoostingRegressor используют OpenMP для распараллеливания через Cython. Более подробную информацию о том, как контролировать количество потоков, можно найти в наших примечаниях по Параллелизм.

Следующие части алгоритма могут быть паралелизуются:

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

  • построение гистограмм распараллелено по признакам

  • поиск лучшей точки разделения в узле распараллеливается по признакам.

  • во время обучения соотвествие выборок с левыми и правыми дочерними элементами распараллеливается по выборкам.

  • Вычисления градиента и гессиана распараллеливаются по выборкам.

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

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 необходимо разделить на целочисленные ячейки. Эта процедура объединения требует сортировки значений признаков, но она происходит только один раз в самом начале процесса бустинга (а не на каждом узле, как в GradientBoostingClassifier и GradientBoostingRegressor).

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

1.11.1.2. GradientBoostingClassifier и GradientBoostingRegressor

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

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

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

>>> 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], который управляет переобучением через сокращение (shrinkage) .

Примечание

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

1.11.1.2.2. Регрессия

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.3. Обучение дополнительных простых моделей

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

>>> _ = est.set_params(n_estimators=200, warm_start=True)  # set warm_start and new nr 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.4. Управление размером дерева

Размер базы обучающихся дерева регрессии определяет уровень взаимодействия переменных, которые могут быть учтены моделью градиентного бустинга. В общем, дерево глубины 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 в языке R пакета gbm, где max_leaf_nodes == interaction.depth + 1.

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

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

1.11.1.2.5.1. Регрессия

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

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

где \(h_m\) - это модель, называемая простой моделью (weak learners) в контексте бустинга. В градиентном бустинге дерева использует регрессоры дерева решений фиксированного размера в качестве простых моделей. Константа 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\). Обновление зависит от потерь: при абсолютной потере ошибки значение листа обновляется до медианы выборок в этом листе.

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

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

Отображение значения \(F_M(x_i)\) в класс или вероятность зависит от потерь. Для логарифмических потерь (log-loss) вероятность того, что \(x_i\) принадлежит положительному классу, моделируется как \(p(y_i = 1 | x_i) = \sigma(F_M(x_i))\) где \(\sigma\) - сигмовидная функция или функция выхода.

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

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

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

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

  • Регрессия

    • Квадратная ошибка ('squared_error'): естественный выбор регрессии из-за ее превосходных вычислительных свойств. Исходная модель задается средним значением целевых значений.

    • Абсолютная ошибка ('absolute_error'): устойчивая функция потерь для регрессии. Исходная модель представляет собой медиану целевых значений.

    • Хубер ('huber'): еще одна устойчивая функция потерь, сочетающая в себе метод наименьших квадратов и наименьшее абсолютное отклонение; используйте alpha для управления чувствительностью к выбросам (более подробную информацию см. в [Friedman2001]).

    • Квантиль ('quantile'): функция потерь для квантильной регрессии. Используйте 0 < alpha < 1, ​​чтобы указать квантиль. Эту функцию потерь можно использовать для создания интервалов прогнозирования (см. Prediction Intervals for Gradient Boosting Regression).

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

    • Бинарный логарифмическая функция потерь ('log-loss'): Бинарный функция потерь логарифма правдоподобия с отрицательным логарифмом для двоичной классификации. Она обеспечивает оценки вероятности. Исходная модель определяется логарифмом отношения шансов.

    • Логарифмическая функция потерь нескольких классов ('log-loss'): полиномиальная отрицательная логарифмическая функция потери правдоподобия для многоклассовой классификации с взаимоисключающими классами n_classes. Она обеспечивает оценки вероятности. Исходная модель задается априорной вероятностью каждого класса. На каждой итерации необходимо строить деревья регрессии n_classes, что делает GBRT довольно неэффективным для наборов данных с большим количеством классов.

    • Экспоненциальная потеря ('exponential'): та же функция потерь, что и AdaBoostClassifier. Менее устойчив к неправильно помеченным примерам, чем 'log-loss'; может использоваться только для бинарной классификации.

1.11.1.2.7. Сокращение из-за скорости обучения

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

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

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

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

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

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

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

../_images/sphx_glr_plot_gradient_boosting_regularization_001.png

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

Примечание

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

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

1.11.1.2.9. Интерпретация на основе важности признаков

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

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

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

Доступ к оценкам важности признаков, обучаемой модели градиентного бустинга, можно получить через свойство 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.10..., 0.10..., 0.11..., ...

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

1.11.2. Случайные леса (Random Forest) и другие случайные ансамбли деревьев

Модуль sklearn.ensemble включает в себя два алгоритма усреднения, основанных на рандомизированных деревьях решений: алгоритм RandomForest и метод Extra-Trees. Оба алгоритма представляют собой методы возмущения и объединения (perturb-and-combine) [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. Случайные леса (Random Forests)

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

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

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

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

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

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

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

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

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

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()
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()
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
True
../_images/sphx_glr_plot_forest_iris_001.png

1.11.2.3. Параметры

Основные параметры, которые необходимо настроить при использовании этих методов, являются n_estimators и max_features. 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), тогда как стратегия по умолчанию для дополнительных деревьев заключается в использовании всего набора данных (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 раз быстрее). Однако значительного ускорения все же можно достичь при построении большого количества деревьев или когда построение одного дерева требует достаточного количества времени (например, для больших наборов данных).

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

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

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

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

Значимость признаков на основе примесей, рассчитанная на основе древовидных моделей, страдает двумя недостатками, которые могут привести к ошибочным выводам. Сначала они рассчитываются на основе статистики, полученной из набора обучающих данных, и поэтому не обязательно сообщают нам о том, какие признаки наиболее важны для получения хороших прогнозов на отложенном наборе данных. Во-вторых, они отдают предпочтение признакам с высокой мощностью, то есть признакам со многими уникальными значениями. Вычисление важности признаков с помощью перестановки - это альтернатива важности признаков на основе примесей, которая не страдает этими недостатками. Эти два метода определения важности функции рассматриваются в: Permutation Importance vs Random Forest Feature Importance (MDI).

В следующем примере показано представление с цветовой кодировкой относительной важности каждого отдельного пикселя для задачи распознавания лиц с использованием модели ExtraTreesClassifier.

../_images/sphx_glr_plot_forest_importances_faces_001.png

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

1.11.2.6. Ембединги (Embedding) совершенно случайных деревьев

RandomTreesEmbedding реализует неконтролируемое преобразование данных. Используя лес полностью случайных деревьев, RandomTreesEmbedding кодирует данные по индексам листьев, в которых находится точка данных. Затем этот индекс кодируется методом “один из K”, что приводит к многомерному, разреженному двоичному кодированию (так называемый Ембединги - Embedding). Это кодирование можно очень эффективно вычислить, а затем использовать в качестве основы для других задач обучения. На размер и разреженность кода можно влиять, выбирая количество деревьев и максимальную глубину каждого дерева. Для каждого дерева в ансамбле кодировка содержит одну запись из одного. Размер кодирования не более n_estimators * 2 ** max_depth, максимальное количество листьев в лесу.

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

См. также

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

1.11.3. Бэггинг метамодель (Bagging meta-estimator)

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

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

  • Когда случайные подмножества набора данных формируются как случайные подмножества выборок, этот алгоритм называется вставкой (Pasting) [B1999].

  • Когда образцы отбираются с заменой, этот метод известен как беггинг (Bagging) [B1996].

  • Когда случайные подмножества набора данных формируются как случайные подмножества признаков, этот метод известен как “Случайные подпространства” (Random Subspaces) [H1998].

  • Наконец, когда базовые модели строятся на подмножествах как выборок, так и признаков, этот метод известен как “Случайные патчи” (Random Patches) [LG2012].

В scikit-learn методы беггинга предлагаются в виде метамодели BagingClassifier (соответственно BagingRegressor), принимающего в качестве входных данных указанный пользователем модели вместе с параметрами, определяющими стратегию формирования случайных подмножеств. В частности, 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)

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

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

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

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

Например, если прогноз для данной выборки

  • classifier 1 -> class 1

  • classifier 2 -> class 1

  • classifier 3 -> class 2

VotingClassifiervoting='hard') будет классифицировать выборку как класс 1 на основании метки класса большинства.

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

  • classifier 1 -> class 2

  • classifier 2 -> class 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. Средневзвешенные вероятности (мягкое голосование)

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

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

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

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

classifier

class 1

class 2

class 3

classifier 1

w1 * 0.2

w1 * 0.5

w1 * 0.3

classifier 2

w2 * 0.6

w2 * 0.3

w2 * 0.1

classifier 3

w3 * 0.3

w3 * 0.4

w3 * 0.3

weighted average

0.37

0.4

0.23

Здесь прогнозируемая метка класса равна 2, поскольку она имеет наибольшую среднюю вероятность.

Следующий пример иллюстрирует, как могут изменяться области принятия решений, когда используется Мягкое голосование VotingClassifier на основе линейного метода опорных векторов (svm), дерева решений и классификатора K-ближайших соседей:

>>> from sklearn import datasets
>>> from sklearn.tree import DecisionTreeClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> from sklearn.svm import SVC
>>> from itertools import product
>>> from sklearn.ensemble import VotingClassifier

>>> # Loading some example data
>>> iris = datasets.load_iris()
>>> X = iris.data[:, [0, 2]]
>>> y = iris.target

>>> # Training classifiers
>>> clf1 = DecisionTreeClassifier(max_depth=4)
>>> clf2 = KNeighborsClassifier(n_neighbors=7)
>>> clf3 = SVC(kernel='rbf', probability=True)
>>> eclf = VotingClassifier(estimators=[('dt', clf1), ('knn', clf2), ('svc', clf3)],
...                         voting='soft', weights=[2, 1, 2])

>>> clf1 = clf1.fit(X, y)
>>> clf2 = clf2.fit(X, y)
>>> clf3 = clf3.fit(X, y)
>>> eclf = eclf.fit(X, y)
../_images/sphx_glr_plot_voting_decision_regions_001.png

1.11.4.4. Использование 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.4.5. Использование

Чтобы предсказать метки классов на основе предсказанных вероятностей классов (в 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]
... )

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. Стекинг (Stacked generalization - Многоуровневое обобщение)

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

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

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 можно использовать как для задач классификации, так и для регрессии:

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, algorithm="SAMME",)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.9...

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