Codificação One-Hot

Visão geral

Muitos conjuntos de dados do mundo real contêm variáveis categóricas — atributos cujos valores são rótulos, e não números (por exemplo, city = "Paris", color = "red", browser = "Chrome"). A maioria dos algoritmos de aprendizado de máquina (machine learning), no entanto, opera sobre vetores numéricos. A codificação one-hot (one-hot encoding) é uma técnica padrão de engenharia de atributos (feature engineering) que converte valores categóricos em atributos indicadores binários, permitindo que modelos os consumam sem inventar uma ordenação numérica enganosa.

A codificação one-hot é uma ferramenta central em Engenharia de Atributos, e interage de perto com a escolha do modelo, a divisão dos dados e preocupações como Vazamento.

O que é codificação one-hot?

Dado um atributo categórico com (K) categorias possíveis, a codificação one-hot mapeia cada categoria para um vetor em ({0,1}^K) com exatamente um “1” e o restante “0”.

Se color ∈ {red, green, blue}, a codificação one-hot cria três atributos indicadores:

  • color_red
  • color_green
  • color_blue

e representa:

  • red → [1, 0, 0]
  • green → [0, 1, 0]
  • blue → [0, 0, 1]

Por que funciona

A codificação one-hot tem uma propriedade importante: ela não impõe uma ordem. Compare isso com atribuir red=0, green=1, blue=2, o que implica “blue > green > red” e faz modelos lineares ou baseados em distância se comportarem como se essas categorias estivessem em uma reta numérica.

Formalmente, vetores one-hot correspondem aos vetores da base padrão (standard basis vectors) (e_1, e_2, \dots, e_K). Em modelos lineares, cada categoria recebe seu próprio peso aprendido (em relação a uma referência), o que geralmente é o que queremos.

Quando a codificação one-hot é apropriada?

A codificação one-hot é uma boa escolha padrão quando:

  • O atributo é nominal (sem ordem significativa): país, ID de produto (até certo ponto), tipo de dispositivo etc.
  • Você usa modelos que assumem relações numéricas aproximadamente lineares:
    • regressão linear / regressão logística
    • SVM linear
    • modelos lineares generalizados
    • muitas redes neurais (embora incorporações sejam frequentemente melhores para alta cardinalidade)
  • Você quer uma representação simples e interpretável: em modelos lineares, cada coeficiente corresponde a um indicador de categoria.

Observações específicas por modelo

  • Regressão linear / regressão logística: a codificação one-hot costuma ser a abordagem padrão. Coeficientes são fáceis de interpretar como efeitos de categoria (com uma categoria de referência).
  • Modelos baseados em árvores (árvores de decisão, florestas aleatórias, gradient boosting): podem funcionar com categorias codificadas ordinalmente, mas one-hot ainda é comum. Dependendo da implementação, one-hot pode aumentar a dimensionalidade e o tempo de treinamento; algumas bibliotecas de árvores suportam divisões categóricas nativas.
  • Modelos baseados em distância (k-NN, k-means): one-hot evita ordenação artificial, mas distâncias em espaços esparsos de alta dimensionalidade podem se tornar menos significativas; considere alternativas ou um pré-processamento cuidadoso.
  • Redes neurais: one-hot pode funcionar, mas, para muitas categorias, incorporações aprendidas (learned embeddings) normalmente são mais eficientes em termos de parâmetros.

Um exemplo prático (à mão)

Suponha que você tenha:

user_id plan region
1 free EU
2 pro US
3 free US

A codificação one-hot produz:

user_id plan_free plan_pro region_EU region_US
1 1 0 1 0
2 0 1 0 1
3 1 0 0 1

Essas novas colunas são “flags” binárias que os modelos podem ingerir diretamente.

Implementando codificação one-hot na prática

Pandas: `get_dummies`

import pandas as pd

df = pd.DataFrame({
    "plan": ["free", "pro", "free"],
    "region": ["EU", "US", "US"]
})

encoded = pd.get_dummies(df, columns=["plan", "region"])
print(encoded)

Isso é conveniente para exploração e pipelines pequenos, mas, para aprendizado de máquina em produção, costuma ser mais seguro usar transformadores do scikit-learn para evitar inconsistências entre treino e teste.

Scikit-learn: `OneHotEncoder` (recomendado)

Principais vantagens:

  • Ajusta os mapeamentos de categoria nos dados de treino
  • Pode lidar com categorias desconhecidas no momento da inferência
  • Funciona de forma eficiente com matrizes esparsas
  • Integra-se de maneira limpa com pipelines
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

X = df  # example features
y = [0, 1, 0]  # example labels

categorical = ["plan", "region"]

preprocess = ColumnTransformer(
    transformers=[
        ("cat", OneHotEncoder(handle_unknown="ignore"), categorical)
    ],
    remainder="drop"
)

model = Pipeline(steps=[
    ("preprocess", preprocess),
    ("clf", LogisticRegression(max_iter=1000))
])

model.fit(X, y)

A configuração handle_unknown="ignore" é importante para robustez quando novas categorias aparecem no momento da predição (mais sobre isso abaixo).

A “armadilha das variáveis dummy” e a multicolinearidade

O que é a armadilha das variáveis dummy?

Se uma variável categórica tem (K) categorias e você inclui todas as (K) colunas one-hot mais um intercepto, os atributos se tornam linearmente dependentes:

[ \text{plan_free} + \text{plan_pro} + \dots + \text{plan_enterprise} = 1 ]

Isso cria multicolinearidade perfeita, o que significa que a matriz de projeto não tem posto completo. Em mínimos quadrados ordinários, isso faz com que os coeficientes não sejam identificáveis de forma única; muitos solucionadores derrubarão uma coluna automaticamente ou produzirão estimativas instáveis.

Como evitar

Estratégias comuns:

  • Remover uma categoria por atributo (“codificação de referência”):
    • Pandas: pd.get_dummies(..., drop_first=True)
    • scikit-learn: OneHotEncoder(drop="first")
  • Manter todas as colunas, mas remover o intercepto (menos comum)
  • Confiar em regularização (por exemplo, regressão logística L2) e em um solucionador que lide com deficiência de posto — mas a interpretabilidade ainda fica mais difícil.

Exemplo com scikit-learn:

OneHotEncoder(drop="first", handle_unknown="ignore")

Isso sempre importa?

  • Para muitos modelos baseados em árvores, multicolinearidade é menos um problema conceitual do que para regressão linear, mas remover um nível ainda pode reduzir redundância.
  • Para modelos lineares, é uma boa prática evitar colinearidade perfeita se você quer coeficientes estáveis e interpretáveis.

Armadilhas comuns

1) Alta cardinalidade (categorias demais)

Se um atributo tem milhares (ou milhões) de valores únicos — como user_id, product_sku ou zip_code bruto — a codificação one-hot pode explodir o espaço de atributos:

  • Memória: a matriz fica enorme (mesmo que esparsa).
  • Computação: treinamento e inferência ficam mais lentos.
  • Sobreajuste (overfitting): categorias raras podem receber pesos pouco confiáveis, especialmente em modelos lineares.

Mitigações

  • Agrupar categorias raras em um bucket "other" (limiar por frequência).
  • Usar hashing (o “hashing trick”) para mapear categorias em um número fixo de bins.
  • Usar codificação por alvo ou incorporações (com controle cuidadoso de vazamento).
  • Considerar se o atributo deve ser usado (veja Seleção de Atributos).

2) Incompatibilidades de categorias entre treino/teste (categorias não vistas)

Um bug clássico em produção: uma categoria aparece em validação/teste/inferência que nunca apareceu no treino. Por exemplo, o treino vê region ∈ {EU, US}, mas a inferência vê region="APAC".

O que acontece depende das suas ferramentas:

  • One-hot ingênuo com um conjunto fixo de colunas pode dar erro ou desalinha colunas silenciosamente.
  • Se você ajustar codificadores separadamente em treino e teste, você pode acabar com ordenações diferentes de colunas, o que é catastrófico.

Boas práticas

  • Ajuste o codificador apenas nos dados de treino, e então reutilize-o para validação/teste.
  • Use um pipeline para que o pré-processamento fique acoplado ao modelo.
  • No scikit-learn, defina:
OneHotEncoder(handle_unknown="ignore")

Isso codifica categorias não vistas como todos zeros no bloco one-hot desse atributo. Em algumas aplicações, você pode preferir modelar explicitamente “desconhecido” adicionando uma categoria "__UNK__" durante o pré-processamento.

3) Matrizes esparsas e incompatibilidades a jusante

Matrizes codificadas com one-hot são tipicamente esparsas (a maioria dos valores é zero). Muitas bibliotecas de aprendizado de máquina lidam com entradas esparsas com eficiência, mas algumas etapas podem densificar a matriz e explodir o uso de memória.

Fique atento a:

  • algoritmos ou transformadores que exigem arrays densos
  • chamadas acidentais de .toarray() em dados enormes
  • etapas de escalonamento de atributos que densificam

No scikit-learn, muitos modelos lineares funcionam bem com entradas esparsas; sempre verifique se o estimador escolhido suporta matrizes esparsas.

4) Tratar valores ausentes incorretamente

Valores ausentes em categorias precisam de tratamento explícito:

  • Você pode tratar o ausente como sua própria categoria (por exemplo, "__MISSING__")
  • Ou imputar a partir dos dados (moda/mais frequente)

No scikit-learn, OneHotEncoder pode tratar None/np.nan como uma categoria em versões mais novas, mas o comportamento depende do tipo de entrada; em pipelines robustos, considere imputação explícita com Imputação (Tratamento de Valores Ausentes).

5) Vazamento com codificações “espertas”

A codificação one-hot em si não é inerentemente sujeita a vazamento, mas o processo pode ser:

  • Ajustar codificadores no conjunto completo antes de dividir pode vazar informação distribucional (geralmente pequeno, mas ainda evitável).
  • Algumas alternativas (notavelmente codificação por alvo) podem vazar informação do rótulo de forma grave se não forem feitas corretamente (veja Vazamento).

Use divisão adequada de treino/validação e pipelines.

Visão teórica: codificação one-hot em modelos lineares

Considere regressão logística com indicadores categóricos codificados com one-hot. Suponha que plan tenha categorias {free, pro, enterprise} e você remova free como referência. O modelo é:

[ \log\frac{p(y=1)}{1-p(y=1)} = b + w_{\text{pro}} \cdot I(\text{plan=pro}) + w_{\text{enterprise}} \cdot I(\text{plan=enterprise}) + \dots ]

Interpretação:

  • (b) é o log-odds de base para free (mantendo os outros atributos fixos).
  • (w_{\text{pro}}) é a mudança no log-odds ao passar de free para pro.

Esse é um dos motivos pelos quais a codificação one-hot é popular: ela produz efeitos limpos no nível de categoria.

Variantes: one-hot vs multi-hot

O one-hot padrão assume exatamente uma categoria por exemplo (por exemplo, um único país).

Se um atributo pode conter múltiplos rótulos ao mesmo tempo (por exemplo, interesses do usuário: {sports, music, travel}), normalmente você usa uma representação multi-hot (também chamada binarização multi-rótulo): múltiplos 1s podem aparecer no vetor. A ideia é semelhante (indicadores binários), mas a semântica dos dados é diferente.

Alternativas à codificação one-hot

A codificação one-hot nem sempre é a melhor escolha. Alternativas comuns incluem:

Codificação ordinal

A codificação ordinal (ordinal encoding) mapeia categorias para inteiros: small=0, medium=1, large=2.

  • Apropriada quando categorias têm uma ordem real (nível de escolaridade, faixas de tamanho).
  • Frequentemente usada com modelos de árvore, especialmente se a ordem for significativa.
  • Arriscada para categorias nominais: introduz uma ordenação artificial.

No scikit-learn, veja OrdinalEncoder.

Codificação por alvo (mean encoding)

A codificação por alvo (target encoding) substitui uma categoria por uma estatística do rótulo, como:

  • classificação: (E[y \mid \text{category}])
  • regressão: média do alvo por categoria

Prós:

  • Lida com alta cardinalidade de forma eficiente (um atributo numérico em vez de milhares).
  • Pode melhorar desempenho para modelos poderosos com poucos dados.

Contras / principal armadilha:

  • Extremamente propensa a vazamento do alvo (target leakage) se calculada usando o rótulo do próprio ponto de dados.
  • Deve ser feita com esquemas cuidadosos de validação cruzada (por exemplo, codificação K-fold out-of-fold) e suavização/regularização.

A codificação por alvo deve fazer parte de um pipeline consciente de vazamento; veja Vazamento.

Hashing trick (feature hashing)

Mapeia categorias em um vetor de tamanho fixo usando uma função de hash.

Prós:

  • Memória constante em relação ao número de categorias
  • Lida naturalmente com categorias não vistas
  • Rápido

Contras:

  • Colisões: categorias diferentes podem mapear para o mesmo índice de atributo
  • Mais difícil de interpretar

Útil para sinais categóricos semelhantes a texto e atributos de cardinalidade muito alta.

Incorporações aprendidas

Comuns em aprendizado profundo e sistemas de recomendação:

  • Cada categoria recebe um vetor denso aprendido (incorporação).
  • Muito mais compacto que one-hot para alta cardinalidade.
  • Pode capturar similaridade entre categorias.

Desvantagens:

  • Exige mais complexidade de modelagem e treinamento cuidadoso
  • Menos transparente que one-hot para interpretação

Orientação prática e boas práticas

Escolhendo uma estratégia de codificação

Uma regra prática razoável:

  • Atributos nominais de baixa a moderada cardinalidade: one-hot
  • Categorias ordenadas: codificação ordinal
  • Cardinalidade muito alta: hashing / codificação por alvo (com controles de vazamento) / incorporações
  • IDs sem significado semântico: frequentemente é melhor excluir ou tratar via modelos especializados (por exemplo, incorporações em sistemas de recomendação)

Boas práticas de pipeline (scikit-learn)

  • Sempre divida os dados primeiro; ajuste o pré-processamento apenas no treino.
  • Use Pipeline + ColumnTransformer para manter transformações consistentes.
  • Use handle_unknown="ignore" para evitar falhas na inferência.
  • Considere drop="first" para modelos lineares com intercepto para evitar colunas redundantes.

Exemplo combinando numérico + categórico:

import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

X = pd.DataFrame({
    "age": [25, np.nan, 40],
    "plan": ["free", "pro", "free"],
    "region": ["EU", "US", "US"]
})
y = [0, 1, 0]

numeric_features = ["age"]
categorical_features = ["plan", "region"]

numeric_pipe = Pipeline([
    ("impute", SimpleImputer(strategy="median")),
    ("scale", StandardScaler())
])

categorical_pipe = Pipeline([
    ("impute", SimpleImputer(strategy="most_frequent")),
    ("ohe", OneHotEncoder(handle_unknown="ignore", drop="first"))
])

preprocess = ColumnTransformer([
    ("num", numeric_pipe, numeric_features),
    ("cat", categorical_pipe, categorical_features)
])

clf = Pipeline([
    ("prep", preprocess),
    ("model", LogisticRegression(max_iter=1000))
])

clf.fit(X, y)

Esse desenho também funciona bem com validação cruzada e reduz o risco de vazamento acidental.

Lidando com categorias raras

Se as categorias têm uma cauda longa, one-hot pode criar muitas colunas que aparecem apenas algumas vezes, aumentando o risco de sobreajuste.

Táticas comuns:

  • Combinar categorias raras em "other" com base em um limiar de frequência.
  • Usar regularização (L1/L2) em modelos lineares para amortecer pesos ruidosos.
  • Considerar codificação por alvo com suavização se a cardinalidade for alta e o vazamento estiver controlado.

Resumo

A codificação one-hot converte variáveis categóricas em atributos indicadores binários para que modelos de aprendizado de máquina possam usá-las sem impor uma ordem artificial. Ela é amplamente aplicável e especialmente eficaz para categorias nominais em modelos lineares, mas traz armadilhas práticas:

  • Alta cardinalidade pode causar explosão de dimensionalidade e sobreajuste.
  • A armadilha das variáveis dummy pode introduzir multicolinearidade perfeita (normalmente resolvida removendo um nível por atributo).
  • Incompatibilidades entre treino/teste podem quebrar a inferência, a menos que você ajuste codificadores nos dados de treino e lide com categorias desconhecidas.
  • Algumas alternativas — especialmente codificação por alvo — podem trazer resultados fortes, mas devem ser implementadas com cuidado para evitar Vazamento.

Na maioria dos fluxos de trabalho aplicados, a codificação one-hot continua sendo uma linha de base forte — desde que você use pipelines robustos, gerencie cardinalidade e escolha estratégias de codificação alinhadas tanto aos dados quanto ao modelo.