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

Угадайте, сколько желейных бобов в этой банке?

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

Ансамбли в машинном обучении

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

Затем разбиваем данные на обучающую и тестовую части:

А теперь давайте напишем функцию для обучения и оценки классификаторов:

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

Древо решений

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

from sklearn.tree import DecisionTreeClassifier
# call Decision Tree
predictor(DecisionTreeClassifier(random_state=1))

# DecisionTreeClassifier results:
# Accuracy: 78.0%
# [[200  50]
#  [ 60 190]]
# Processed in  0.0157 seconds

Из данных Матрицы путаницы Дерево ошиблось 50 раз при предсказании класса 0 и 60 раз при предсказании класса 1. Перейдем к ансамблям.

Ансамбль мешков

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

from sklearn.ensemble import BaggingClassifier
# call Bagging Trees
predictor(BaggingClassifier(random_state=1))

# BaggingClassifier results:
# Accuracy: 87.8%
# [[225  25]
#  [ 36 214]]
# Processed in  0.1033 seconds

Результат почти на 10% выше. 25 ошибок для класса 0 и 36 для класса 1. Также стоит обратить внимание на то, что обучение заняло почти в 10 раз больше времени.

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

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

from sklearn.ensemble import RandomForestClassifier
# call Random Forest
predictor(RandomForestClassifier(random_state=1))

# RandomForestClassifier results:
# Accuracy: 91.2%
# [[234  16]
#  [ 28 222]]
# Processed in  0.2108 seconds

Да. 16 ошибок для класса 0 и 28 для класса 1.

Дополнительные деревья

В Extremely Randomized Trees случайность идет еще дальше. Как и в случае случайных лесов, используется случайное подмножество признаков, но вместо того, чтобы находить наиболее характерные пороги для каждого признака-кандидата, пороги выбираются случайным образом, и в качестве правила ветвления выбирается лучший из этих случайно сгенерированных порогов. Этот метод разделяет узлы, выбирая точки среза совершенно случайным образом.
Кроме того, алгоритм использует весь обучающий набор (а не загрузочную реплику) для выращивания деревьев.
Еще лучше?

from sklearn.ensemble import ExtraTreesClassifier
# call Extra Trees
predictor(ExtraTreesClassifier(random_state=1))

# ExtraTreesClassifier results:
# Accuracy: 93.0%
# [[238  12]
#  [ 23 227]]
# Processed in  0.1247 seconds

И да. 12 ошибок для класса 0 и 23 ошибки для класса 1. Можно ли придумать что-то лучше?

Адаптивное повышение (AdaBoost)

В отличие от Бэгинга, где несколько базовых обучаемых обучаются независимо друг от друга, бустинг включает в себя обучающие модели последовательно, так что следующая модель улучшает производительность предыдущей.
В Адаптивном бустинге это достигается путем присвоения веса каждому обучающему примеру. . На каждой итерации AdaBoost увеличивает вес примеров, в которых последний базовый ученик допустил ошибки, и уменьшает вес правильно предсказанных примеров. В результате новый базовый учащийся, который тренируется в следующей итерации, будет больше фокусироваться на трудных примерах из обучающих данных.
Звучит круто, но действительно ли это работает?

from sklearn.ensemble import AdaBoostClassifier
# call Adaptive Boosting
predictor(AdaBoostClassifier(random_state=1))

# AdaBoostClassifier results:
# Accuracy: 85.2%
# [[220  30]
#  [ 44 206]]
# Processed in  0.1048 seconds

Лучше, чем одиночное дерево, но хуже, чем подходы Бэгинга. 30 ошибок для класса 0 и 44 для класса 1. Есть что-то лучше?

Повышение градиента

В Gradient Boosting каждая модель предсказывает ошибки предыдущей, а предсказания моделей в ансамбле суммируются.
Основное отличие от AdaBoost заключается в том, как эти два алгоритма определяют слабые стороны слабых учеников. В то время как модель AdaBoost идентифицирует недостатки, используя точки данных с большим весом, Gradient Boosting делает то же самое, используя градиенты в функции потерь. Функция потерь — это мера того, насколько хорошо коэффициенты модели соответствуют базовым данным.
Эта процедура фактически соответствует алгоритму численной оптимизации, называемому градиентным спуском, который и дал название этому ансамблевому методу. Алгоритм можно прочитать здесь:



Давайте посмотрим, насколько лучше этот подход:

from sklearn.ensemble import GradientBoostingClassifier
# call Gradient Boosting
predictor(GradientBoostingClassifier(random_state=1))

# GradientBoostingClassifier results:
# Accuracy: 91.4%
# [[230  20]
#  [ 23 227]]
# Processed in  0.2346 seconds

Намного лучше. 20 ошибок для класса 0 и 23 для класса 1. Можно ли сделать этот метод еще лучше?

