Data Science Machine Learning Python

O Guia do XGBoost com Python

XGBoost Vantagens

Fala galera do mundo dos dados! Neste artigo, conheceremos o eXtreme Gradient Boosting (XGBoost) sendo um dos algoritmos de aprendizado de máquina, atualmente, mais populares e poderosos. Desde sua introdução em 2014, o XGBoost tem sido elogiado como o santo graal dos hackathons e competições de aprendizado de máquina. 

Portanto, eu sempre recorro ao XGBoost como meu primeiro algoritmo de escolha em qualquer hackathon de Aprendizagem de Máquina (ML). A precisão que ele oferece de forma consistente e o tempo que economiza demonstram o quão útil ele é. Mas, como ele funciona? Qual o seu segredo? Vamos descobrir as respostas para essas perguntas em breve como também, abordaremos uma implementação prática dessa técnica em Python, onde o modelo será aplicado a um problema de classificação do mundo real. Vamos pra cima, pois temos muito a estudar e a codar.

O que é XGBoost ?

O algoritmo XGBoost foi o resultado de um projeto de investigação organizado por Carlos Guestrin e Tianqi Chen na Universidade de Washington. O XGBoost é um algoritmo de aprendizado supervisionado que implementa um processo chamado Boosting para gerar modelos precisos. O aprendizado supervisionado refere-se à tarefa de inferir um modelo preditivo a partir de um conjunto de exemplos de treinamento rotulados, ou seja, o aprendizado supervisionado pode ser considerado como o aprendizado de uma função F(X) = y que rotulará corretamente novas instâncias de entrada. 

Cabe relembrar que o aprendizado supervisionado pode ser usado para resolver problemas de classificação ou regressão. Em problemas de classificação, o label y assume um valor discreto (categórico). Por exemplo, podemos desejar prever se um defeito de fabricação ocorre ou não com base em atributos registrados no processo de fabricação, como temperatura ou tempo, representados em X. Em problemas de regressão, o label de destino y assume um valor contínuo. Isso pode ser usado para enquadrar problemas, como prever temperatura ou umidade em um determinado dia. 

Como Funciona o XGBoost ?

Assim como outros algoritmos de boosting, o XGBoost usa árvores de decisão para seu modelo de conjunto. Cada árvore é um aprendiz fraco. O algoritmo segue construindo sequencialmente mais árvores de decisão, cada uma corrigindo o erro da árvore anterior até que uma condição de parada seja alcançada. Inclui diferentes penalidades de regularização para evitar overfitting onde essas regularizações de penalidade produzem treinamento bem-sucedido para que o modelo possa generalizar adequadamente (Figura 1).

XGBoost

Ademais, cabe destacar que o XGBoost performa muito bem para classificação, mas pode ser aplicado aos problemas de regressão também, para prever os valores de uma variável contínua.

Por fim, o XGBoost foi integrado a uma ampla variedade de outras ferramentas e pacotes, como scikit-learn para entusiastas de Python e caret para usuários de R. Além disso, o XGBoost é integrado a estruturas de processamento distribuído como Apache Spark e Dask.

Vantagens do XGBoost ?

O XGBoost é considerado um dos modelos mais poderosos para dados tabulares para classificação, entretanto pode ser utilizado em uma vasta gama de aplicações para resolver problemas de previsão, ranking, classificação e regressão definidos pelo utilizador. 

Além disso, o algoritmo XGBoost é baseado na mesma ideia-chave do Gradient Boosting (melhoria gradual através da introdução de árvores adicionais), mas com algumas melhorias consideráveis.

Por fim, acrescemos também, como principais vantagens:

  1. Portabilidade: funciona em diversos SO.
  2. Variabilidade de línguas: suporta a maioria das linguagens de programação incluindo, Julia, Scala, Java, R, Python, C++.
  3. Processamento paralelo: ajuda a reduzir o tempo de treinamento.
  4. Recursos integrados: permite lidar com os valores ausentes nos dados usados ​​para treinamento e teste.
  5. Ajustamento automatizado: quando os parâmetros não são ajustados corretamente.

Desvantagens do XGBoost?

