Fundamentos do Machine Learning com Python

0/25 aulas0%
pratica

Codificação de Variáveis Categóricas: One-Hot Encoding e Label Encoding (Documentação Scikit-learn)

Aprenda sobre codificação de variáveis categóricas: one-hot encoding e label encoding (documentação scikit-learn)

75 min
Aula 5 de 5

🚀 Fundamentos do Machine Learning com Python: Codificação de Variáveis Categóricas

Olá! Bem-vindo(a) à aula de hoje sobre um tópico crucial no pré-processamento de dados para Machine Learning: a codificação de variáveis categóricas. 🎯

🎯 Introdução

No mundo real, nossos conjuntos de dados frequentemente contêm informações que não são numéricas, como "cor" (vermelho, azul, verde), "tamanho" (P, M, G) ou "cidade" (São Paulo, Rio de Janeiro). Essas são as variáveis categóricas.

A maioria dos algoritmos de Machine Learning, no entanto, é construída para trabalhar com números. Eles não entendem texto ou categorias diretamente. Se tentarmos alimentar um modelo com "vermelho", "azul", ele simplesmente não saberá o que fazer! 🤯

É aí que entra a codificação de variáveis categóricas. O objetivo é transformar essas categorias textuais em uma representação numérica que os algoritmos possam processar, sem introduzir relações artificiais ou perder informações importantes.

Nesta aula prática, exploraremos duas das técnicas mais comuns e fundamentais, ambas disponíveis na poderosa biblioteca Scikit-learn:

  1. Label Encoding
  2. One-Hot Encoding

Vamos mergulhar! 🏊‍♂️

📚 1. Label Encoding: Atribuindo Números a Categorias

O que é?

O Label Encoding é uma técnica simples onde cada categoria única em uma coluna é atribuída a um número inteiro único. Por exemplo, se tivermos as categorias "P", "M", "G", elas poderiam ser codificadas como 0, 1, 2, respectivamente.

Quando usar?

Este método é ideal para variáveis categóricas ordinais, ou seja, aquelas que possuem uma ordem intrínseca.

  • Exemplos:
    • Tamanho da roupa: P < M < G
    • Nível de escolaridade: Fundamental < Médio < Superior
    • Classificação de satisfação: Ruim < Regular < Bom < Ótimo

Quando não usar? (O perigo! ⚠️)

Não é recomendado para variáveis categóricas nominais, que não possuem uma ordem natural (e.g., cores, cidades, tipos de fruta). Se aplicarmos Label Encoding a categorias nominais (ex: Vermelho=0, Azul=1, Verde=2), o algoritmo de ML pode interpretar que "Azul" é "maior" que "Vermelho" ou que a "distância" entre "Vermelho" e "Azul" é a mesma que entre "Azul" e "Verde". Isso introduz uma relação numérica artificial e incorreta que pode enganar o modelo e levar a resultados ruins.

Exemplo Prático com Scikit-learn (LabelEncoder)

Vamos usar a classe LabelEncoder do Scikit-learn.

import pandas as pd
from sklearn.preprocessing import LabelEncoder
 
# 1. Dados de exemplo: Tamanhos de camiseta (variável ordinal)
data = {
    'Tamanho': ['P', 'M', 'G', 'P', 'G', 'M', 'P', 'GG'],
    'Cor': ['Vermelho', 'Azul', 'Verde', 'Azul', 'Vermelho', 'Verde', 'Vermelho', 'Azul'],
    'Preco': [50, 60, 70, 55, 75, 65, 52, 80]
}
df = pd.DataFrame(data)
 
print("DataFrame Original:")
print(df)
print("-" * 30)
 
# 2. Criando uma instância do LabelEncoder
label_encoder = LabelEncoder()
 
# 3. Aplicando Label Encoding à coluna 'Tamanho'
# fit_transform() aprende as categorias únicas e as transforma em números
df['Tamanho_Encoded'] = label_encoder.fit_transform(df['Tamanho'])
 
print("\nDataFrame com 'Tamanho' codificado por Label Encoding:")
print(df)
print("-" * 30)
 