Экстремальное повышение градиента (XGBoost)

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

from xgboost import XGBClassifier
# call Extreme Gradient Boosting
predictor(XGBClassifier(random_state=1))

# XGBClassifier results:
# Accuracy: 92.2%
# [[235  15]
#  [ 24 226]]
# Processed in  1.4683 seconds

Даже лучше. 15 ошибок для класса 0 и 24 для класса 1.

Повышение градиента на основе гистограммы

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

from sklearn.ensemble import HistGradientBoostingClassifier
# call Histogram-Based Gradient Boosting
predictor(HistGradientBoostingClassifier(random_state=1))

# HistGradientBoostingClassifier results:
# Accuracy: 92.4%
# [[235  15]
#  [ 23 227]]
# Processed in  0.3195 seconds

Лучше. 15 ошибок для класса 0 и 23 для класса 1.

Промежуточный итог

Давайте очень утрированно разделим ансамбли на 2 типа, как показано на изображении выше, чтобы понять, что бустинг немного потерял. Это происходит не всегда и многое зависит от данных и от того, как эти данные были подготовлены (для простоты мы этого не делали и вообще данные, которые у нас есть, синтетические).
Результаты, которые мы получили — общие явление, т.е. отсюда мы можем понять, что ансамбль почти всегда будет лучше, чем отдельное дерево и что чем сложнее ансамбль, тем точнее будет результат. Так бывает не всегда, но часто.
Пришло время перейти к следующему типу ансамблей. Ансамбли ансамблей. Мы выберем все модели, показавшие точность более 90%. Их 5:

estimators = [('rf', RandomForestClassifier(random_state=1)),
              ('et', ExtraTreesClassifier(random_state=1)),
              ('gb', GradientBoostingClassifier(random_state=1)),
              ('xgb', XGBClassifier(random_state=1)),
              ('hgb', HistGradientBoostingClassifier(learning_rate=1))]

Стек оценок с итоговым классификатором (Stacking)

Это создание новой модели машинного обучения, которая учится комбинировать прогнозы нескольких других моделей.
Чтобы обучить базовый составной ансамбль, сначала необходимо обучить несколько различных моделей машинного обучения. Затем обучается другая модель, которая предсказывает значение целевого атрибута на основе значений, предсказанных моделями, обученными на предыдущем шаге.
При решении задачи классификации в качестве конечной модели обычно используется Логистическая регрессия. , а линейная регрессия часто используется для числовых целей. Узнайте больше о логистической регрессии здесь:



На самом деле стековые ансамбли могут быть более сложными и содержать больше слоев.
А теперь давайте выясним, может ли ансамбль ансамблей дать результат выше:

from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
# call Stacked generalization
predictor(StackingClassifier(estimators=estimators, final_estimator=LogisticRegression()))

# StackingClassifier results:
# Accuracy: 92.6%
# [[239  11]
#  [ 26 224]]
# Processed in  2.8881 seconds

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

Жесткий классификатор голосования

Суть в том, чтобы объединить концептуально разные классификаторы машинного обучения и использовать большинство голосов для прогнозирования меток классов. Это жесткое голосование включает в себя выбор прогноза, набравшего наибольшее количество голосов.
Может ли этот подход быть лучше, чем Stacking? Давай выясним!

from sklearn.ensemble import VotingClassifier
# call Soft Majority Rule classifier
predictor(VotingClassifier(estimators=estimators, voting='hard'))

# VotingClassifier results:
# Accuracy: 92.6%
# [[238  12]
#  [ 25 225]]
# Processed in  0.5794 seconds

Ошибок № 12 для класса 0 и 25 для класса 1.

Средневзвешенные вероятности (классификатор мягкого голосования)

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

from sklearn.ensemble import VotingClassifier
# call Soft Majority Rule classifier
predictor(VotingClassifier(estimators=estimators, voting='soft'))

# VotingClassifier results:
# Accuracy: 93.2%
# [[239  11]
#  [ 23 227]]
# Processed in  0.5797 seconds

И да, наконец получилось опередить ExtraTreesClassifier. 11 ошибок для класса 0 и 23 для класса 1.

Общий

Вы сами все видели, Soft Voting победил, но с крайне небольшим отрывом, а значит нельзя сказать, что он 100% лидер. Однако можно точно сказать, что ансамбль всегда будет эффективнее одной модели, главное правильно все настроить.
Обращаю внимание, что вся сегодняшняя музыка была сыграна с помощи деревьев, но это не значит, что вы ограничиваетесь только ими. Используйте любые классификаторы или регрессоры, которые вам нравятся. Деревья — не всегда лучшее решение для данного типа данных, а ансамбли разных моделей — всегда.
Полная версия кода:



Если хотите что-то попроще, то вам сюда: