W3docs

Escalado de características en Python

Aprende el escalado de características en Python con scikit-learn: StandardScaler, MinMaxScaler, RobustScaler y MaxAbsScaler, con ejemplos y resultados.

Los modelos de aprendizaje automático se entrenan con conjuntos de datos donde cada característica puede abarcar un rango numérico muy diferente. El brillo de un píxel puede ir de 0 a 255, mientras que los ingresos van de 0 a 1.000.000. Cuando las magnitudes de las características difieren en órdenes de magnitud, los algoritmos que se basan en distancias (k-NN, SVM, k-means) o en el descenso de gradiente (regresión logística, redes neuronales) pueden otorgar un peso desproporcionado a las características de mayor escala. El escalado de características lleva todas las características a un rango comparable para que el modelo pueda aprender de todas ellas por igual.

Este capítulo explica por qué el escalado es importante, cubre los cuatro escaladores disponibles en scikit-learn, muestra sus resultados con datos reales y demuestra la forma correcta de integrar el escalado en un pipeline de aprendizaje automático sin filtrar datos de prueba.

Por qué importa el escalado de características

Considera un conjunto de datos simple con dos características: age (20–60) e income (20.000–100.000). La columna income tiene valores aproximadamente 1.000 veces mayores que age. Para los algoritmos que miden la distancia euclidiana, un cambio de una unidad en income domina completamente a un cambio de una unidad en age.

Situaciones específicas en las que el escalado es esencial:

  • Algoritmos basados en distanciasK-Nearest Neighbors y K-Means Clustering calculan distancias entre puntos de datos. Las características sin escalar hacen que la métrica de distancia pierda significado.
  • Optimizadores de descenso de gradienteLogistic Regression y Linear Regression convergen mucho más rápido cuando todas las características se encuentran en rangos similares.
  • Modelos regularizados — Ridge, Lasso y ElasticNet penalizan los coeficientes grandes por igual. Una característica de gran escala atrae artificialmente un coeficiente pequeño, ocultando su verdadera importancia.

Cuándo NO necesitas escalado: los modelos basados en árboles (árboles de decisión, bosques aleatorios, gradient boosting) dividen según umbrales individuales de cada característica. La escala absoluta de una característica no afecta dónde cae la mejor división, por lo que el escalado no tiene efecto en su precisión.

Los cuatro escaladores de scikit-learn

StandardScaler

StandardScaler (también llamado normalización z-score) transforma cada característica para que tenga una media de 0 y una desviación estándar de 1.

Fórmula por característica:

z = (x − mean) / std

Esta es la opción predeterminada cuando no hay una razón sólida para preferir otra. Funciona bien con datos distribuidos normalmente y es la esperada por la mayoría de los modelos lineales regularizados.

from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np

data = load_iris()
X = data.data          # shape (150, 4)
y = data.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)   # fit + transform on training data
X_test_scaled  = scaler.transform(X_test)        # transform only (no re-fit)

# Inspect the result
print("Training set — mean per feature (should be ~0):")
print(np.round(X_train_scaled.mean(axis=0), 4))

print("\nTraining set — std per feature (should be ~1):")
print(np.round(X_train_scaled.std(axis=0), 4))

Salida:

Training set — mean per feature (should be ~0):
[ 0. -0. -0. -0.]

Training set — std per feature (should be ~1):
[1. 1. 1. 1.]

Observa que fit_transform se llama solo en el conjunto de entrenamiento. Llamarlo también en el conjunto de prueba filtraría las estadísticas del conjunto de prueba hacia los parámetros del escalador — consulta la sección Fuga de datos más abajo.

MinMaxScaler

MinMaxScaler reescala cada característica a un rango fijo, por defecto [0, 1].

Fórmula por característica:

x_scaled = (x − min) / (max − min)

Usa MinMaxScaler cuando necesites valores dentro de un rango acotado — por ejemplo, al alimentar datos a una red neuronal con unidades de salida sigmoide, o cuando el algoritmo siguiente espera entradas no negativas.

from sklearn.preprocessing import MinMaxScaler

mm_scaler = MinMaxScaler()   # default feature_range=(0, 1)
X_train_mm = mm_scaler.fit_transform(X_train)
X_test_mm  = mm_scaler.transform(X_test)

print("Min per feature (should be 0):", np.round(X_train_mm.min(axis=0), 4))
print("Max per feature (should be 1):", np.round(X_train_mm.max(axis=0), 4))

Salida:

Min per feature (should be 0): [0. 0. 0. 0.]
Max per feature (should be 1): [1. 1. 1. 1.]

Advertencia: MinMaxScaler es muy sensible a los valores atípicos. Un único valor extremo comprime todos los demás valores en una banda estrecha en un extremo del rango. Si tus datos contienen valores atípicos, considera usar RobustScaler en su lugar.

RobustScaler

RobustScaler usa la mediana y el rango intercuartílico (IQR) en lugar de la media y la desviación estándar, lo que lo hace resistente a los valores atípicos.

Fórmula por característica:

x_scaled = (x − median) / IQR

donde IQR = Q3 − Q1 (percentil 75 menos percentil 25).

from sklearn.preprocessing import RobustScaler

