Сравнение методов усиления дерева решений

От случайного леса к LightGBM

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

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

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

  • Случайный лес
  • Повышение градиента
  • XGBoost
  • LightGBM

Чтобы сравнить производительность этих методов, я инициализировал искусственный набор данных следующим образом:

from sklearn.datasets import make_blobs
from matplotlib import pyplot
from pandas import DataFrame
# generate 2d classification dataset
X, y = make_blobs(n_samples=10000, centers=3, n_features=2)
df = DataFrame(dict(x1=X[:,0], x2=X[:,1], label=y))
df.head()

Как видите, наш набор данных содержит наблюдения, имеющие вектор из двух предикторов [x1, x2] и категориальный вывод с 3 классами [0,1,2].

Конечная цель - показать, как LightGBM превосходит (намного) другие алгоритмы.

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

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

Кроме того, алгоритм случайного леса добавляет еще одно ограничение: каждый раз, когда дерево растет из загруженной выборки, алгоритм позволяет ему рассматривать только подмножество размера m всех пространств ковариаций размера p (с m ‹p). Таким образом, каждое дерево становится независимым друг от друга.

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

#random forest
import time
start = time.time()
clf_rf = RandomForestClassifier(max_depth=2, random_state=0)
from sklearn.model_selection import cross_val_score
clf_rf = RandomForestClassifier()
scores = cross_val_score(clf_rf, X, y, cv=5)
acc_rf = scores.mean()
#acc_rf
#do something
end = time.time()
temp_rf = end-start

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

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

Идея бустинга заключается в построении серии деревьев, каждое из которых является обновленной версией предыдущего. По сути, на каждой итерации дерево строится по набору данных (X, r), а не (X, y), где «r» указывает остатки, полученные предыдущим деревом. Затем уменьшенная версия этого классификатора добавляется к предыдущей, и процедура продолжается до конца цикла (или когда достигается определенное условие прерывания).

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

Итак, давайте также инициализируем этот алгоритм и обучим его нашим данным:

from sklearn.ensemble import GradientBoostingClassifier
start = time.time()
clf_gb = GradientBoostingClassifier(max_depth=2, random_state=0)
scores = cross_val_score(clf_gb, X, y, cv=5)
acc_gb = scores.mean()
end = time.time()
temp_gb = end-start

XGBoost

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

Все эти функции сделали его любимым алгоритмом на Kaggle в течение очень долгого времени, пока на рынок не вышли новые версии Gradient Boosting (в том числе LightGBM).

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

#installing the package for xgboost
!pip install xgboost
import xgboost as xgb
start = time.time()
clf_xgb=xgb.XGBClassifier()
scores = cross_val_score(clf_xgb, X, y, cv=5)
acc_xgb = scores.mean()
end = time.time()
temp_xgb = end-start

Примечание: в отличие от Random Forest и Gradient Boosting Classifier, которые были библиотеками scikit-learn, с XGBoost и, позже, LightGBM, мы должны рассматривать их как отдельные пакеты. Следовательно, мы можем легко установить их через pip.

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

LightGBM

LightGBM - это еще один фреймворк для повышения градиента, который использует древовидный алгоритм обучения. Как его коллега XGBoost, он фокусируется на вычислительной эффективности и высокой стандартной производительности.

В последнее время LightGBM добился невероятных успехов во многих соревнованиях Kaggle, превзойдя XGBoost как по скорости обучения, так и по точности прогнозов.

Посмотрим, верно ли это и для нашего искусственного набора данных.

! pip install lightgbm
import lightgbm as lgb
params = {
    'boosting_type': 'gbdt',
    'objective': 'binary',
    'metric': 'binary_error', 
}
lgb_train = lgb.Dataset(X, y, free_raw_data=False)
start = time.time()
scores = lgb.cv(
        params,
        lgb_train,
        num_boost_round=100,
        nfold=5,
        stratified=False
        )
scores
end = time.time()
temp_lgb = end-start

Выводы

Теперь давайте посмотрим на результаты наших алгоритмов:

import pandas as pd
data = dict([('LigthGBM', [acc_lgb, temp_lgb]), ('XGBoost', [acc_xgb*100, temp_xgb]), ('Random Forest', [acc_rf*100, temp_rf]),
             ('Gradient Boosting', [acc_gb*100, temp_gb])])
df = pd.DataFrame(data).T.rename(columns={0: 'Accuracy', 1: 'Training Time'})
df

import matplotlib.pyplot as plt
fig, axes = plt.subplots(figsize=(12,8),nrows=1, ncols=2, sharey=True)
#initializing a function for a better interpretability of the 
#training time
def ret_time(temp):
    minutes = round(temp//60, 0)
    seconds = round(temp - 60*minutes, 0)
    return [int(minutes), int(seconds)]
#ax2=plt.subplot(2,2,2)
ax1=df.sort_values(by='Accuracy', ascending=True)["Accuracy"].plot(ax=axes[0], kind='barh', logx=True, xlim=(0,102))
ax1.text(96.15, 0, str(str(round(acc_rf*100,2))+'%'), fontsize=15)
ax1.text(96.4, 1, str(str(round(acc_gb*100,2))+'%'), fontsize=15)
ax1.text(96.44, 2, str(str(round(acc_xgb*100,2))+'%'), fontsize=15)
ax1.text(100, 3, str(str(round(acc_lgb,2))+'%'), fontsize=15)
ax1.set_title('Accuracy on 5-fold CV')
ax2 = df.sort_values(by='Accuracy', ascending=True)["Training Time"].plot(ax=axes[1], kind='barh', xlim=(0,900), colormap='viridis')
ax2.text(400, 0, str(str(ret_time(temp_rf)[0]) + 'm:'+str(ret_time(temp_rf)[1])+'s'), fontsize=15)
ax2.text(700, 1, str(str(ret_time(temp_gb)[0]) + 'm:'+str(ret_time(temp_gb)[1])+'s'), fontsize=15)
ax2.text(400, 2, str(str(ret_time(temp_xgb)[0]) + 'm:'+str(ret_time(temp_xgb)[1])+'s'), fontsize=15)
ax2.text(100, 3, str(str(ret_time(temp_lgb)[0]) + 'm:'+str(ret_time(temp_lgb)[1])+'s'), fontsize=15)
#ax1.text(700, 1, str(), fontsize=15)
#ax1.text(400, 2, str(), fontsize=15)
ax2.set_title('Training Time')

Как видите, LightGBM не только является моделью с высочайшей точностью, но и имеет наименьшее время обучения (безусловно).

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

Тем не менее, LightGBM показал отличные результаты во многих соревнованиях Kaggle и сегодня является одним из предпочтительных классификаторов на рынке.

Надеюсь, вам понравится это чтение! Если вам интересна тема, а также дальнейшие «экстремальные» версии Gradient Boosting, я предлагаю вам ссылки ниже:

использованная литература