Перейти к основному содержимому

Простая агрегация в ансамблях

При борьбе с переобучением (overfitting) базовых моделей f1(x),...fM(x)f_1(\mathbf{x}),...f_M(\mathbf{x}) используются простые агрегирующие функции G()G(\cdot). Рассмотрим основные типы таких агрегаций для задач регрессии и классификации.

Регрессия

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

y^(x)=1Mm=1Mfm(x)\widehat{y}(\mathbf{x})=\frac{1}{M}\sum_{m=1}^{M}f_{m}(\mathbf{x})

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

Другим и гораздо более часто используемым вариантом усреднения является взвешеннное среднее:

y^(x)=m=1Mwmfm(x)m=1Mwm\widehat{y}(\mathbf{x})=\frac{\sum_{m=1}^{M}w_{m}f_{m}(\mathbf{x})}{\sum_{m=1}^{M}w_{m}}

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

Усложнение взвешенного усреднения

При взвешенном усреднении веса могут быть не фиксированными константами, а функциями, зависящими от вектора признаков:

y^(x)=m=1Mwm(x)fm(x)m=1Mwm(x)\widehat{y}(\mathbf{x})=\frac{\sum_{m=1}^{M}w_{m}(\mathbf{x})\cdot f_{m}(\mathbf{x})}{\sum_{m=1}^{M}w_{m}(\mathbf{x})}

Например, веса могут считаться как SoftMax преобразование от линейных функций от признаков. В этом случае разные модели будут более предпочтительными в разных участках признакового пространства. Этот подход называется смесь экспертов (mixture of experts).

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

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

Классификаторы выдают вероятности классов

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

Вероятность класса cc в этом случае будет средним по предсказанным вероятностям этого класса для всех классификаторов:

pc(x)=1Mm=1Mpcm(x),c=1,2,...C.p_{c}(\mathbf{x})=\frac{1}{M}\sum_{m=1}^{M}p_{c}^{m}(\mathbf{x}), \quad c=1,2,...C.

Аналогично регрессии, равномерное усреднение можно заменить взвешенным.

Классификаторы выдают метки классов

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

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

Бинарная классификация

Когда классов всего два, то можно предсказывать положительный класс, когда этот класс предсказывают

  • все базовые классификаторы (правило AND),

  • хотя бы один из классификаторов (правило OR),

  • по крайней мере K классификаторов (правило K-out-of-N).

Последнее правило обобщает стратегии AND и OR при K=N и K=1 соответственно. Правило OR используется при обнаружении аномалий отдельными классификаторами: если хотя бы один базовый классификатор увидел что-то необычное в объекте, то он считается аномалией.

Классификаторы выдают рейтинги

Как мы знаем, каждый классификатор внутри себя рассчитывает рейтинги классов при построении прогноза. Соответственно, можно извлекать не окончательные метки, а вектора рейтингов классов g1(x),...gM(x)RC\mathbf{g}^1(\mathbf{x}),...\mathbf{g}^M(\mathbf{x})\in\mathbb{R}^C для соответствующих базовых классификаторов f1(x),...fM(x)f_1(\mathbf{x}),...f_M(\mathbf{x}), после чего их усреднять:

g=1Mm=1MgmRC,\mathbf{g}=\frac{1}{M}\sum_{m=1}^{M}\mathbf{g}^m \in \mathbb{R}^C,

получая вектор рейтингов для ансамбля:

g=[g1,...gC]T.\mathbf{g}=[g_1,...g_C]^T.

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

y^(x)=argmaxcgc(x)\hat{y}(\mathbf{x})=\arg\max_c g_c(\mathbf{x})
Ограничения подхода

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

Корректировка для классификаторов разных типов

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

g1(x)g_1(\mathbf{x})g2(x)g_2(\mathbf{x})g3(x)g_3(\mathbf{x})g4(x)g_4(\mathbf{x})
f1(x)f_1(\mathbf{x})1007034-25
f2(x)f_2(\mathbf{x})150-14-10
f3(x)f_3(\mathbf{x})0.050.60.20.15

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

Для этого применяется ранговое преобразование, в котором новый рейтинг класса считается как количество других классов, которые рассматриваемый класс доминирует (принимая более высокое значение дискриминантной функции). Преобразованный рейтинг называется рейтингом Бриера (Brier score).

В примере выше модели ранжируют классы следующим образом:

модельранжирование классов
f1(x)f_1(\mathbf{x})12341 \succ 2 \succ 3 \succ 4
f2(x)f_2(\mathbf{x})12431 \succ 2 \succ 4 \succ 3
f3(x)f_3(\mathbf{x})2 3412 \succ 3 \succ 4 \succ 1

Поэтому рейтинги Бриера будут:

