W3docs

Datos Categóricos

Aprende a codificar datos categóricos en Python con Label Encoding, Ordinal Encoding, One-Hot Encoding y pd.get_dummies con ejemplos de scikit-learn.

Los datos categóricos son cualquier dato que toma un conjunto limitado y fijo de valores — piensa en "red", "blue", "green" para una columna de colores, o en "low", "medium", "high" para una clasificación de severidad. La mayoría de los algoritmos de aprendizaje automático trabajan con números, por lo que las columnas categóricas deben convertirse a una representación numérica antes del entrenamiento.

Este capítulo explica las principales estrategias de codificación, cuándo elegir cada una y cómo aplicarlas correctamente en Python usando pandas y scikit-learn sin filtrar información del conjunto de prueba hacia tu modelo.

Por Qué Importa la Codificación

Pasar valores de string sin procesar a un estimador de scikit-learn genera un ValueError. Incluso cuando una columna ya contiene números — como 1, 2, 3 que representan "small", "medium", "large" — un algoritmo que trata los valores de las características como números continuos inferirá una relación falsa (por ejemplo, que "large" es tres veces "small"). La codificación te permite representar la relación real con precisión.

La elección de la codificación depende de dos preguntas:

  1. ¿Existe un orden natural? El color no tiene un orden natural (nominal). La talla de camiseta tiene un orden natural (ordinal). La codificación correcta preserva el orden cuando existe y lo ignora cuando no lo tiene.
  2. ¿Cuántos valores distintos (cardinalidad) tiene la columna? Las columnas de alta cardinalidad (cientos de ciudades únicas, IDs de productos) pueden crear miles de columnas dummy con One-Hot Encoding, lo que perjudica tanto la memoria como el rendimiento del modelo.

Configuración de un Conjunto de Datos de Ejemplo

Los ejemplos a continuación usan un pequeño conjunto de datos de ropa para que puedas seguir la salida exactamente.

import pandas as pd

data = {
    "color":  ["red", "green", "blue", "green", "red"],
    "size":   ["S", "M", "L", "S", "M"],
    "price":  [10, 20, 30, 10, 20],
    "in_stock": [True, True, False, True, False],
}

df = pd.DataFrame(data)
print(df)

Salida:

   color size  price  in_stock
0    red    S     10      True
1  green    M     20      True
2   blue    L     30     False
3  green    S     10      True
4    red    M     20     False

Label Encoding

Label Encoding reemplaza cada categoría con un entero. El LabelEncoder de scikit-learn asigna enteros alfabéticamente.

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
df["color_encoded"] = le.fit_transform(df["color"])

print(df[["color", "color_encoded"]])
print("Classes:", list(le.classes_))

Salida:

   color  color_encoded
0    red              2
1  green              1
2   blue              0
3  green              1
4    red              2
Classes: ['blue', 'green', 'red']

blue → 0, green → 1, red → 2 (orden alfabético).

Cuándo usarlo: Label Encoding está pensado para la variable objetivo (y), no para las características de entrada. Aplicado a una columna de características nominales, los enteros codificados implican un ordenamiento que no existe, lo que confunde a los modelos basados en árboles y es perjudicial para los modelos lineales.

Revertir la codificación:

decoded = le.inverse_transform([0, 1, 2])
print(decoded)  # ['blue' 'green' 'red']

Ordinal Encoding

Ordinal Encoding es como Label Encoding pero te permite especificar el orden exacto de las categorías. Úsalo para características donde el orden es significativo.

from sklearn.preprocessing import OrdinalEncoder

# Define the order explicitly: S < M < L
oe = OrdinalEncoder(categories=[["S", "M", "L"]])
df["size_encoded"] = oe.fit_transform(df[["size"]])

print(df[["size", "size_encoded"]])

Salida:

  size  size_encoded
0    S           0.0
1    M           1.0
2    L           2.0
3    S           0.0
4    M           1.0

El modelo ahora puede inferir correctamente que L (2) > M (1) > S (0).

Manejo de categorías desconocidas en el momento de la predicción:

# Use handle_unknown='use_encoded_value' with unknown_value=-1
oe_safe = OrdinalEncoder(
    categories=[["S", "M", "L"]],
    handle_unknown="use_encoded_value",
    unknown_value=-1,
)
oe_safe.fit(df[["size"]])
print(oe_safe.transform([["XL"]]))  # [[-1.]]

One-Hot Encoding

One-Hot Encoding crea una columna binaria por categoría. Un 1 en una columna significa que la fila pertenece a esa categoría; todas las demás columnas son 0. Esta es la opción estándar para características nominales (sin orden) que se introducen en modelos lineales, SVMs y redes neuronales.

from sklearn.preprocessing import OneHotEncoder
import numpy as np

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
color_encoded = ohe.fit_transform(df[["color"]])

# Build a labelled DataFrame from the result
col_names = ohe.get_feature_names_out(["color"])
color_df = pd.DataFrame(color_encoded, columns=col_names, dtype=int)

print(color_df)

Salida:

   color_blue  color_green  color_red
0           0            0          1
1           0            1          0
2           1            0          0
3           0            1          0
4           0            0          1

handle_unknown='ignore' rellena las categorías no vistas con todos ceros en lugar de generar un error cuando llegan nuevos datos en el momento de la predicción.

