CatBoost x LightGBM x XGBoost, quem é o mais forte!

Algoritmos de reforço são uma classe de algoritmos de aprendizado de máquina que constroem um classificador forte treinando iterativamente uma série de classificadores fracos (geralmente árvores de decisão). Em cada rodada de iterações, novos classificadores são projetados para corrigir os erros das rodadas anteriores de classificadores, melhorando gradualmente o desempenho geral da classificação.

Apesar da ascensão e popularidade das redes neurais, os algoritmos de reforço ainda são bastante práticos. Porque eles ainda funcionam bem com dados de treinamento limitados, tempo de treinamento curto, falta de experiência em ajuste de parâmetros, etc.

Os algoritmos de reforço incluem AdaBoost, CatBoost, LightGBM, XGBoost, etc.

foto

Neste artigo, focaremos em CatBoost, LightGBM e XGBoost. será incluído:

  • Diferença estrutural;

  • Como cada algoritmo trata variáveis ​​categóricas;

  • compreender parâmetros;

  • prática em conjuntos de dados;

  • desempenho de cada algoritmo.

Como o XGBoost (frequentemente chamado de GBM Killer) já existe no aprendizado de máquina há muito tempo e há muitos artigos dedicados a ele, este artigo se concentrará mais em CatBoost e LGBM.

1. Diferenças estruturais entre LightGBM e XGBoost

LightGBM usa uma nova técnica de amostragem unilateral baseada em gradiente (GOSS) para filtrar instâncias de dados ao procurar valores de divisão, enquanto XGBoost usa um algoritmo pré-classificado e um algoritmo baseado em histograma (algoritmo baseado em histograma) para calcular a divisão ideal .

Os casos acima referem-se a observações/amostras.

Primeiro, vamos entender como funciona a divisão de pré-classificação do XGBoost:

  • Para cada nó, enumere todos os recursos;

  • Para cada recurso, classifique as instâncias por valor de recurso;

  • Use uma varredura linear para determinar a melhor divisão do recurso com base no ganho de informações;

  • Selecione a melhor solução de divisão entre todos os recursos.

Em termos simples, os algoritmos baseados em histograma dividem todos os pontos de dados de um recurso em compartimentos discretos e usam esses compartimentos para encontrar os valores de divisão do histograma. Embora seja mais eficiente na velocidade de treinamento do que o algoritmo de pré-classificação, que precisa enumerar todos os pontos de divisão possíveis nos autovalores pré-classificados, ele ainda fica atrás do GOSS em termos de velocidade.

Então, o que torna o método GOSS eficiente?

No AdaBoost, os pesos amostrais podem ser usados ​​como um bom indicador da importância da amostra. Porém, na árvore de decisão com gradiente reforçado (GBDT), não há peso amostral nativo, portanto não pode ser aplicado diretamente ao método de amostragem proposto pelo AdaBoost. Isso introduz métodos de amostragem baseados em gradiente.

O gradiente representa a inclinação da tangente à função de perda, portanto, de certa forma, se o gradiente dos pontos de dados for grande, esses pontos são importantes para encontrar o melhor ponto de divisão porque apresentam um erro maior.

GOSS mantém todas as instâncias com grandes gradientes e amostra aleatoriamente instâncias com pequenos gradientes. Por exemplo, suponha que eu tenha 500.000 linhas de dados, 10.000 das quais possuem grandes gradientes. Portanto, meu algoritmo escolherá (10 mil linhas com gradientes grandes + x% seleção aleatória das 490 mil linhas restantes). Supondo que x seja 10%, o número total de linhas selecionadas é 59k com base nos valores de divisão encontrados.

A suposição básica aqui é que instâncias de treinamento com gradientes menores apresentam erros de treinamento menores e já são bem treinadas. Para manter a mesma distribuição de dados, ao calcular o ganho de informação, o GOSS introduz um multiplicador constante para instâncias de dados com gradientes menores. Portanto, o GOSS alcança um bom equilíbrio entre a redução do número de instâncias de dados e a manutenção da precisão das árvores de decisão de aprendizagem.

foto

LGBM cresce ainda mais em folhas com gradientes/erros maiores

2. Como cada modelo lida com variáveis ​​categóricas?

2.1 Cat Boost

CatBoost tem a flexibilidade de fornecer índices em colunas categóricas para que possam ser codificados usando codificação one-hot, usando o parâmetro one_hot_max_size (use codificação one-hot para todos os recursos com um número de valores distintos menor ou igual ao dado valor do parâmetro).

Se nada for passado no parâmetro cat_features, CatBoost tratará todas as colunas como variáveis ​​numéricas.

Nota: CatBoost gerará um erro se uma coluna contendo valores de string não for fornecida em cat_features. Além disso,as colunas cujo padrão é o tipo int serão tratadas como numéricas por padrão.Se você quiser tratá-las como variáveis ​​categóricas,você deve especificá-las em cat_features.

foto