# 4. Visualizando as classes e seus mapeamentos
print("\nMapeamento das classes pelo LabelEncoder:")
for i, item in enumerate(label_encoder.classes_):
    print(f"{item} -> {i}")
 
# 5. Invertendo a transformação (útil para entender as previsões)
# Vamos pegar o primeiro valor codificado de 'Tamanho'
first_encoded_size = df['Tamanho_Encoded'].iloc[0]
original_size = label_encoder.inverse_transform([first_encoded_size])
print(f"\nValor codificado '{first_encoded_size}' retransformado: {original_size[0]}")
 
# Exemplo de uma categoria nova (não vista no fit)
# Se tentarmos transformar uma categoria nova, o LabelEncoder vai falhar
# try:
#     label_encoder.transform(['XG'])
# except ValueError as e:
#     print(f"\nErro ao tentar codificar uma categoria não vista: {e}")

Saída esperada:

DataFrame Original:
  Tamanho       Cor  Preco
0       P  Vermelho     50
1       M      Azul     60
2       G     Verde     70
3       P      Azul     55
4       G  Vermelho     75
5       M     Verde     65
6       P  Vermelho     52
7      GG      Azul     80
------------------------------

DataFrame com 'Tamanho' codificado por Label Encoding:
  Tamanho       Cor  Preco  Tamanho_Encoded
0       P  Vermelho     50                2
1       M      Azul     60                1
2       G     Verde     70                0
3       P      Azul     55                2
4       G  Vermelho     75                0
5       M     Verde     65                1
6       P  Vermelho     52                2
7      GG      Azul     80                3
------------------------------

Mapeamento das classes pelo LabelEncoder:
G -> 0
GG -> 1
M -> 2
P -> 3

Valor codificado '2' retransformado: P

Observação: O LabelEncoder atribui os números em ordem alfabética por padrão (G=0, GG=1, M=2, P=3). Se a ordem numérica precisa refletir uma ordem ordinal específica (ex: P=0, M=1, G=2, GG=3), você pode usar OrdinalEncoder do Scikit-learn e especificar a ordem das categorias, ou mapear manualmente usando um dicionário.

🌈 2. One-Hot Encoding: Criando Colunas Binárias

O que é?

O One-Hot Encoding resolve o problema da ordem artificial introduzido pelo Label Encoding em variáveis nominais. Ele transforma cada categoria em uma nova coluna binária (0 ou 1).

  • Se uma linha pertence a uma categoria, a coluna correspondente recebe 1, e as outras colunas de categoria recebem 0.
  • Exemplo: Se tivermos as cores "Vermelho", "Azul", "Verde", seriam criadas três novas colunas: Cor_Vermelho, Cor_Azul, Cor_Verde.
    • Uma linha com "Vermelho" teria Cor_Vermelho=1, Cor_Azul=0, Cor_Verde=0.

Quando usar?

Este método é o mais recomendado para variáveis categóricas nominais, onde não há uma ordem intrínseca entre as categorias.

  • Exemplos:
    • Cores: Vermelho, Azul, Verde
    • Cidades: São Paulo, Rio de Janeiro, Belo Horizonte
    • Tipos de produto: Eletrônico, Roupa, Alimento

Quando não usar? (O problema da dimensionalidade! 💥)

  • Alta Cardinalidade: Se uma variável categórica tiver muitas categorias únicas (ex: 1000 cidades diferentes), o One-Hot Encoding criará 1000 novas colunas. Isso pode levar ao "curse of dimensionality" (maldição da dimensionalidade), aumentando muito o número de features, tornando o modelo mais lento, propenso a overfitting e mais difícil de interpretar.
  • Multicolinearidade (Dummy Variable Trap): Quando se usam todas as $N$ categorias para criar $N$ colunas binárias, uma das colunas pode ser perfeitamente predita pelas outras $N-1$ colunas (ex: se não é Vermelho e não é Azul, então tem que ser Verde). Isso pode causar problemas em alguns modelos (como regressão linear). A solução é geralmente dropar uma das colunas (drop='first').

