1.11. Ансамбли: Градиентный бустинг, случайные леса, бэггинг, голосование, стекинг
Методы ансамблей объединяют предсказания нескольких базовых оценщиков, построенных с использованием заданного алгоритма обучения, для повышения обобщающей способности/устойчивости по сравнению с одним оценщиком.
Два очень известных примера методов ансамблей — это градиентно-усиленные деревья и случайные леса.
В более общем случае модели ансамблей могут быть применены к любому базовому обучающему элементу помимо деревьев, в методах усреднения, таких как методы бэггинга, стекинг моделей или голосование, или в бустинге, как AdaBoost.
1.11.1. Градиентно-усиленные деревья
Градиентный бустинг деревьев или Градиентно-усиленные деревья решений (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’, менее чувствительна к выбросам, чем среднеквадратическая ошибка;
- ‘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]):
Подробности о 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. Можно остановить процесс раннее, используя произвольный scorer, или просто значение потерь обучения или проверки. Обратите внимание, что по техническим причинам использование вызываемого объекта в качестве scorer значительно медленнее, чем использование значения потерь. По умолчанию раннее прекращение выполняется, если в обучающей выборке есть как минимум 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] 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. Пример использования основанного на гистограмме градиентного бустинга для категориальных признаков см. в Поддержка категориальных признаков в градиентном бустинге.
Если во время обучения есть пропущенные значения, пропущенные значения будут обрабатываться как соответствующая категория. Если во время обучения пропущенных значений нет, то во время предсказания пропущенные значения будут сопоставляться с дочерним узлом, имеющим наибольшее количество образцов (как и для непрерывных признаков). При предсказании категории, которые не были видны во время подгонки, будут обрабатываться как пропущенные значения.
Поиск разбиений с категориальными признаками
Канонический способ рассмотрения категориальных разбиений в дереве — это рассмотрение всех \(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 ... # monotonic increase, monotonic decrease, and no constraint on the 3 features >>> gbdt = HistGradientBoostingRegressor(monotonic_cst=[1, -1, 0])
В контексте бинарной классификации наложение ограничения на монотонное возрастание (убывание) означает, что более высокие значения признака должны оказывать положительное (отрицательное) влияние на вероятность того, что образцы будут принадлежать положительному классу.
Тем не менее, монотонные ограничения лишь в незначительной степени ограничивают влияние признаков на выходные данные. Например, ограничения на монотонное возрастание и убывание не могут быть использованы для обеспечения следующего ограничения моделирования:
Кроме того, монотонные ограничения не поддерживаются для многоклассовой классификации.
Примечание
Поскольку категории являются неупорядоченными величинами, невозможно применить монотонные ограничения к категориальным признакам.
Примеры
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}].
Примеры
Ссылки
M. Mayer, S.C. Bourassa, M. Hoesli, and D.F. Scognamiglio. 2022. Machine Learning Applications to Land and Structure Valuation. Journal of Risk and Financial Management 15, no. 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 необходимо разбить на целочисленные бины. Эта процедура разбиения требует сортировки значений признаков, но она выполняется только один раз в самом начале процесса бустинга (не в каждом узле, как в GradientBoostingClassifier и GradientBoostingRegressor).
Наконец, многие части реализации HistGradientBoostingClassifier и HistGradientBoostingRegressor распараллелены.
Ссылки
Fisher, W.D. (1958). “On Grouping for Maximum Homogeneity” 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) с помощью ранней остановки.
Примеры
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\) имеет следующий вид:
где \(h_m\) — это оценки, называемые слабыми обучающимися в контексте бустинга. Градиентное усиление деревьев использует регрессоры решающих деревьев фиксированного размера в качестве слабых обучающихся. Постоянная M соответствует параметру n_estimators.
Аналогично другим алгоритмам бустинга, GBRT строится жадным способом:
где новое добавленное дерево \(h_m\) подгоняется для минимизации суммы потерь \(L_m\) с учетом предыдущего ансамбля \(F_{m-1}\):
где \(l(y_i, F(x_i))\) определяется параметром loss, подробности которого приведены в следующем разделе.
По умолчанию начальная модель \(F_{0}\) выбирается как константа, минимизирующая потери: для потери наименьших квадратов это среднее эмпирическое значение целевых значений. Начальную модель также можно указать с помощью аргумента init.
Используя приближение первого порядка Тейлора, значение \(l\) можно приблизить следующим образом:
Примечание
Вкратце, приближение первого порядка Тейлора гласит, что \(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(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\) — сигмоидная или эквипитальная функция.
Для многоклассовой классификации на каждой из \(M\) итераций строятся K деревьев (для K классов). Вероятность того, что \(x_i\) принадлежит классу k, моделируется как софтмакс значений \(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\):
Параметр \(\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] предложил стохастический градиентный бустинг, который сочетает градиентный бустинг со средним по бутстрепу (bagging). На каждой итерации базовый классификатор обучается на части subsample доступных данных обучения. Подвыборка выбирается без возвращения. Типичное значение subsample равно 0,5.
На рисунке ниже показано влияние уменьшения шага и подвыборки на адекватность модели. Мы можем ясно увидеть, что уменьшение шага превосходит отсутствие уменьшения шага. Подвыборка с уменьшением шага может ещё больше повысить точность модели. Подвыборка без уменьшения шага, с другой стороны, показывает плохие результаты.
Другой стратегией для уменьшения дисперсии является подвыборка признаков, аналогичная случайным разделениям в RandomForestClassifier. Количество подвыбранных признаков можно контролировать с помощью параметра max_features.
Примечание
Использование малого значения max_features может значительно уменьшить время выполнения.
Стохастический градиентный бустинг позволяет вычислить оценки вне выборки (out-of-bag) тестового отклонения, вычислив улучшение отклонения на примерах, не включенных в образец бутстрепа (т. е. примерах вне выборки). Улучшения хранятся в атрибуте 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.10..., 0.10..., 0.11..., ...
Обратите внимание, что это вычисление важности признаков основано на энтропии и отличается от sklearn.inspection.permutation_importance, которое основано на перестановке признаков.
Примеры
Ссылки
Friedman, J.H. (2001). Жадный приближенный метод функций: машина градиентного бустинга. Журнал «Анализ статистических данных», 29, 1189-1232.
Friedman, J.H. (2002). Стохастический градиентный бустинг.. Вычислительная статистика и анализ данных, 38, 367-378.
G. Ridgeway (2006). Обобщенные модели бустинга: руководство к пакету gbm
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. (См. руководство по настройке параметров для получения дополнительной информации.)
Цель этих двух источников случайности состоит в уменьшении дисперсии оценщика леса. Действительно, отдельные деревья решений, как правило, демонстрируют высокую дисперсию и склонны к переобучению. Вводимая случайность в лесах приводит к деревьям решений с несколько декоррелированными ошибками предсказания. Путем усреднения этих предсказаний некоторые ошибки могут взаимно компенсироваться. Случайные леса достигают снижения дисперсии путем объединения разнородных деревьев, иногда ценой небольшого увеличения смещения. На практике уменьшение дисперсии часто является значительным, что приводит к лучшей модели в целом.
В отличие от первоначальной публикации [B2001], реализация scikit-learn объединяет классификаторы путем усреднения вероятностного предсказания, вместо того, чтобы позволять каждому классификатору голосовать за один класс.
Альтернативой случайным лесам являются модели Градиентного бустинга на основе гистограмм (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
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), в то время как по умолчанию в экстремально случайных деревьях используется весь набор данных (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 раз быстрее). Однако существенное ускорение всё же может быть достигнуто при построении большого количества деревьев или когда построение одного дерева требует значительного времени (например, на больших наборах данных).
Примеры
- Постройте поверхности решений ансамблей деревьев на наборе данных ирис
- Завершение лица с помощью многовыходных оценщиков
Ссылки
- Breiman, «Случайные леса», Machine Learning, 45(1), 5-32, 2001.
- Breiman, «Arcing Classifiers», Annals of Statistics 1998.
- P. Geurts, D. Ernst., and L. Wehenkel, «Экстремально случайные деревья», Machine Learning, 63(1), 3-42, 2006.
1.11.2.5. Оценка важности признаков
Относительный ранг (т.е. глубина) признака, используемого в качестве узла принятия решения в дереве, может быть использован для оценки относительной важности этого признака по отношению к предсказуемости целевой переменной. Признаки, используемые в верхней части дерева, вносят вклад в окончательное решение о предсказании для большей части входных выборок. Таким образом, долю выборок, к которым они относятся, можно использовать в качестве оценки относительной важности признаков. В scikit-learn доля выборок, в которую вносит вклад признак, комбинируется со снижением неопределенности при разделении, чтобы создать нормализованную оценку предсказательной способности этого признака.
Среднее значение оценок предсказательной способности по нескольким случайным деревьям позволяет снизить дисперсию такой оценки и использовать её для выбора признаков. Это известно как среднее снижение неопределенности или MDI. Обратитесь к [L2014] для получения дополнительной информации о MDI и оценке важности признаков с помощью случайных лесов.
Предупреждение
Важность признаков, основанные на неопределенности, вычисленные на основе моделей на основе деревьев, страдают двумя недостатками, которые могут привести к ошибочным выводам. Во-первых, они вычисляются на основе статистических данных, полученных из обучающего набора данных, и поэтому не обязательно указывают, какие признаки наиболее важны для создания хороших прогнозов на независимом наборе данных. Во-вторых, они предпочитают признаки с высоким количеством значений, то есть признаки с множеством уникальных значений. Перестановки важности признаков — это альтернатива важности признаков, основанной на неопределённости, которая не страдает этими недостатками. Эти два метода получения важности признаков изучены в: Сравнение важности признаков по перестановкам и важности признаков случайного леса (MDI).
На практике эти оценки хранятся в качестве атрибута с именем feature_importances_ на обученной модели. Это массив с формой (n_features,), значения которого положительны и суммируются до 1,0. Чем выше значение, тем больше вклад соответствующего признака в функцию прогнозирования.
Примеры
Ссылки
G. Louppe, “Understanding Random Forests: From Theory to Practice”, Диссертация PhD, У. of Liege, 2014.
1.11.2.6. Встраивание совершенно случайных деревьев
RandomTreesEmbedding реализует без учителя преобразование данных. Используя лес полностью случайных деревьев, RandomTreesEmbedding кодирует данные по индексам листьев, в которые попадает точка данных. Этот индекс затем кодируется способом «один из K», что приводит к высокоразмерному разреженному двоичному кодированию. Это кодирование может быть вычислено очень эффективно и может затем быть использовано в качестве основы для других задач обучения. Размер и разреженность кода могут быть скорректированы путем выбора количества деревьев и максимальной глубины каждого дерева. Для каждого дерева в ансамбле кодирование содержит одну запись единицы. Размер кодирования не превышает n_estimators * 2
** max_depth, максимальное количество листьев в лесу.
Поскольку соседние точки данных с большей вероятностью находятся в одном листе дерева, преобразование выполняет непараметрическую оценку плотности.
Примеры
- Преобразование признаков с помощью хэширования с помощью совершенно случайных деревьев
- Обучение по многообразиям на рукописных цифрах: локально-линейное вложение, изокарта... сравнивает методы нелинейного уменьшения размерности на рукописных цифрах.
- Преобразования признаков с помощью ансамблей деревьев сравнивает контролируемые и неконтролируемые преобразования признаков на основе деревьев.
См. также
Методы обучения по многообразиям также могут быть полезны для получения нелинейных представлений пространства признаков, при этом эти подходы также ориентированы на уменьшение размерности.
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. Метод усреднения по выборкам (Bagging)
В алгоритмах ансамбля методы bagging образуют класс алгоритмов, которые строят несколько экземпляров оценивающей функции с «черным ящиком» на случайных подвыборках исходного набора данных для обучения, а затем агрегируют их индивидуальные предсказания для формирования окончательного предсказания. Эти методы используются для уменьшения дисперсии базовой оценивающей функции (например, дерева решений), путем введения случайности в процесс ее построения и создания ансамбля. Во многих случаях методы bagging представляют собой очень простой способ улучшения по сравнению с одной моделью, без необходимости адаптации базового алгоритма. Поскольку они обеспечивают способ уменьшения переобучения, методы bagging работают лучше всего с сильными и сложными моделями (например, полностью развитыми деревьями решений), в отличие от методов бустинга, которые обычно работают лучше всего со слабыми моделями (например, неглубокими деревьями решений).
Методы bagging существуют в различных вариантах, но в основном различаются способом извлечения случайных подвыборок набора данных для обучения:
- Когда случайные подвыборки данных извлекаются как случайные подвыборки из набора элементов данных, этот алгоритм известен как Pasting [B1999].
- Когда элементы данных извлекаются с возвращением, этот метод известен как Bagging [B1996].
- Когда случайные подвыборки данных извлекаются как случайные подвыборки из набора признаков, этот метод известен как Случайные подпространства [H1998].
- Наконец, когда базовые оценивающие функции строятся на подвыборках как элементов данных, так и признаков, этот метод известен как Случайные патчи [LG2012].
В scikit-learn методы bagging предлагаются как единый BaggingClassifier мета-оценивающий алгоритм (соответственно BaggingRegressor), принимающий на вход указанную пользователем оценивающую функцию вместе с параметрами, определяющими стратегию извлечения случайных подвыборок. В частности, max_samples и max_features контролируют размер подвыборок (в терминах элементов данных и признаков), а bootstrap и bootstrap_features контролируют извлекаются ли элементы данных и признаки с возвращением или без. При использовании подвыборки из доступных элементов данных точность обобщения можно оценить с помощью элементов данных «вне выборки» (out-of-bag), установив oob_score=True. В качестве примера, фрагмент кода ниже иллюстрирует, как создать ансамбль bagging из KNeighborsClassifier оценивающих функций, каждая из которых построена на случайных подвыборках 50% элементов данных и 50% признаков.
>>> from sklearn.ensemble import BaggingClassifier >>> from sklearn.neighbors import KNeighborsClassifier >>> bagging = BaggingClassifier(KNeighborsClassifier(), ... max_samples=0.5, max_features=0.5)
Примеры
Ссылки
L. Breiman, “Pasting small votes for classification in large databases and on-line”, Machine Learning, 36(1), 85-103, 1999.
L. Breiman, “Bagging predictors”, Machine Learning, 24(2), 123-140, 1996.
T. Ho, “The random subspace method for constructing decision forests”, Pattern Analysis and Machine Intelligence, 20(8), 832-844, 1998.
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. Взвешенное среднее вероятностей (мягкое голосование)
В отличие от голосования большинством (жёсткого голосования), мягкое голосование возвращает метку класса как argmax от суммы предсказанных вероятностей.
Конкретные веса могут быть назначены каждой оценивающей функции через параметр 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 на основе линейной машины опорных векторов, дерева решений и классификатора 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)
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)
Примеры
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
Список литературы
Уолперт, Дэвид Х. «Стек обобщения». Нейронные сети 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].
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() 0.9...
Количество слабых обучаемых контролируется параметром n_estimators. Параметр learning_rate контролирует вклад слабых обучаемых в конечное объединение. По умолчанию, слабые обучаемые — это отрезки решения. Различные слабые обучаемые могут быть указаны через параметр estimator. Основные параметры для настройки, чтобы получить хорошие результаты, — это n_estimators и сложность базовых оценок (например, его глубина max_depth или минимальное необходимое количество образцов для рассмотрения разбиения min_samples_split).
Примеры
- Деревья решений AdaBoost для нескольких классов показывает производительность AdaBoost в задаче многоклассовой классификации.
- AdaBoost для двух классов показывает границу решений и значения функции решений для задачи с двумя классами, нелинейно разделимыми, с использованием AdaBoost-SAMME.
- Регрессия с деревьями решений с помощью AdaBoost демонстрирует регрессию с помощью алгоритма AdaBoost.R2.
Ссылки
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/modules/ensemble.html