E quanto às desvantagens, há algumas características não positivas no uso do algoritmo? Sim, podemos destacar como principais desvantagens:

  1. Tempo de treinamento maior em comparação com outros modelos de reforço.
  2. O XGBoost não funciona tão bem em dados esparsos e não estruturados.
  3. O método geral dificilmente é escalável. Isso ocorre porque os estimadores baseiam sua correção em preditores anteriores, portanto, o procedimento envolve muita dificuldade para simplificar.
  4. O Gradient Boosting é muito sensível a outliers.

Implementação Prática do XGBoost com Python

Até agora temos um bom entendimento do XGBoost e nesta seção veremos como ele pode ser aplicado a problemas de classificação utilizando o algoritmo XGBClassifier. Sendo assim, nesta implementação, vamos aplicar o classificador XGBoost para resolver o problema de classificação binária onde nossa tarefa é prever se um determinado indivíduo pode ter adquirido diabete ou não. Para isso, estamos considerando um conjunto de dados que contém informações sobre o nível de glicose, pressão sanguínea, espessura da pele, insulina, índice de massa corporal, histórico familiar de diabetes, idade, etc. 

Portanto, agora vamos dar os seguintes passos para implementar este problema de classificação binária. 

1ª Interação com o XGBoost

Etapa 1 : carregar as bibliotecas iniciais para o desafio

A comunidade ML distribuída desenvolve e mantem o XGBoost. Primeiramente, é preciso instalá-lo utilizando o comando pip conforme código abaixo.

# Instalar o pacote
! pip install xgboost

Carregar as bibliotecas 

# carregando as bibliotecas necessárias ao desafio
try:
  import pandas as pd
  from IPython.core.display import display, HTML
  from xgboost import XGBClassifier
    
  # bibliotecas para visualização
  import matplotlib.pyplot as plt
  import seaborn as sns
  display( HTML( '<style>.container { width:100% !important; }</style>') )

  # maximiza o número de colunas e linhas para impressão 
  # quando do uso da função head() do Pandas
  pd.options.display.max_columns = 15
  pd.options.display.max_rows = 50

  # Ignorar warnings
  import warnings
  warnings.filterwarnings("ignore")

  %matplotlib inline
  print("Bibliotecas carregadas com sucesso!")

except:
  print("Problemas ao carregar as bibliotecas!")

Bibliotecas carregadas com sucesso!

Etapa 2 : carregar os dados

# carrega base de dados do GitHub (link + '?raw=true')
git_url = "https://github.com/plotly/datasets/blob/master/diabetes.csv?raw=true"
df_diabetes = pd.read_csv(git_url)

# apresenta cabecalho
display(HTML('<h3><b>BASE DE DADOS DIABETES</b></h3><hr/>'))

# CONSTANTES
NUM_POPULACAO = df_diabetes.shape[0]
NUM_ATRIBUTOS = df_diabetes.shape[1] 

# carregando 10 amostras aleatórias
display(df_diabetes.head(10))
display(HTML('<hr/><h3><b>População : </b>' + 
             str(NUM_POPULACAO) + 
             '  |  Número de atributos : ' + 
             str(NUM_ATRIBUTOS) +'</h3>'))

Vamos traduzir as nossas variáveis

# traduzindo toda as colunas
LISTA_ATRIBUTOS_BR = ['gravidez','glicose','pressao_sanguinea',
                      'espessura_pele','insulina','imc',
                      'historico_familiar_diabetes',
                      'idade','resultado']
df_diabetes.columns = LISTA_ATRIBUTOS_BR
df_diabetes.head()

Como vemos, há um total de 9 recursos ou atributos, dos quais os 8 primeiros serão nossos recursos de entrada para o modelo e o último é o recurso de saída ou alvo. Temos um total de 768 registros, posteriormente dividiremos esses registros para fins de treinamento e teste.    

Aqui estamos lidando com um problema de classificação. Para isso, devemos verificar como os rótulos das classes estão distribuídos ao longo de 768 registros.

# contagem da classe alvo
contagem = df_diabetes['resultado'].value_counts()
print(f"População sem diabetes: {contagem[0]}")
print(f"População com diabetes: {contagem[1]}")

População sem diabetes: 500
População com diabetes: 268

# plotar gráfico de barras para as Classes
sns.countplot('resultado', data=df_diabetes);
print('0 - pacientes sem diabetes | 1 - pacientes com diabtes\n')