Exemplo Prático com Scikit-learn (OneHotEncoder)

Vamos usar a classe OneHotEncoder do Scikit-learn.

import pandas as pd
from sklearn.preprocessing import OneHotEncoder
 
# Reutilizando o DataFrame original
data = {
    'Tamanho': ['P', 'M', 'G', 'P', 'G', 'M', 'P', 'GG'],
    'Cor': ['Vermelho', 'Azul', 'Verde', 'Azul', 'Vermelho', 'Verde', 'Vermelho', 'Azul'],
    'Preco': [50, 60, 70, 55, 75, 65, 52, 80]
}
df = pd.DataFrame(data)
 
print("DataFrame Original:")
print(df)
print("-" * 30)
 
# 1. Criando uma instância do OneHotEncoder
# handle_unknown='ignore': Ignora categorias não vistas durante o fit, atribuindo 0s.
#                          Útil em produção para evitar erros se novas categorias aparecerem.
# sparse_output=False: Retorna um array denso em vez de uma matriz esparsa (mais fácil de visualizar).
# drop='first': Remove a primeira categoria de cada feature para evitar multicolinearidade.
one_hot_encoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop='first')
 
# 2. Aplicando One-Hot Encoding à coluna 'Cor' (variável nominal)
# Precisamos passar um array 2D (DataFrame com uma única coluna)
encoded_features = one_hot_encoder.fit_transform(df[['Cor']])
 
# 3. Criando um DataFrame com as novas colunas codificadas
# one_hot_encoder.get_feature_names_out() retorna os nomes das novas colunas
encoded_df = pd.DataFrame(encoded_features, columns=one_hot_encoder.get_feature_names_out(['Cor']))
 
print("\nDataFrame com 'Cor' codificada por One-Hot Encoding:")
print(encoded_df)
print("-" * 30)
 
# 4. Combinando com o DataFrame original (opcional, mas comum)
df_combined = pd.concat([df, encoded_df], axis=1)
# Agora podemos dropar a coluna 'Cor' original se quisermos
df_combined = df_combined.drop('Cor', axis=1)
 
print("\nDataFrame Original com 'Cor' substituída por One-Hot Encoding:")
print(df_combined)

Saída esperada:

DataFrame Original:
  Tamanho       Cor  Preco
0       P  Vermelho     50
1       M      Azul     60
2       G     Verde     70
3       P      Azul     55
4       G  Vermelho     75
5       M     Verde     65
6       P  Vermelho     52
7      GG      Azul     80
------------------------------

DataFrame com 'Cor' codificada por One-Hot Encoding:
   Cor_Verde  Cor_Vermelho
0        0.0           1.0
1        0.0           0.0
2        1.0           0.0
3        0.0           0.0
4        0.0           1.0
5        1.0           0.0
6        0.0           1.0
7        0.0           0.0
------------------------------

DataFrame Original com 'Cor' substituída por One-Hot Encoding:
  Tamanho  Preco  Cor_Verde  Cor_Vermelho
0       P     50        0.0           1.0
1       M     60        0.0           0.0
2       G     70        1.0           0.0
3       P     55        0.0           0.0
4       G     75        0.0           1.0
5       M     65        1.0           0.0
6       P     52        0.0           1.0
7      GG     80        0.0           0.0

Observação: Perceba que com drop='first', a coluna Cor_Azul não foi criada. Se Cor_Verde=0 e Cor_Vermelho=0, isso implica que a cor é Azul. Isso evita a multicolinearidade.

🤝 Integração: Combinando Ambas as Técnicas

É muito comum em um projeto de Machine Learning que seu dataset tenha variáveis categóricas tanto ordinais quanto nominais. Nesses casos, você aplicará a técnica mais adequada para cada coluna.

Vamos aplicar o LabelEncoder para 'Tamanho' e o OneHotEncoder para 'Cor' no mesmo DataFrame.

import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
 
