Cómo normalizar datos con scikit-learn en Machine Learning
Normalizar datos es uno de los pasos de preprocesamiento más importantes en Machine Learning. Cuando las variables están en escalas muy distintas — por ejemplo, edad entre 0 y 100 y salario entre 0 y 100000 — algoritmos como KNN, la regresión logística o las redes neuronales tienden a dar más peso a las variables de mayor magnitud, lo que perjudica al modelo. No todos los algoritmos necesitan escalado — los árboles de decisión y los bosques aleatorios son indiferentes a la escala —, pero para modelos basados en distancia o en gradientes la normalización es esencial. Aquí aprenderás a normalizar datos con scikit-learn, usando StandardScaler y MinMaxScaler, y a hacerlo de la forma correcta: ajustando el scaler solo con los datos de entrenamiento.
Requisitos previos
- Python 3.9 o superior instalado.
- Las librerías scikit-learn, pandas y NumPy (instala con
pip install scikit-learn pandas numpy). - Saber cargar un conjunto de datos en un DataFrame de pandas.
Paso 1: Entender la diferencia entre estandarizar y normalizar
Los dos métodos más habituales producen resultados diferentes, así que conviene saber cuándo usar cada uno:
- Estandarización (StandardScaler): transforma cada variable para que tenga media 0 y desviación típica 1. Es la opción por defecto para la mayoría de los algoritmos y funciona bien cuando los datos siguen una distribución aproximadamente normal.
- Normalización Min-Max (MinMaxScaler): coloca los valores en un rango fijo, normalmente entre 0 y 1. Es útil cuando necesitas límites conocidos, por ejemplo en redes neuronales o en el procesamiento de imágenes.
La intuición es sencilla: los algoritmos que miden distancias entre puntos, como KNN, suman las diferencias de todas las variables; si una tiene valores mucho mayores, domina el cálculo y las demás apenas cuentan. En ambos casos, la regla de oro es la misma: ajusta el scaler solo con los datos de entrenamiento y aplica exactamente la misma transformación a los datos de prueba.
Paso 2: Preparar y dividir los datos
Antes de escalar, separa los datos en entrenamiento y prueba. Así te aseguras de que la información del conjunto de prueba no influya en el cálculo de la media y la desviación típica — un error frecuente conocido como data leakage. El random_state solo sirve para que la división sea reproducible.
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)
Paso 3: Aplicar el StandardScaler
Crea el scaler, ajústalo con fit sobre los datos de entrenamiento y transforma ambos conjuntos con transform. Fíjate en que fit nunca se llama sobre los datos de prueba.
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)
El método fit_transform es solo un atajo para fit seguido de transform. Aplicado al entrenamiento, aprende la media y la desviación típica de cada columna y devuelve directamente los valores estandarizados, que ahora varían alrededor de 0 (con números negativos y positivos).
Regla práctica: llama afituna sola vez, siempre sobre el entrenamiento. Los datos de prueba solo pasan portransform.
Paso 4: Alternativa con el MinMaxScaler
Si prefieres llevar los valores a un rango de 0 a 1, cambia solo la clase del scaler — la lógica de fit y transform se mantiene 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)
Paso 5: Integrar el scaler en un Pipeline (recomendado)
En proyectos reales, lo ideal es combinar el scaler y el modelo en un Pipeline. De este modo, el escalado siempre se aplica en el orden correcto y evitas repetir código u olvidarte de transformar datos nuevos.
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
Cuando llamas a pipeline.fit, el scaler se ajusta solo con los datos de entrenamiento y el modelo ya recibe los valores escalados — todo de forma automática.
Verificar el resultado
Para confirmar que la estandarización funcionó, revisa las estadísticas de las columnas escaladas del entrenamiento. Con StandardScaler, la media de cada columna debe quedar muy cerca de 0 y la desviación típica cerca 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.]
Si usaste MinMaxScaler, confirma que, en el conjunto de entrenamiento, el mínimo de cada columna es 0 y el máximo es 1. En los datos de prueba es normal que aparezcan valores ligeramente fuera de ese rango — es lo esperado y no es un error.
Conclusión
Ya sabes normalizar datos en Machine Learning con scikit-learn, elegir entre StandardScaler y MinMaxScaler y, sobre todo, evitar el data leakage ajustando el scaler solo en el entrenamiento. El siguiente paso es meter este preprocesamiento dentro de un Pipeline completo con un modelo y medir el impacto en el rendimiento. Un consejo para probar: en tu propio conjunto de datos, ¿mejora la estandarización la exactitud del modelo frente a los datos en bruto?