g1(x)g_1'(\mathbf{x})g2(x)g_2'(\mathbf{x})g3(x)g_3'(\mathbf{x})g4(x)g_4'(\mathbf{x})
f1(x)f_1(\mathbf{x})3210
f2(x)f_2(\mathbf{x})3201
f3(x)f_3(\mathbf{x})0321

Рейтинги Бриера принадлежат уже одинаковой шкале значений {0,1,2,3}\{0,1,2,3\} поэтому их можно усреднять. В результате усреднения получим следующие рейтинги для ансамбля:

g1(x)g_1''(\mathbf{x})g2(x)g_2''(\mathbf{x})g3(x)g_3''(\mathbf{x})g4(x)g_4''(\mathbf{x})
6/37/33/62/6

Далее, как обычно, назначается класс с максимальным средним рейтингом. Это будет класс 2. Заметим, что прогноз отличается от прогноза голосованием по большинству, когда был назначен класс 1. Класс 2 победил новым способом, поскольку класс 2 считается вероятным всеми тремя классификаторами, а класс 1 считается самым маловероятным третьей моделью f3(x)f_3(\mathbf{x}).

Учёт классификаторов с разной степенью

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

Пример запуска в Python

Усредняющий ансамбль для классификации:
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import brier_score_loss

X_train, X_test, Y_train, Y_test = get_demo_classification_data()

# Инициализируем базовые модели и проверим их качество
log_model = LogisticRegression() # инициализация модели
log_model.fit(X_train, Y_train) # обучение модели
Y_hat = log_model.predict(X_test) # построение прогнозов
print(f'Точность LogisticRegression: {100*accuracy_score(Y_test, Y_hat):.1f}%')

tree_model = DecisionTreeClassifier() # инициализация дерева
tree_model.fit(X_train, Y_train) # обучение модели
Y_hat = tree_model.predict(X_test) # построение прогнозов
print(f'Точность DecisionTree: {100*accuracy_score(Y_test, Y_hat):.1f}%')

# Инициализируем ансамбль, усредняющий метки классов
ensemble = VotingClassifier(estimators=[('logistic regression', log_model),
('decision tree', tree_model)],
voting='hard', # усредняем метки классов
weights=[0.5,0.5]) # веса учёта базовых моделей
ensemble.fit(X_train, Y_train) # обучение базовых моделей ансамбля
Y_hat = ensemble.predict(X_test) # построение прогнозов
print(f'Точность VotingClassifier: {100*accuracy_score(Y_test, Y_hat):.1f}%')

# Инициализируем ансамбль, усредняющий вероятности классов
ensemble = VotingClassifier(estimators=[('logistic regression', log_model),
('decision tree', tree_model)],
voting='soft', # усредняем вероятности классов
weights=[0.5,0.5]) # веса учёта базовых моделей
ensemble.fit(X_train, Y_train) # обучение базовых моделей ансамбля
Y_hat = ensemble.predict(X_test) # построение прогнозов
print(f'Точность VotingClassifier: {100*accuracy_score(Y_test, Y_hat):.1f}%')

P_hat = ensemble.predict_proba(X_test) # можно предсказывать вероятности классов
loss = brier_score_loss(Y_test, P_hat[:,1]) # мера Бриера на вероятности положительного класса
print(f'Мера Бриера ошибки прогноза вероятностей: {loss:.2f}')

Больше информации. Полный код.

Усредняющий ансамбль для регрессии:
from sklearn.neighbors import KNeighborsRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import VotingRegressor
from sklearn.metrics import mean_absolute_error

X_train, X_test, Y_train, Y_test = get_demo_classification_data()

# Инициализируем базовые модели и проверим их качество
knn = KNeighborsRegressor(n_neighbors=100) # инициализация модели
log_model.fit(X_train, Y_train) # обучение модели
Y_hat = log_model.predict(X_test) # построение прогнозов
print(f'Средний модуль ошибки (MAE): {mean_absolute_error(Y_test, Y_hat):.2f}')

tree_model = DecisionTreeRegressor() # инициализация дерева
tree_model.fit(X_train, Y_train) # обучение модели
Y_hat = tree_model.predict(X_test) # построение прогнозов
print(f'Средний модуль ошибки (MAE): {mean_absolute_error(Y_test, Y_hat):.2f}')

# Инициализируем усредняющий ансамбль
ensemble = VotingRegressor(estimators=[('K nearest neighbours', knn),
('decision tree', tree_model)],
weights=[0.5,0.5]) # веса учёта базовых моделей
ensemble.fit(X_train, Y_train) # обучение базовых моделей ансамбля
Y_hat = ensemble.predict(X_test) # построение прогнозов
print(f'Средний модуль ошибки (MAE): {mean_absolute_error(Y_test, Y_hat):.2f}')

Больше информации. Полный код.