# DataFrame original
data = {
    'Tamanho': ['P', 'M', 'G', 'P', 'G', 'M', 'P', 'GG'],
    'Cor': ['Vermelho', 'Azul', 'Verde', 'Azul', 'Vermelho', 'Verde', 'Vermelho', 'Azul'],
    'Preco': [50, 60, 70, 55, 75, 65, 52, 80],
    'Avaliacao_Cliente': ['Ruim', 'Bom', 'Excelente', 'Regular', 'Bom', 'Ruim', 'Excelente', 'Regular']
}
df = pd.DataFrame(data)
 
print("DataFrame Original:")
print(df)
print("-" * 50)
 
# --- 1. Label Encoding para 'Tamanho' (Ordinal) ---
label_encoder_tamanho = LabelEncoder()
df['Tamanho_Encoded'] = label_encoder_tamanho.fit_transform(df['Tamanho'])
print("\nMapeamento de Tamanho:", dict(zip(label_encoder_tamanho.classes_, label_encoder_tamanho.transform(label_encoder_tamanho.classes_))))
 
# --- 2. Label Encoding para 'Avaliacao_Cliente' (Ordinal) ---
# Aqui, a ordem alfabética padrão do LabelEncoder pode não ser a que queremos.
# Para ter controle sobre a ordem, poderíamos usar OrdinalEncoder ou mapeamento manual.
# Para este exemplo, vamos usar LabelEncoder e aceitar a ordem padrão.
label_encoder_avaliacao = LabelEncoder()
df['Avaliacao_Encoded'] = label_encoder_avaliacao.fit_transform(df['Avaliacao_Cliente'])
print("\nMapeamento de Avaliação (padrão LabelEncoder):", dict(zip(label_encoder_avaliacao.classes_, label_encoder_avaliacao.transform(label_encoder_avaliacao.classes_))))
 
 
# --- 3. One-Hot Encoding para 'Cor' (Nominal) ---
one_hot_encoder_cor = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop='first')
encoded_cor_features = one_hot_encoder_cor.fit_transform(df[['Cor']])
encoded_cor_df = pd.DataFrame(encoded_cor_features, columns=one_hot_encoder_cor.get_feature_names_out(['Cor']))
 
# --- 4. Combinando tudo ---
# Primeiro, dropamos as colunas categóricas originais que foram codificadas
df_processed = df.drop(columns=['Tamanho', 'Cor', 'Avaliacao_Cliente'])
 
# Depois, concatenamos as colunas One-Hot Encoded
df_final = pd.concat([df_processed, encoded_cor_df], axis=1)
 
print("\nDataFrame Final Após Codificação:")
print(df_final)

Saída esperada:

DataFrame Original:
  Tamanho       Cor  Preco Avaliacao_Cliente
0       P  Vermelho     50              Ruim
1       M      Azul     60               Bom
2       G     Verde     70         Excelente
3       P      Azul     55           Regular
4       G  Vermelho     75               Bom
5       M     Verde     65              Ruim
6       P  Vermelho     52         Excelente
7      GG      Azul     80           Regular
--------------------------------------------------

Mapeamento de Tamanho: {'G': 0, 'GG': 1, 'M': 2, 'P': 3}

Mapeamento de Avaliação (padrão LabelEncoder): {'Bom': 0, 'Excelente': 1, 'Regular': 2, 'Ruim': 3}

DataFrame Final Após Codificação:
   Preco  Tamanho_Encoded  Avaliacao_Encoded  Cor_Verde  Cor_Vermelho
0     50                3                  3        0.0           1.0
1     60                2                  0        0.0           0.0
2     70                0                  1        1.0           0.0
3     55                3                  2        0.0           0.0
4     75                0                  0        0.0           1.0
5     65                2                  3        1.0           0.0
6     52                3                  1        0.0           1.0
7     80                1                  2        0.0           0.0

Neste exemplo, você pode ver como diferentes estratégias de codificação foram aplicadas a diferentes tipos de variáveis categóricas dentro do mesmo pipeline de pré-processamento.

🛠️ Exercícios/Desafios Práticos

É hora de colocar a mão na massa! 💪

Cenário: Análise de Dados de Imóveis 🏠