Eliminar una Columna para Evitar la Multicolinealidad

Con tres categorías se obtienen tres columnas binarias, pero la tercera es completamente predecible a partir de las otras dos (blue = 1 − green − red). Esta trampa de las variables dummy puede causar problemas en los modelos lineales. Elimina una columna con drop='first':

ohe_nodrop = OneHotEncoder(sparse_output=False, drop="first", handle_unknown="ignore")
reduced = ohe_nodrop.fit_transform(df[["color"]])
print(pd.DataFrame(reduced, columns=ohe_nodrop.get_feature_names_out(["color"]), dtype=int))

Salida (una columna eliminada):

   color_green  color_red
0            0          1
1            1          0
2            0          0
3            1          0
4            0          1

Los modelos basados en árboles (árboles de decisión, bosques aleatorios, gradient boosting) son inmunes a la trampa de las variables dummy, por lo que eliminar una columna es opcional para ellos.

pd.get_dummies — La Alternativa Rápida de Pandas

Para trabajo exploratorio, pd.get_dummies() es la forma más rápida de aplicar one-hot encoding a un DataFrame:

dummies = pd.get_dummies(df[["color", "size"]], dtype=int)
print(dummies)

Salida:

   color_blue  color_green  color_red  size_L  size_M  size_S
0           0            0          1       0       0       1
1           0            1          0       0       1       0
2           1            0          0       1       0       0
3           0            1          0       0       0       1
4           0            0          1       0       1       0

Limitación: pd.get_dummies() no es un transformador ajustado. No puede garantizar el mismo conjunto de columnas entre las divisiones de entrenamiento y prueba, y no admite handle_unknown. Para pipelines de producción, prefiere OneHotEncoder dentro de un Pipeline de scikit-learn.

Cómo Evitar la Fuga de Datos

La fuga de datos ocurre cuando la información del conjunto de prueba influye en cómo se preparan los datos de entrenamiento. El resultado es una puntuación de evaluación excesivamente optimista que no refleja el rendimiento en el mundo real.

El patrón correcto es:

  1. Dividir los datos en conjuntos de entrenamiento y prueba primero.
  2. Ajustar cualquier codificador solo con el conjunto de entrenamiento.
  3. Usar transform() (no fit_transform()) en el conjunto de prueba.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

X = df[["color", "size"]]
y = df["price"]

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

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
ohe.fit(X_train)                       # fit on training data only

X_train_enc = ohe.transform(X_train)  # transform training set
X_test_enc  = ohe.transform(X_test)   # transform test set using training-fit encoder

Para más detalles sobre la división en entrenamiento y prueba, consulta el capítulo Train/Test Split.

Uso de un Pipeline para Combinar la Codificación con un Modelo

Un Pipeline de scikit-learn encadena un transformador y un estimador. Esto garantiza que el codificador siempre se ajuste solo con los datos de entrenamiento, incluso durante la validación cruzada.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split

categorical_cols = ["color", "size"]
numeric_cols     = ["in_stock"]

X_full = df[categorical_cols + numeric_cols]
y_full = df["price"]

X_tr, X_te, y_tr, y_te = train_test_split(X_full, y_full, test_size=0.4, random_state=42)

preprocessor = ColumnTransformer(transformers=[
    ("ohe", OneHotEncoder(handle_unknown="ignore"), categorical_cols),
    ("pass", "passthrough", numeric_cols),
])

pipe = Pipeline(steps=[
    ("preprocessor", preprocessor),
    ("model", LinearRegression()),
])

pipe.fit(X_tr, y_tr)
print("Test predictions:", pipe.predict(X_te))

El ColumnTransformer aplica diferentes pasos de preprocesamiento a distintas columnas en un solo paso. El pipeline es el patrón recomendado para todos los flujos de trabajo de aprendizaje automático de nivel productivo.

Cómo Elegir la Codificación Correcta

SituaciónCodificación recomendada
Variable objetivo (y)LabelEncoder
Característica ordinal (existe orden natural)OrdinalEncoder con categories explícitas
Característica nominal, baja cardinalidadOneHotEncoder (o pd.get_dummies para exploración)
Característica nominal, alta cardinalidadTarget encoding o frequency encoding (ver nota abajo)
Pipeline de producciónOneHotEncoder dentro de un Pipeline / ColumnTransformer

Target encoding reemplaza cada categoría con la media de la variable objetivo para esa categoría. Maneja bien la alta cardinalidad pero es especialmente propenso a la fuga de datos — aplícalo siempre con pliegues de validación cruzada o usa una implementación de biblioteca (p. ej., category_encoders.TargetEncoder) que lo gestione automáticamente.

Capítulos Relacionados

  • Scale — normaliza y estandariza características numéricas antes del modelado
  • Train/Test Split — divide los datos correctamente antes de cualquier paso de preprocesamiento
  • Linear Regression — un modelo que se beneficia de una codificación categórica adecuada
  • Cross Validation — evalúa modelos de forma fiable cuando se combina con pipelines de codificación
  • Confusion Matrix — mide el rendimiento del modelo de clasificación tras codificar los objetivos
  • Pandas Tutorial — fundamentos de pandas, incluyendo la creación y manipulación de DataFrames
Was this page helpful?