Методы ансамбля для машинного обучения: AdaBoost

Реализация на Python

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

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

AdaBoost, который остается для «Adaptive Boosting», представляет собой мета-алгоритм машинного обучения, который можно использовать в сочетании со многими другими типами алгоритмов обучения для повышения производительности.

В этой статье я расскажу о математике, лежащей в основе Adaboost, а также предоставлю реализацию на Python.

Интуиция и математика, лежащие в основе AdaBoost

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

Рассматривая простую задачу двоичной классификации, цели которой представлены знаками «положительный» или «отрицательный» (выраженные как 1 и -1), уравнение окончательного классификатора выглядит следующим образом:

По сути, выход окончательного классификатора для наблюдения x равен знаку взвешенной суммы выходных данных h_t (x) T слабых классификаторов с весами, равными α_t.

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

Где ε_t - это ошибка классификатора t (неверно классифицированные наблюдения / общие наблюдения). Конечно, классификаторы с низкой ошибкой будут иметь приоритет в сумме, следовательно, их вес будет выше. Действительно, если мы посмотрим на альфу, соответствующую разным ошибкам:

import numpy as np
import matplotlib.pyplot as plt

epsilon=np.arange(0,1,0.01)
alpha=1/2*np.log((1-epsilon)/epsilon)

plt.plot(epsilon, alpha)
plt.xlabel('error')
plt.ylabel('alpha')

Как видите, вес классификатора экспоненциально растет по мере приближения ошибки к 0 и экспоненциально отрицателен по мере приближения ошибки к 1.

Затем значение альфа используется для вычисления весов другого типа, которые будут приписаны наблюдениям подмножества. Для первого классификатора веса инициализируются одинаково, так что каждое наблюдение имеет вес = 1 / n (где n = размер подмножества). Из второго классификатора каждый вес рекурсивно вычисляется как:

Где y_t - это целевое значение (1 или -1), а переменная w_t - это вектор весов с одним весом для каждого обучающего примера в обучающем наборе. «I» - это номер обучающего примера. Это уравнение показывает, как обновить вес для i-го тренировочного примера.

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

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

Давайте интерпретируем эту формулу. Поскольку мы имеем дело с двоичной классификацией (-1 против 1), произведение y_t * h_t (x_i) будет положительным, если фактические и подогнанные значения имеют один и тот же знак (хорошо классифицированы), отрицательным, если они имеют разные знаки (неправильно классифицированы ). Следовательно:

  • если продукт положительный, а альфа больше нуля (сильный классификатор), вес, присвоенный i-му наблюдению, будет небольшим
  • если продукт положительный, а альфа меньше нуля (слабый классификатор), вес, присвоенный i-му наблюдению, будет высоким
  • если продукт отрицательный, а альфа больше нуля (сильный классификатор), вес, присвоенный i-му наблюдению, будет высоким
  • если произведение отрицательное и альфа меньше нуля (слабый классификатор), вес, присвоенный i-му наблюдению, будет небольшим

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

Теперь, когда у нас есть представление о том, как работает AdaBoost, давайте посмотрим на его реализацию на Python с использованием хорошо известного набора данных Iris.

Реализация с Python

Давайте сначала импортируем наши данные:

from sklearn.ensemble import AdaBoostClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import metrics

iris = datasets.load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

Алгоритм по умолчанию в AdaBoost - это дерево решений, но вы можете вручную установить другой классификатор. Здесь я собираюсь использовать классификатор Support Vector Machine (подробнее о SVM вы можете прочитать здесь).

from sklearn.svm import SVC
from sklearn import metrics
svc=SVC(probability=True, kernel='linear')


abc =AdaBoostClassifier(n_estimators=50, base_estimator=svc,learning_rate=1)

model = abc.fit(X_train, y_train)

y_pred = model.predict(X_test)
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))

Output:

Accuracy: 0.9777777777777777

Как видите, почти 98% наших наблюдений классифицированы правильно.

Выводы

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

Первоначально опубликовано на http://datasciencechalktalk.com 7 сентября 2019 г.