Como normalizar dados com scikit-learn em Machine Learning
Normalizar dados é um dos passos mais importantes do pré-processamento em Machine Learning. Quando as variáveis têm escalas muito diferentes — por exemplo, idade entre 0 e 100 e salário entre 0 e 100000 — algoritmos como o KNN, a regressão logística ou as redes neuronais tendem a dar mais peso às variáveis de maior magnitude, o que prejudica o modelo. Nem todos os algoritmos precisam de escalamento — as árvores de decisão e as florestas aleatórias são indiferentes à escala —, mas para modelos baseados em distância ou em gradientes a normalização é essencial. Aqui vais aprender a normalizar dados com o scikit-learn, usando o StandardScaler e o MinMaxScaler, e a fazê-lo da forma correta: ajustando o scaler apenas com os dados de treino.
Pré-requisitos
- Python 3.9 ou superior instalado.
- As bibliotecas scikit-learn, pandas e NumPy (instala com
pip install scikit-learn pandas numpy). - Saber carregar um conjunto de dados para um DataFrame do pandas.
Passo 1: Perceber a diferença entre padronizar e normalizar
Os dois métodos mais comuns produzem resultados diferentes, por isso convém saber quando usar cada um:
- Padronização (StandardScaler): transforma cada variável para ter média 0 e desvio-padrão 1. É a escolha por defeito para a maioria dos algoritmos e funciona bem quando os dados seguem uma distribuição aproximadamente normal.
- Normalização Min-Max (MinMaxScaler): coloca os valores num intervalo fixo, habitualmente entre 0 e 1. É útil quando precisas de limites conhecidos, por exemplo em redes neuronais ou no processamento de imagem.
A intuição é simples: algoritmos que medem distâncias entre pontos, como o KNN, somam as diferenças de todas as variáveis; se uma delas tiver valores muito maiores, domina o cálculo e as restantes quase não contam. Em ambos os casos, a regra de ouro é a mesma: ajusta o scaler só com os dados de treino e aplica exatamente a mesma transformação aos dados de teste.
Passo 2: Preparar e dividir os dados
Antes de escalar, separa os dados em treino e teste. Assim garantes que a informação do conjunto de teste não influencia o cálculo da média e do desvio-padrão — um erro comum conhecido como data leakage. O random_state serve apenas para tornar a divisão reproduzível.
import pandas as pd
from sklearn.model_selection import train_test_split
# Two features on very different scales
data = pd.DataFrame({
"age": [22, 35, 58, 45, 28, 60, 31],
"salary": [18000, 42000, 95000, 61000, 27000, 88000, 35000]
})
X_train, X_test = train_test_split(data, test_size=0.3, random_state=42)
print(X_train)
Passo 3: Aplicar o StandardScaler
Cria o scaler, ajusta-o com fit nos dados de treino e transforma treino e teste com transform. Repara que o fit nunca é chamado sobre os dados de teste.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
# fit_transform on the training set only
X_train_scaled = scaler.fit_transform(X_train)
# transform (no fit) on the test set
X_test_scaled = scaler.transform(X_test)
print(X_train_scaled)
O fit_transform é apenas um atalho para fit seguido de transform. Ao ser aplicado ao treino, aprende a média e o desvio-padrão de cada coluna e devolve logo os valores padronizados, que passam a variar em torno de 0 (com valores negativos e positivos).
Regra prática: chamafituma única vez, sempre sobre o treino. Os dados de teste só passam portransform.
Passo 4: Alternativa com o MinMaxScaler
Se preferires colocar os valores entre 0 e 1, muda apenas a classe do scaler — a lógica de fit e transform mantém-se igual.
from sklearn.preprocessing import MinMaxScaler
scaler_mm = MinMaxScaler(feature_range=(0, 1))
X_train_mm = scaler_mm.fit_transform(X_train)
X_test_mm = scaler_mm.transform(X_test)
Passo 5: Juntar o scaler a um Pipeline (recomendado)
Em projetos reais, o ideal é juntar o scaler e o modelo num Pipeline. Desta forma, o scaling é sempre aplicado pela ordem certa e evitas repetir código ou esquecer-te de transformar novos dados.
from sklearn.pipeline import Pipeline
from sklearn.neighbors import KNeighborsClassifier
pipeline = Pipeline([
("scaler", StandardScaler()),
("model", KNeighborsClassifier(n_neighbors=3))
])
# pipeline.fit(X_train, y_train) # fits scaler + model in one call
Quando chamas pipeline.fit, o scaler é ajustado apenas com os dados de treino e o modelo recebe já os valores escalados — tudo de forma automática.
Verificar o resultado
Para confirmar que a padronização correu bem, verifica as estatísticas das colunas escaladas do treino. Com o StandardScaler, a média de cada coluna deve ficar muito perto de 0 e o desvio-padrão perto de 1.
import numpy as np
print("Mean:", np.round(X_train_scaled.mean(axis=0), 2))
print("Std:", np.round(X_train_scaled.std(axis=0), 2))
# Mean: [ 0. -0.] Std: [1. 1.]
Se usaste o MinMaxScaler, confirma que, no conjunto de treino, o mínimo de cada coluna é 0 e o máximo é 1. Nos dados de teste é normal surgirem valores ligeiramente fora desse intervalo — isso é esperado e não é um erro.
Conclusão
Já consegues normalizar dados em Machine Learning com o scikit-learn, escolher entre o StandardScaler e o MinMaxScaler e, o mais importante, evitar o data leakage ajustando o scaler apenas no treino. O passo seguinte é colocar este pré-processamento dentro de um Pipeline completo com um modelo e medir o impacto no desempenho. Fica a dica: no teu conjunto de dados, será que a padronização melhora a exatidão do modelo em comparação com os dados em bruto?