Você recebeu um conjunto de dados simplificado de imóveis e precisa prepará-lo para um modelo de Machine Learning.

Dataset:

import pandas as pd
data_imoveis = {
    'Bairro': ['Centro', 'Jardins', 'Centro', 'Pinheiros', 'Jardins', 'Centro', 'Pinheiros', 'Centro'],
    'Tipo_Imovel': ['Apartamento', 'Casa', 'Apartamento', 'Studio', 'Casa', 'Studio', 'Apartamento', 'Casa'],
    'Qualidade_Acabamento': ['Boa', 'Excelente', 'Regular', 'Boa', 'Excelente', 'Regular', 'Boa', 'Regular'],
    'Num_Quartos': [2, 3, 1, 1, 4, 1, 2, 3],
    'Preco_Venda': [300000, 800000, 200000, 350000, 950000, 280000, 400000, 600000]
}
df_imoveis = pd.DataFrame(data_imoveis)

Tarefas:

  • 1. Carregar o DataFrame: Crie o DataFrame df_imoveis a partir dos dados fornecidos.
  • 2. Análise Inicial:
    • Exiba as primeiras 5 linhas do DataFrame.
    • Verifique os tipos de dados de cada coluna (df.info()).
    • Identifique quais colunas são categóricas e classifique-as como nominais ou ordinais.
  • 3. Codificação de Variáveis Ordinais:
    • Escolha a coluna categórica ordinal identificada.
    • Utilize o LabelEncoder para codificá-la.
    • Crie uma nova coluna no DataFrame para a versão codificada (e.g., Qualidade_Acabamento_Encoded).
    • Exiba o mapeamento gerado pelo LabelEncoder (classes originais vs. números).
    • Desafio Extra: Se a ordem padrão do LabelEncoder não for a ideal para sua variável ordinal, como você poderia ajustar isso (dica: OrdinalEncoder ou mapeamento manual)? Não precisa implementar, apenas pensar na estratégia.
  • 4. Codificação de Variáveis Nominais:
    • Escolha as colunas categóricas nominais identificadas.
    • Utilize o OneHotEncoder para codificá-las. Lembre-se de configurar handle_unknown='ignore' e drop='first' para robustez e para evitar multicolinearidade.
    • Crie um novo DataFrame apenas com as colunas One-Hot Encoded.
    • Exiba as primeiras linhas deste novo DataFrame.
  • 5. Combinar o DataFrame Final:
    • Remova as colunas categóricas originais do df_imoveis.
    • Concatene o DataFrame resultante com o DataFrame das colunas One-Hot Encoded.
    • Exiba as primeiras linhas do DataFrame final, que agora deve conter apenas variáveis numéricas (e as colunas originais numéricas).
# Seu código começa aqui!
import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
 
# 1. Carregar o DataFrame
data_imoveis = {
    'Bairro': ['Centro', 'Jardins', 'Centro', 'Pinheiros', 'Jardins', 'Centro', 'Pinheiros', 'Centro'],
    'Tipo_Imovel': ['Apartamento', 'Casa', 'Apartamento', 'Studio', 'Casa', 'Studio', 'Apartamento', 'Casa'],
    'Qualidade_Acabamento': ['Boa', 'Excelente', 'Regular', 'Boa', 'Excelente', 'Regular', 'Boa', 'Regular'],
    'Num_Quartos': [2, 3, 1, 1, 4, 1, 2, 3],
    'Preco_Venda': [300000, 800000, 200000, 350000, 950000, 280000, 400000, 600000]
}
df_imoveis = pd.DataFrame(data_imoveis)
 
print("--- Tarefa 1 & 2: DataFrame Original e Análise Inicial ---")
print(df_imoveis.head())
print("\nInformações do DataFrame:")
df_imoveis.info()
 
# Classificação das variáveis categóricas:
# Bairro: Nominal
# Tipo_Imovel: Nominal
# Qualidade_Acabamento: Ordinal (Regular < Boa < Excelente)
 