Para as colunas categóricas restantes, onde o número de categorias exclusivas é maior que one_hot_max_size, CatBoost usa um método de codificação eficiente semelhante à codificação média, mas reduzindo o sobreajuste. O processo é como se segue:

  • Random permuta o conjunto de observações de entrada em uma ordem aleatória, gerando múltiplas permutações aleatórias;

  • Converta valores de rótulos de números flutuantes ou categorias em números inteiros;

  • Converta todos os valores de recursos categóricos em valores numéricos usando a seguinte fórmula:

foto

Entre eles, countInClass indica o número de ocorrências do valor do recurso de classificação atual em objetos com valor de rótulo igual a “1”, prior é o valor preliminar do numerador, determinado pelo parâmetro inicial, e totalCount é o número total de objetos antes do objeto atual que possui um número de valor do recurso de classificação atual correspondente.

Matematicamente, pode ser expresso pela seguinte equação:

foto

imagem

2.2 LightGBM

Semelhante ao CatBoost, LightGBM também pode lidar com recursos categóricos inserindo nomes de recursos. Ele não converte para codificação one-hot e é muito mais rápido que a codificação one-hot. LGBM usa um algoritmo especial para encontrar valores de divisão para recursos categóricos.

foto

imagem

Nota: Antes de construir o conjunto de dados LGBM, você deve converter os recursos categóricos em tipos inteiros. Ele não aceita um valor de string mesmo que seja passado pelo parâmetro categorical_feature.

2.3XGBoost

Ao contrário do CatBoost ou LGBM, o próprio XGBoost não pode lidar com recursos categóricos, ele aceita apenas dados numéricos semelhantes ao Random Forest. Portanto, várias codificações, como codificação de rótulo, codificação média ou codificação one-hot, precisam ser executadas antes de alimentar dados categóricos ao XGBoost.

3. Entenda os parâmetros

Todos esses modelos possuem muitos parâmetros para ajustar, mas discutiremos apenas os mais importantes. Abaixo está uma lista desses parâmetros, de acordo com sua função e seus parâmetros correspondentes nos diferentes modelos.

foto

imagem

4. Implementação no conjunto de dados

Usei o conjunto de dados Kaggle de atrasos de voos em 2015 porque ele contém recursos categóricos e numéricos. Com aproximadamente 5 milhões de linhas de dados, este conjunto de dados é bom para avaliar o desempenho de cada tipo de modelo de boost em termos de velocidade e precisão. Usarei um subconjunto de 10% desses dados, cerca de 500.000 linhas.

Os seguintes recursos são usados ​​para modelagem:

  • MÊS, DIA, DAY_OF_WEEK: tipo de dados int

  • AIRLINE e FLIGHT_NUMBER: tipo de dados int

  • ORIGIN_AIRPORT e DESTINATION_AIRPORT: tipo de dados string

  • DEPARTURE_TIME: tipo de dados flutuante

  • ARRIVAL_DELAY: Esta será a variável de destino e será convertida em um booleano representando um atraso de mais de 10 minutos

  • DISTANCE e AIR_TIME: tipo de dados float

import pandas as pd, numpy as np, time
from sklearn.model_selection import train_test_split

data = pd.read_csv("./data/flights.csv")
data = data.sample(frac = 0.1, random_state=10)

data = data[["MONTH","DAY","DAY_OF_WEEK","AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT",
                 "ORIGIN_AIRPORT","AIR_TIME", "DEPARTURE_TIME","DISTANCE","ARRIVAL_DELAY"]]
data.dropna(inplace=True)

data["ARRIVAL_DELAY"] = (data["ARRIVAL_DELAY"]>10)*1

cols = ["AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT","ORIGIN_AIRPORT"]
for item in cols:
    data[item] = data[item].astype("category").cat.codes + 1

train, test, y_train, y_test = train_test_split(data.drop(["ARRIVAL_DELAY"], axis=1), data["ARRIVAL_DELAY"],random_state=10, test_size=0.25)

4.1XGBoost

import xgboost as xgb
from sklearn import metrics
from sklearn.model_selection import GridSearchCV

def auc(m, train, test): 
    return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]),
                            metrics.roc_auc_score(y_test,m.predict_proba(test)[:,1]))

# Parameter Tuning
model = xgb.XGBClassifier()
param_dist = {
    
    "max_depth": [10,30,50],
              "min_child_weight" : [1,3,6],
              "n_estimators": [200],
              "learning_rate": [0.05, 0.1,0.16],}
grid_search = GridSearchCV(model, param_grid=param_dist, cv = 3, 
                                   verbose=10, n_jobs=-1)
grid_search.fit(train, y_train)

grid_search.best_estimator_

model = xgb.XGBClassifier(max_depth=50, min_child_weight=1,  n_estimators=200,\
                          n_jobs=-1 , verbose=1,learning_rate=0.16)
model.fit(train,y_train)
auc(model, train, test)

4.2 LightGBM