observação : pelos resultados apresentados, podemos constatar que o nosso dataset está desbalanceado.

# porcentagem de cada classe alvo presente
print(f"População sem diabetes: {contagem[0]}")
print(f"População com diabetes: {contagem[1]}")

População sem diabetes: 65.1%
População com diabetes: 34.9%

De um total de 768 registros, 500 ou 65,10% registros pertencem à classe 0 (sem diabetes) e 268 ou 34,90% registros pertencem à classe 1 (com diabetes). Como podemos ver, a distribuição das classes é desequilibrada, o que significa que ao fazer previsões há uma grande chance de o resultado estar mais concentrado na classe 0 (sem diabetes). Verificaremos como o classificador se comportará nesse tipo de distribuição de classes quando avaliarmos o modelo no passo X. 

Agora vamos avançar com os procedimentos para a construção do modelo. 

Etapa 3 : verificar existência de outliers

# plotar um boxplot para analisar presença de outliers no dataset
colunas = df_copia.columns.to_list()
plt.figure(figsize=(15,8))
df_copia.boxplot(column = colunas[:-1])
plt.show()

Há possibilidade de outliers, entretanto iremos continuar com o dataset intacto e se for o caso, na próxima iteração removeremos algumas instâncias.

Etapa 4 : carregar os dados

Agora que entendemos e identificamos os recursos, aqui vamos vincular os recursos de entrada à variável X e o recurso de saída à variável y, esta etapa é necessária, pois o modelo recebe os dados na forma X e y.

# tirando uma cópia para preservar o DataFrame original
df_copia = df_diabetes.copy()

# definindo os recuros de entrada(X) e saida(y) 
X = df_copia.iloc [: , :-1].values
y = df_copia.iloc[ : , -1].values

Após delimitar os dados, vamos agora criar um par de conjuntos de treinamento e teste usando a função train_test_split() da biblioteca SKLearn para usar na fase de treinamento e teste, respectivamente. 

# separando os dados de treino e teste
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size = 0.30, 
                                                    shuffle=True, 
                                                    random_state = 0)

# verificando a dimensão dos dados de treino e teste
print(f'Dados para Treino: {X_train.shape[0]} amostras')
print(f'Dados para Teste: {X_test.shape[0]} amostras')

Dados para Treino: 537 amostras
Dados para Teste: 231 amostras

Etapa 5: inicializando e treinando o classificador de aumento de gradiente eXtremely

Aconselho que você visite o site do XGBOOST, previsto na referência, para entender cada parâmetro adotado.

Iniciando o modelo e o seu treinamento.

clf = XGBClassifier(n_estimators = 650,
                    max_depth = 10, 
                    learning_rate = 0.01,
                    subsample = 1,
                    random_state=0)

# Training the XGB classifier
clf.fit(X_train, y_train)

XGBClassifier(learning_rate=0.01, max_depth=10, n_estimators=650)

Etapa 6: prevendo e avaliando o classificador

Após treinar com sucesso o classificador nesta seção, primeiro faremos as previsões nos dados de teste para compararmos a previsão com os dados reais.

# fazendo a predição com os dados de teste
y_pred = clf.predict(X_test)
# Cobinando os valores encontrados com os valores atuais
pd.DataFrame(data={'Rótulo Atual': y_test, 'Rótulo Predito': y_pred}).head()

A partir da comparação acima, cada rótulo real está sendo previsto com precisão, mas pode haver alguns casos em que o modelo fez previsões imprecisas. Vamos revelar tudo isso usando a matriz de confusão.

Lembrando que a matriz de confusão é uma tabela que representa os acertos e erros de uma classificação. Dessa forma, com os resultado obtidos é possível fazer cálculos de desempenho.

# apresentando os resultados pela Matriz de COnfusão
from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(clf, X_test, y_test, cmap='Blues')

Agora vamos obter a precisão do teste do classificador. 

# Score da Acurácia
from sklearn.metrics import accuracy_score
print(f'Precisão do modelo: {round(accuracy_score(y_test, y_pred)*100,3)}%')

Precisão do modelo: 80.087%

Para a avaliação final do classificador vamos usar o relatório de classificação que avalia o modelo em vários parâmetros, e observando a pontuação podemos concluir o desempenho do modelo.