rb_scaler = RobustScaler()
X_train_rb = rb_scaler.fit_transform(X_train)
X_test_rb  = rb_scaler.transform(X_test)

print("Median per feature (should be ~0):")
print(np.round(np.median(X_train_rb, axis=0), 4))

Salida:

Median per feature (should be ~0):
[0. 0. 0. 0.]

RobustScaler es la elección correcta cuando tu conjunto de datos contiene valores atípicos que no puedes o no deseas eliminar.

MaxAbsScaler

MaxAbsScaler divide cada valor por el valor absoluto máximo del conjunto de entrenamiento, colocando cada característica en el rango [−1, 1] sin desplazar los datos.

Fórmula por característica:

x_scaled = x / max(|x|)

Es el único escalador que deja los datos centrados en cero sin desplazarlos. Está diseñado específicamente para matrices dispersas (p. ej., vectores TF-IDF de texto), donde desplazar la media destruiría la dispersión.

from sklearn.preprocessing import MaxAbsScaler

ma_scaler = MaxAbsScaler()
X_train_ma = ma_scaler.fit_transform(X_train)
X_test_ma  = ma_scaler.transform(X_test)

print("Max absolute value per feature (should be 1):")
print(np.round(np.abs(X_train_ma).max(axis=0), 4))

Salida:

Max absolute value per feature (should be 1):
[1. 1. 1. 1.]

Comparación de los cuatro escaladores

La tabla siguiente resume cuándo usar cada escalador:

EscaladorRango de salidaSensible a valores atípicosMejor para
StandardScalerno acotado (media=0, std=1)Datos distribuidos normalmente, modelos lineales regularizados
MinMaxScaler[0, 1] (configurable)Redes neuronales, datos de píxeles de imágenes
RobustScalerno acotado (mediana=0)NoDatos con valores atípicos significativos
MaxAbsScaler[−1, 1]Matrices dispersas (características de texto)

Cómo evitar la fuga de datos

La fuga de datos ocurre cuando la información del conjunto de prueba influye en el paso de preprocesamiento. El error típico es ajustar el escalador en todo el conjunto de datos antes de dividirlo:

# WRONG — leaks test-set statistics into the scaler
scaler = StandardScaler()
X_all_scaled = scaler.fit_transform(X)           # uses test rows
X_train_bad, X_test_bad, _, _ = train_test_split(
    X_all_scaled, y, test_size=0.2, random_state=42
)

El orden correcto es siempre dividir primero y luego ajustar el escalador solo con los datos de entrenamiento:

# CORRECT
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)   # fit on train only
X_test_scaled  = scaler.transform(X_test)        # apply the same transformation

Para más información sobre la división de datos, consulta Train/Test Split.

Usar un Pipeline para mantener el escalado seguro

Un Pipeline de scikit-learn es la forma más robusta de combinar el escalado con un modelo. El pipeline garantiza que fit_transform se llame con los datos de entrenamiento y que solo transform se aplique a cualquier subconjunto reservado — incluso durante la validación cruzada.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)

pipe = Pipeline(steps=[
    ("scaler", StandardScaler()),
    ("model",  LogisticRegression(max_iter=200)),
])

scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
print("CV accuracy scores:", np.round(scores, 3))
print("Mean accuracy:      ", round(scores.mean(), 3))

Salida:

CV accuracy scores: [0.967 1.    0.933 0.9   1.   ]
Mean accuracy:       0.96

El pipeline elimina automáticamente el riesgo de fuga de datos en los cinco pliegues de validación cruzada.

Ajuste de hiperparámetros del escalador

Puedes ajustar la elección del escalador junto con los hiperparámetros del modelo usando Grid Search:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)

pipe = Pipeline(steps=[
    ("scaler", StandardScaler()),
    ("model",  LogisticRegression(max_iter=300)),
])

param_grid = {
    "scaler": [StandardScaler(), MinMaxScaler(), RobustScaler()],
    "model__C": [0.1, 1.0, 10.0],
}

grid = GridSearchCV(pipe, param_grid, cv=5, scoring="accuracy")
grid.fit(X, y)

print("Best scaler:", grid.best_params_["scaler"].__class__.__name__)
print("Best C:     ", grid.best_params_["model__C"])
print("Best score: ", round(grid.best_score_, 3))

Salida:

Best scaler: StandardScaler
Best C:      10.0
Best score:  0.973

Esto permite que los datos te indiquen qué escalador funciona mejor para un modelo y conjunto de datos determinados.

Capítulos relacionados

  • Train/Test Split — divide los datos antes de ajustar cualquier escalador
  • Categorical Data — codifica las características no numéricas antes de escalar
  • K-Nearest Neighbors — modelo basado en distancias que requiere características escaladas
  • K-Means Clustering — algoritmo de agrupamiento sensible a la escala de las características
  • Linear Regression — modelo de descenso de gradiente que converge más rápido con escalado
  • Logistic Regression — clasificador regularizado que se beneficia de StandardScaler
  • Cross Validation — usa un Pipeline para garantizar que el escalado sea seguro durante la CV
  • Grid Search — ajusta la elección del escalador junto con los hiperparámetros del modelo
Was this page helpful?