import lightgbm as lgb
from sklearn import metrics

def auc2(m, train, test): 
    return (metrics.roc_auc_score(y_train,m.predict(train)),
                            metrics.roc_auc_score(y_test,m.predict(test)))

lg = lgb.LGBMClassifier(verbose=0)
param_dist = {
    
    "max_depth": [25,50, 75],
              "learning_rate" : [0.01,0.05,0.1],
              "num_leaves": [300,900,1200],
              "n_estimators": [200]
             }
grid_search = GridSearchCV(lg, n_jobs=-1, param_grid=param_dist, cv = 3, scoring="roc_auc", verbose=5)
grid_search.fit(train,y_train)
grid_search.best_estimator_

d_train = lgb.Dataset(train, label=y_train)
params = {
    
    "max_depth": 50, "learning_rate" : 0.1, "num_leaves": 900,  "n_estimators": 300}

# Without Categorical Features
model2 = lgb.train(params, d_train)
auc2(model2, train, test)

# With Catgeorical Features
cate_features_name = ["MONTH","DAY","DAY_OF_WEEK","AIRLINE","DESTINATION_AIRPORT",
                 "ORIGIN_AIRPORT"]
model2 = lgb.train(params, d_train, categorical_feature = cate_features_name)
auc2(model2, train, test)

4.3 Impulso do Gato

Ao ajustar os parâmetros do CatBoost, é difícil passar o índice dos recursos categóricos. Então ajustei os parâmetros sem passar recursos categóricos e avaliei dois modelos - um com recursos categóricos e outro sem. Ajustei one_hot_max_size sozinho, pois não afeta outros parâmetros.

import catboost as cb
cat_features_index = [0,1,2,3,4,5,6]

def auc(m, train, test): 
    return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]),
                            metrics.roc_auc_score(y_test,m.predict_proba(test)[:,1]))

params = {
    
    'depth': [4, 7, 10],
          'learning_rate' : [0.03, 0.1, 0.15],
         'l2_leaf_reg': [1,4,9],
         'iterations': [300]}
cb = cb.CatBoostClassifier()
cb_model = GridSearchCV(cb, params, scoring="roc_auc", cv = 3)
cb_model.fit(train, y_train)

With Categorical features
clf = cb.CatBoostClassifier(eval_metric="AUC", depth=10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15)
clf.fit(train,y_train)
auc(clf, train, test)

With Categorical features
clf = cb.CatBoostClassifier(eval_metric="AUC",one_hot_max_size=31, \
                            depth=10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15)
clf.fit(train,y_train, cat_features= cat_features_index)
auc(clf, train, test)

5. Conclusão

foto

Ao avaliar um modelo, devemos considerar o desempenho do modelo em termos de velocidade e precisão.

Com isso em mente, CatBoost é o vencedor, com a maior precisão no conjunto de teste (0,816), o menor overfitting (precisão próxima nos conjuntos de treinamento e teste) e o menor tempo de previsão e ajuste. Mas isso ocorre apenas porque consideramos variáveis ​​​​categóricas e ajustamos one_hot_max_size. Se não aproveitarmos esses recursos do CatBoost, sua precisão é de apenas 0,752, que é o pior desempenho. Portanto, concluímos que CatBoost só tem um bom desempenho quando há variáveis ​​categóricas nos dados e as ajustamos corretamente.

Nosso próximo modelo com bom desempenho é o XGBoost. Mesmo ignorando o fato de que tínhamos variáveis ​​categóricas nos dados e as convertemos em variáveis ​​numéricas para o XGBoost usar, sua precisão ainda estava bem próxima do CatBoost. No entanto, o único problema do XGBoost é que ele é muito lento. É realmente frustrante ajustar seus parâmetros, especialmente com o GridSearchCV (demorei 6 horas para executar o GridSearchCV, péssima ideia!). Uma abordagem melhor é ajustar os parâmetros individualmente em vez de usar GridSearchCV. Leia esta postagem do blog para saber como ajustar os parâmetros.

Finalmente, LightGBM ocupa o último lugar. Uma coisa a notar aqui é que ao usar cat_features ele não funciona bem em termos de velocidade e precisão. Acho que o motivo pelo qual ele tem um desempenho ruim é que ele usa algum tipo de codificação média modificada nos dados categóricos, o que leva ao overfitting (precisão de treinamento muito alta - 0,999 em comparação com a baixa precisão do teste). No entanto, se usado normalmente como o XGBoost, ele pode atingir uma precisão semelhante (ou até maior) (LGBM - 0,785, XGBoost - 0,789) muito mais rápido que o XGBoost.

Finalmente, devo dizer que estas observações se aplicam a este conjunto de dados específico e podem ou não ser válidas para outros conjuntos de dados. Em geral, porém, é verdade que o XGBoost é mais lento que os outros dois algoritmos.

Acho que você gosta

Origin blog.csdn.net/qq_34160248/article/details/132679278
Recomendado
Clasificación