# Relatório da Classificação
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
Métricas de avaliação do XGBoost com Python

Na primeira iteração, trabalhamos com a distribuição das classes desequilibrada o que poderia nos levar a pensar que a previsão se concentraria no rótulo da classe 0 (sem diabetes). Mas, pelo relatório de classificação acima, podemos dizer que o classificador XGBoost lidou bem com o conjunto de dados desequilibrado. Entretanto,  a acurácia não foi muito satisfatória.

2ª Interação com o XGBoost

Nessa 2ª Iteração, iremos balancear o nosso dataset para verificar se haverá melhora na acurácia do modelo XGBClassifier. Nesse balanceamento, iremos adotar a técnica de oversampling.

# instala a biblioteca para balanceamento
! pip install imbalanced-learn

# carrega a bibliotecas necessárias para a 2ª iteração
from imblearn.over_sampling import SMOTE
from collections import Counter

Ambiente, preparado! Agora é partir para o balanceamento.

# executa o balanceamento usando a técnica SMOTE
oversample = SMOTE()
X, y = oversample.fit_resample(X, y)

# realiza a contagem das classes
contagem = Counter(y)
print(contagem)

Counter({1: 500, 0: 500})

Agora que nossas classes estão balanceadas, vamos separar o nosso conjunto de treinamento e testes (manteremos a proporção da iteração 1).

# separando os dados de treino e teste
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size = 0.30, 
                                                    shuffle=True, 
                                                    random_state = 0)

Separado os nossos dados, iremos criar o nosso novo modelo.

clf2 = XGBClassifier(n_estimators = 650, 
                     max_depth = 10, 
                     learning_rate = 0.01,
                     subsample = 1,
                     random_state=0)

# Training the XGB classifier
clf2.fit(X_train, y_train)

XGBClassifier(learning_rate=0.01, max_depth=10, n_estimators=650)

Modelo criado, passaremos a treinar o modelo.

# fazendo a predição com os dados de teste
y_pred = clf2.predict(X_test)
# Cobinando os valores encontrados com os valores atuais
pd.DataFrame(data={'Rótulo Atual': y_test, 'Rótulo Predito': y_pred}).head()

Modelo treinado, agora iremos ver como o nosso modelo está performando. Para isso, usaremos a matriz de confusão novamente, e iremos plotar um relatório com o resultado das principais métricas.

# apresentando os resultados pela Matriz de Confusão
from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(clf2, X_test, y_test, cmap='Blues')
# Score da Acurácia
from sklearn.metrics import accuracy_score
print(f'Precisão do modelo : {round(accuracy_score(y_test, y_pred)*100,3)}%')

Precisão do modelo : 85.0%

# Relatório da Classificação
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
Métricas de avaliação do XGBoost com Python

Na segunda iteração, com as classes balanceadas, pudemos atestar, pelos resultados apresentados, uma melhora na acurácia do modelo, saindo dos 80,087% para 85.0%. Portanto, atingimos o objetivo.

XGBoost ao Cubo

Cobrimos, ao longo deste post, alguns aspectos do XGBoost, começando de um ponto de vista teórico até um caminho mais prático com a aplicação do algoritmo XGBClassifier em Python. 

Como desafio, acredito que vale a pena realizar uma 3ª iteração para aplicar a técnica de oversampling com a remoção dos possíveis outliers, com o propósito de analisar a acurácia do novo modelo gerado.

Muito grato pela sua leitura, espero que tenham gostado e nos vemos num próximo post.

Como sempre, deixarei algumas referências úteis abaixo, para que você possa expandir ainda mais seu conhecimento e melhorar suas habilidades de codificação.

Referências

Conteúdos ao Cubo

Se curtiu, lá no Dados ao Cubo tem muito mais. Então, deixo algumas sugestões de conteúdos que você pode encontrar por lá, sempre falando sobre o mundo dos dados.

Para finalizar, se torne também Parceiro de Publicação Dados ao Cubo. Escreva o próximo artigo e compartilhe conhecimento para toda a comunidade de dados. Não esqueça de assinar a nossa Newsletter para ficar por dentro de todas as novidades. 

Gostou? Compartilhe!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *