Engenharia de Features
A engenharia de features transforma colunas brutas em representações que os modelos podem aprender. Codificar categóricas, escalar numéricas e compor transformações com ColumnTransformer são os padrões centrais para ML tabular.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
preprocessor = ColumnTransformer([
("num", StandardScaler(), numeric_cols),
("cat", OneHotEncoder(handle_unknown="ignore"), categorical_cols),
])
pipe = Pipeline([("prep", preprocessor), ("clf", RandomForestClassifier())])Quando usar isso:
- Colunas numéricas e categóricas mistas no mesmo conjunto de dados.
- Modelos sensíveis à escala das features (SVM, regressão logística, redes neurais em dados tabulares).
- Categóricas de alta cardinalidade que necessitam de hashing ou codificação de destino (target encoding).
- Pré-processamento reproduzível, agrupado com o modelo para implantação.
Exemplo de Trabalho
"""feature_engineering.py - pré-processamento de tipos mistos com ColumnTransformer."""
from __future__ import annotations
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
df = pd.DataFrame({
"age": [25, 34, 45, 29, 52],
"income": [45000, 62000, 88000, 51000, 95000],
"city": ["nyc", "la", "nyc", "chicago", "la"],
"plan": ["basic", "pro", "pro", "basic", "enterprise"],
"churned": [0, 0, 1, 0, 1],
})
X = df.drop(columns=["churned"])
y = df["churned"]
numeric_cols = ["age", "income"]
categorical_cols = ["city", "plan"]
preprocessor = ColumnTransformer(
transformers=[
("num", StandardScaler(), numeric_cols),
("cat", OneHotEncoder(handle_unknown="ignore", sparse_output=False), categorical_cols),
],
remainder="drop",
)
pipe = Pipeline([
("prep", preprocessor),
("clf", GradientBoostingClassifier(random_state=42)),
])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)
pipe.fit(X_train, y_train)
print(classification_report(y_test, pipe.predict(X_test)))O que isso demonstra:
- Diferentes transformações aplicadas a grupos de colunas numéricas e categóricas.
OneHotEncodercomhandle_unknown="ignore"para segurança em produção.sparse_output=Falsepara saída densa compatível com modelos de árvore e lineares.- Serialização completa do pipeline - o pré-processamento acompanha o classificador.
Mergulho Profundo
Como Funciona
- Escalonamento centraliza e escala colunas numéricas para que modelos baseados em gradiente convirjam mais rapidamente.
- Codificação one-hot expande categóricas em colunas indicadoras binárias por categoria.
- ColumnTransformer executa cada sub-transformador em suas colunas designadas e concatena os resultados.
- Pipelines chamam
fitem dados de treinamento por fold de CV, prevenindo vazamento de estatísticas. - Nomes de features podem ser recuperados com
get_feature_names_out()após o ajuste.
Transformações Comuns
| Transformação | Tipo de Coluna | Classe sklearn |
|---|---|---|
| Escalonamento Padrão | Numérico | StandardScaler |
| Escalonamento Min-Max | Numérico limitado | MinMaxScaler |
| Transformação Log | Numérico assimétrico | FunctionTransformer(np.log1p) |
| One-hot | Categórica de baixa cardinalidade | OneHotEncoder |
| Ordinal | Categorias ordenadas | OrdinalEncoder |
| Imputação | Valores ausentes | SimpleImputer |
Notas Python
from sklearn.preprocessing import FunctionTransformer
import numpy as np
log_transform = FunctionTransformer(np.log1p, validate=False)
# Encadear imputação antes do escalonamento no ramo numérico:
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline as SkPipeline
numeric_pipe = SkPipeline([
("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
])Armadilhas
- Ajustar em dados completos - calcular média/std ou listas de categorias a partir de linhas de teste vaza informações. Correção: ajustar dentro de um pipeline apenas em folds de treinamento.
- Categorias não vistas na inferência - novos valores de categoria travam um
OneHotEncodersimples. Correção:handle_unknown="ignore"ouhandle_unknown="infrequent_if_exist". - Vazamento de codificação de destino (target encoding) - codificar categorias com a média do destino usando todos os dados infla as pontuações de CV. Correção: usar
TargetEncoderdentro de um pipeline com CV adequado. - Escalonamento desnecessário para modelos de árvore - florestas aleatórias e gradient boosting são invariantes à escala. Correção: pular o escalonamento para ensembles de árvores; ainda codificar categóricas.
- One-hot de alta cardinalidade - milhares de colunas dummy desaceleram o treinamento e causam overfitting. Correção: hashing (
FeatureHasher), codificação de frequência ou embeddings. - Explosão polinomial -
PolynomialFeatures(degree=3)em 20 colunas cria milhares de features. Correção: limitar o grau, usar seleção de features ou modo apenas de interação.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
ColumnTransformer | Tipos de coluna mistos em um modelo | Todas as colunas são do mesmo tipo (usar um único transformador) |
pandas.get_dummies | EDA rápida em notebooks | Pipelines de produção (não serializável, sem tratamento de desconhecidos) |
| Codificação de destino (Target encoding) | Categóricas de alta cardinalidade com dados suficientes | Conjuntos de dados pequenos (risco severo de overfitting) |
| Hashing de features | Cardinalidade muito alta, restrições de memória | Você precisa de nomes de features interpretáveis |
FAQs
Por que usar ColumnTransformer em vez de operações manuais do pandas?
- Serializável com
joblibpara implantação. - Integra-se com
Pipelinee validação cruzada sem vazamento. - Lida com categorias desconhecidas e valores ausentes de forma consistente na inferência.
Devo escalar features para RandomForest?
- Modelos de árvore dividem por ordem de classificação - o escalonamento não altera as divisões.
- Ainda codifique categóricas e impute valores ausentes.
- Escalone para regressão logística, SVM e k-NN no mesmo conjunto de dados.
Como obtenho os nomes das features após a codificação one-hot?
pipe.fit(X_train, y_train)
names = pipe.named_steps["prep"].get_feature_names_out()
print(list(names))- Nomes seguem o padrão
cat__city_nyc,num__age.
O que significa remainder="drop"?
- Colunas não listadas em nenhum transformador são descartadas.
- Use
remainder="passthrough"para manter colunas não listadas como estão. - Listas explícitas de colunas evitam a inclusão acidental de colunas de ID.
Como lidar com valores ausentes?
from sklearn.impute import SimpleImputer
num_pipe = Pipeline([("impute", SimpleImputer(strategy="median")), ("scale", StandardScaler())])- Impute antes de escalar - o escalonamento em colunas NaN falha.
strategy="most_frequent"funciona para imputação categórica comSimpleImputer+ dtype string.
Quando devo usar OrdinalEncoder vs OneHotEncoder?
- Ordinal para categorias com ordem natural (baixo/médio/alto).
- One-hot para categorias nominais sem ordenação (nomes de cidades).
- Modelos de árvore lidam com ordinais codificados como rótulos; modelos lineares preferem one-hot.
Posso aplicar funções personalizadas do pandas?
- Use
FunctionTransformerpara envolver qualquer função compatível com numpy. - Evite closures que capturam estado externo - elas quebram a serialização.
- Prefira os built-ins do sklearn quando disponíveis.
Como engenheirar features de data?
df["order_year"] = df["order_date"].dt.year
df["order_dow"] = df["order_date"].dt.dayofweek- Extraia ano, mês, dia da semana, é fim de semana como colunas numéricas.
- Remova a coluna datetime bruta das entradas do modelo.
E quanto às colunas de texto?
- ML Clássico:
TfidfVectorizerem um branchColumnTransformer. - Era LLM: pré-calcule embeddings e armazene como colunas numéricas.
- Veja Embeddings & Similaridade para features baseadas em embeddings.
Como prevenir vazamento de dados com codificação de destino?
- Nunca calcule médias de destino usando o conjunto de dados completo antes de dividir.
- Use
category_encoders.TargetEncoderdentro de umPipelinecom CV. - Ou calcule as codificações apenas dentro de cada fold de CV.
Devo normalizar ou padronizar?
- Padronize (
StandardScaler) quando as features tiverem unidades e escalas diferentes. - Normalize (
MinMaxScaler) quando precisar de entradas limitadas a [0,1]. - RobustScaler para conjuntos de dados com outliers.
Como inspecionar a forma da saída transformada?
Xt = preprocessor.fit_transform(X_train)
print(Xt.shape) # linhas x total de features codificadas- One-hot expande colunas: 3 categorias se tornam 3 colunas binárias.
Relacionados
- Pipelines - encadeando transformações e modelos
- Datasets & Divisões - ajustar transformações apenas em treino
- Aprendizado Supervisionado - necessidades de pré-processamento específicas do modelo
- Dados Desbalanceados - reamostragem dentro de pipelines
- Gradient Boosting - modelos de árvore e categóricas
Versões da Stack: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.