print("\n--- Tarefa 3: Codificação de Variáveis Ordinais ---")
# Codificar 'Qualidade_Acabamento'
label_encoder_qualidade = LabelEncoder()
df_imoveis['Qualidade_Acabamento_Encoded'] = label_encoder_qualidade.fit_transform(df_imoveis['Qualidade_Acabamento'])
 
print("\nMapeamento de Qualidade_Acabamento:", dict(zip(label_encoder_qualidade.classes_, label_encoder_qualidade.transform(label_encoder_qualidade.classes_))))
# Note que o LabelEncoder ordenou alfabeticamente: Boa=0, Excelente=1, Regular=2.
# Se quiséssemos Regular=0, Boa=1, Excelente=2, precisaríamos de OrdinalEncoder com a ordem explícita.
# Por enquanto, vamos seguir com o LabelEncoder para simplificar o exercício.
 
print("\nDataFrame com Qualidade_Acabamento codificada:")
print(df_imoveis.head())
 
print("\n--- Tarefa 4: Codificação de Variáveis Nominais ---")
# Codificar 'Bairro' e 'Tipo_Imovel'
one_hot_encoder_nominal = OneHotEncoder(handle_unknown='ignore', sparse_output=False, drop='first')
 
# Aplicar One-Hot Encoding às colunas nominais
encoded_nominal_features = one_hot_encoder_nominal.fit_transform(df_imoveis[['Bairro', 'Tipo_Imovel']])
 
# Criar DataFrame com as colunas One-Hot Encoded
encoded_nominal_df = pd.DataFrame(encoded_nominal_features, columns=one_hot_encoder_nominal.get_feature_names_out(['Bairro', 'Tipo_Imovel']))
 
print("\nDataFrame apenas com colunas One-Hot Encoded:")
print(encoded_nominal_df.head())
 
print("\n--- Tarefa 5: Combinar o DataFrame Final ---")
# Remover as colunas categóricas originais
df_processed = df_imoveis.drop(columns=['Bairro', 'Tipo_Imovel', 'Qualidade_Acabamento'])
 
# Concatenar com as colunas One-Hot Encoded
df_final = pd.concat([df_processed, encoded_nominal_df], axis=1)
 
print("\nDataFrame Final Após Todas as Codificações:")
print(df_final.head())

📝 Resumo e Próximos Passos

Parabéns! 🎉 Você deu um grande passo para entender como lidar com variáveis categóricas, um desafio comum no pré-processamento de dados.

Pontos Chave:

  • Label Encoding: Ideal para variáveis ordinais, atribui um número inteiro a cada categoria. Cuidado para não introduzir ordem artificial em dados nominais.
  • One-Hot Encoding: Ideal para variáveis nominais, cria novas colunas binárias para cada categoria. Cuidado com a alta cardinalidade e a multicolinearidade (usando drop='first').
  • Scikit-learn: Oferece ferramentas robustas (LabelEncoder, OneHotEncoder) para implementar essas técnicas de forma eficiente.

Onde ir a seguir?

  1. OrdinalEncoder: Explore o OrdinalEncoder do Scikit-learn para ter controle explícito sobre a ordem das categorias em variáveis ordinais.
  2. Outras Técnicas de Codificação: Para casos mais complexos (como alta cardinalidade), pesquise sobre:
    • Target Encoding / Mean Encoding: Codifica categorias com base na média da variável alvo.
    • Frequency Encoding: Codifica categorias com base em sua frequência no dataset.
    • Hashing Encoding: Transforma categorias em um número fixo de colunas usando uma função hash.
  3. Pipelines de Pré-processamento: Aprenda a combinar várias etapas de pré-processamento (como codificação, escalonamento, tratamento de nulos) em um Pipeline do Scikit-learn para um fluxo de trabalho mais organizado e robusto.

Continue praticando e explorando! A manipulação de dados é uma habilidade fundamental para qualquer cientista ou engenheiro de Machine Learning. 🚀

© 2025 Escola All Dev. Todos os direitos reservados.

Codificação de Variáveis Categóricas: One-Hot Encoding e Label Encoding (Documentação Scikit-learn) - Fundamentos do Machine Learning com Python | escola.all.dev.br