O XGBoost, apesar de ser uma biblioteca de gradient boosting poderosa e eficiente, é feito para trabalhar com dados numéricos.
Isso significa que você precisa encontrar uma maneira de transformar dados categóricos em um formato que o XGBoost possa entender.
Esse processo pode ser demorado e complexo, especialmente se você estiver lidando com um grande número de variáveis categóricas ou categorias.
O problema se torna ainda mais desafiador quando você considera as armadilhas potenciais da transformação de variáveis categóricas.
Se não for feita corretamente, a codificação pode introduzir ruído em seus dados, levando a um desempenho ruim do modelo.
Além disso, alguns métodos de transformação podem aumentar significativamente a dimensionalidade do seu conjunto de dados, tornando o processo de treinamento mais lento e faminto por memória.
Mas depois de ler este tutorial, você saberá como lidar com variáveis categóricas no XGBoost de maneira eficiente e eficaz.
Este tutorial é válido tanto para problemas de regressão quanto de classificação.
Codificação Nativa Usando a Interface Scikit-learn do XGBoost
A interface Scikit-learn do XGBoost fornece um parâmetro chamado enable_categorical
que permite ao XGBoost lidar com variáveis categóricas sem a necessidade de adicionar um passo de pré-processamento manual.
Primeiro, você precisa garantir que suas colunas categóricas sejam do tipo ‘category’ em seu DataFrame do Pandas.
Isso é importante porque o parâmetro enable_categorical
do XGBoost só reconhece colunas categóricas que são do tipo ‘category’.
Vamos usar o conjunto de dados Adult em nossa demonstração, pois ele tem uma mistura de colunas categóricas e numéricas.
A tarefa aqui é prever se uma pessoa ganha mais de $50.000 por ano com base em suas informações demográficas.
Vamos começar convertendo as colunas categóricas para o tipo ‘category’:
import pandas as pd
# Carregar o conjunto de dados
df = pd.read_csv('adult.csv')
# Lista de colunas categóricas
cat_cols = ['marital.status', 'occupation', 'relationship', 'race', 'sex', 'native.country', 'workclass', 'education']
# Converter colunas categóricas para o tipo category
for col in cat_cols:
df[col] = df[col].astype('category')
Às vezes, o Pandas converterá automaticamente suas colunas categóricas para o tipo ‘category’ quando você carregar seu conjunto de dados, mas é sempre uma boa ideia verificar.
Uma vez que suas colunas categóricas sejam do tipo ‘category’, você pode passar seu DataFrame para o XGBoost e definir enable_categorical=True
.
Isso diz ao XGBoost para lidar com as variáveis categóricas nativamente.
from xgboost import XGBClassifier
# Dividir em X e y, remover a variável alvo de X e converter y para binário
y = y = df['income'].map({'<=50K': 0, '>50K': 1})
X = df.drop('income', axis=1)
# Inicializar o classificador XGBoost
model = XGBClassifier(enable_categorical=True, tree_method='hist')
# Treinar o modelo
model.fit(X, y)
Não dividi em conjuntos de treino e teste para manter o código breve, mas você sempre deve fazer isso na prática ANTES de fazer qualquer transformação, incluindo a codificação categórica.
O parâmetro tree_method='hist'
diz ao XGBoost para usar o algoritmo baseado em histograma ao construir árvores.
Além de ser mais rápido, tive que usar esse parâmetro porque recebi o seguinte erro quando tentei treinar o modelo sem ele:
ValueError: Experimental support for categorical data is not implemented for current tree method yet.
Este método é direto e não requer nenhuma codificação manual das variáveis categóricas.
No entanto, é importante notar que esse recurso é experimental e pode nem sempre fornecer os melhores resultados.
Codificação Nativa Usando a Interface Nativa do XGBoost
A interface nativa do XGBoost também fornece uma maneira de transformar variáveis categóricas.
É um pouco diferente da interface Scikit-learn.
Na interface nativa, você ainda precisa converter suas variáveis categóricas para o tipo ‘category’, como descrito na seção anterior.
No entanto, aqui você precisa especificar as colunas categóricas usando o parâmetro enable_categorical
ao converter seu DataFrame para DMatrix.
import xgboost as xgb
y = df['income'].map({'<=50K': 0, '>50K': 1})
X = df.drop('income', axis=1)
# Converter DataFrame para DMatrix
data = xgb.DMatrix(X, label=y, enable_categorical=True)
# Especificar parâmetros
params = {'max_depth': 3, 'eta':1, 'objective':'binary:logistic'}
# Treinar o modelo
model = xgb.train(params, data)
Por que você usaria a interface nativa em vez da interface Scikit-learn?
A interface nativa é mais flexível e geralmente tem mais opções do que a interface Scikit-learn.
Então, se você quiser usar quaisquer hiperparâmetros avançados ou novos, precisará usar a interface nativa, mas para a maioria dos casos de uso, a interface Scikit-learn é suficiente.
Não recebi o erro que tive na seção anterior, mesmo sem especificar o parâmetro tree_method='hist'
.
Se você receber, tente adicionar o parâmetro ao dicionário params
e veja se funciona.
Codificação Categórica Usando One-Hot Encoding
One-Hot Encoding é um método popular para lidar com variáveis categóricas.
Ele cria uma coluna binária para cada nível de categoria e retorna uma matriz com essas representações binárias.
Este método é simples e eficaz, mas pode levar a um conjunto de dados de alta dimensionalidade se suas variáveis categóricas tiverem muitas categorias únicas.
Imagine fazer isso para todos os CEPs do Brasil, por exemplo.
De qualquer forma, pode ser uma boa opção se suas variáveis categóricas tiverem um pequeno número de níveis únicos (baixa cardinalidade).
Para realizar o One-Hot Encoding, a maneira mais fácil é usar a classe OneHotEncoder
da biblioteca category_encoders
.
Primeiro, vamos instalar a biblioteca:
pip install category_encoders
Agora, você pode usar a classe OneHotEncoder
para codificar suas variáveis categóricas:
from category_encoders import OneHotEncoder
# Inicializar OneHotEncoder
encoder = OneHotEncoder(cols=cat_cols)
# Mapear e transformar o DataFrame
df_encoded = encoder.fit_transform(df)
Novamente, não estou dividindo em conjuntos de treino e teste para manter o código breve. Faça isso ANTES de fazer qualquer transformação.
Neste caso, você usaria o método fit_transform
com o conjunto de treinamento e o método transform
com o conjunto de teste.
Assim como com qualquer outro transformador do Scikit-learn.
A melhor coisa sobre esta biblioteca é que ela retorna um DataFrame com as colunas numéricas originais e as novas colunas codificadas, evitando uma etapa extra de concatenação dos dois DataFrames.
age | workclass_1 | workclass_2 | workclass_3 | workclass_4 |
---|---|---|---|---|
90 | 1 | 0 | 0 | 0 |
82 | 0 | 1 | 0 | 0 |
66 | 1 | 0 | 0 | 0 |
54 | 0 | 1 | 0 | 0 |
41 | 0 | 1 | 0 | 0 |
Agora, seu DataFrame está transformado e pronto para ser passado para o XGBoost:
y = df_encoded['income'].map({'<=50K': 0, '>50K': 1})
X = df_encoded.drop('income', axis=1)
# Inicializar o classificador XGBoost
model = XGBClassifier(tree_method='hist')
# Treinar o modelo
model.fit(X, y)