Menu iconMenu icon
Fundamentos de Ingeniería de Datos

Capítulo 6: Codificación de Variables Categóricas

6.2 Métodos de codificación avanzada: Codificación por objetivo, frecuencia y ordinal

Si bien la codificación One-Hot es una técnica fundamental para manejar variables categóricas, no siempre es la opción óptima, especialmente cuando se trata de conjuntos de datos complejos o características de alta cardinalidad. En tales escenarios, métodos de codificación alternativos pueden ofrecer mayor eficiencia y rendimiento del modelo. Esta sección explora tres técnicas avanzadas de codificación: Codificación por Objetivo, Codificación por Frecuencia y Codificación Ordinal.

La codificación por objetivo reemplaza las categorías con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte relación entre la variable categórica y la variable objetivo, y ayuda a mitigar los problemas de dimensionalidad asociados con la codificación One-Hot en características de alta cardinalidad.

La codificación por frecuencia sustituye cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Esta técnica es especialmente útil cuando la prevalencia de una categoría aporta información significativa. Es eficiente en términos de memoria y no sufre del problema de explosión de columnas de la codificación One-Hot.

La codificación ordinal se aplica cuando las categorías tienen una relación natural y ordenada. A diferencia de la codificación One-Hot, que trata todas las categorías por igual, la codificación ordinal asigna valores numéricos que reflejan el rango o el orden de las categorías. Este método es particularmente valioso para características como niveles educativos o calificaciones de productos donde el orden es significativo.

Cada uno de estos métodos de codificación avanzada tiene sus propias fortalezas y es adecuado para diferentes tipos de datos categóricos y escenarios de modelado. Al comprender y aplicar estas técnicas, los científicos de datos pueden mejorar significativamente su conjunto de herramientas de ingeniería de características y potencialmente mejorar el rendimiento del modelo en una amplia gama de tareas de machine learning.

6.2.1 Codificación por Objetivo

La codificación por objetivo es una técnica avanzada de codificación que reemplaza cada categoría en una variable categórica con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte correlación entre la variable categórica y la variable objetivo. Ofrece varias ventajas sobre métodos de codificación tradicionales como la codificación One-Hot:

  1. Reducción de Dimensionalidad: A diferencia de la codificación One-Hot, que crea una nueva columna binaria para cada categoría, la codificación por objetivo mantiene una sola columna, reduciendo significativamente el espacio de características. Esto es especialmente beneficioso para conjuntos de datos de alta dimensión o cuando se trabaja con recursos computacionales limitados.
  2. Captura de Relaciones Complejas: La codificación por objetivo puede capturar relaciones no lineales entre categorías y la variable objetivo, lo que potencialmente mejora el rendimiento del modelo en ciertos algoritmos como modelos lineales o redes neuronales.
  3. Manejo de Categorías Raras: Proporciona una forma sensata de manejar categorías raras, ya que su codificación estará influenciada por la media global de la variable objetivo, reduciendo el riesgo de sobreajuste a eventos raros.

Cuándo usar la codificación por objetivo

  • Características de alta cardinalidad: La codificación por objetivo es particularmente útil cuando se trabaja con variables categóricas que tienen un gran número de categorías únicas. En tales casos, la codificación One-Hot llevaría a una explosión de características, lo que podría causar problemas de memoria y aumentar la complejidad del modelo.
  • Relación significativa entre categoría y objetivo: Este método es especialmente efectivo cuando existe una relación clara y significativa entre la variable categórica y la variable objetivo, aprovechando esta relación para crear características informativas.
  • Datos limitados para ciertas categorías: En situaciones donde algunas categorías tienen pocos puntos de datos, la codificación por objetivo puede proporcionar estimaciones más estables al incorporar información de todo el conjunto de datos.
  • Problemas de series temporales: La codificación por objetivo puede ser especialmente útil en tareas de pronóstico de series temporales, donde la relación histórica entre categorías y la variable objetivo puede informar predicciones futuras.

Ejemplo de código: Codificación por Objetivo

Supongamos que estamos trabajando con un conjunto de datos que incluye una columna de Vecindario y la variable objetivo es Precios de Vivienda.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'],
    'SalePrice': [300000, 450000, 350000, 500000, 470000, 320000, 480000, 460000, 400000, 420000]
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding
def target_encode(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode(train, test, 'Neighborhood', 'SalePrice')

# View the encoded dataframes
print("Train Data:")
print(train)
print("\nTest Data:")
print(test)

# Demonstrate the impact on a simple model
from sklearn.linear_model import LinearRegression

# Model with original categorical data
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with original data: {mse_orig}")
print(f"MSE with target encoded data: {mse_encoded}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para la selección y evaluación de modelos.
    • Se crea un conjunto de datos de muestra con "Vecindario" como característica categórica y "PrecioVenta" como la variable objetivo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.

Este ejemplo proporciona una visión integral de la codificación por objetivo, incluyendo:

  • División de datos para prevenir fuga de datos
  • Una función de codificación por objetivo reutilizable con suavizado
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Una comparación práctica del rendimiento del modelo con y sin codificación por objetivo

Este enfoque proporciona una comprensión realista y detallada de cómo funciona la codificación por objetivo en la práctica y sus posibles beneficios en una canalización de machine learning.

Consideraciones para la codificación por objetivo

  • Fuga de datos: Uno de los principales riesgos con la codificación por objetivo es la fuga de datos, donde la información del conjunto de prueba "se filtra" en el conjunto de entrenamiento. Esto puede llevar a estimaciones de rendimiento del modelo demasiado optimistas y una generalización deficiente. Para mitigar este riesgo, es crucial realizar la codificación por objetivo dentro de los pliegues de validación cruzada. Este enfoque asegura que la codificación se base solo en los datos de entrenamiento dentro de cada pliegue, manteniendo la integridad del proceso de validación.
  • Sobreajuste: Dado que la codificación por objetivo incorpora directamente la variable objetivo, existe un riesgo significativo de sobreajuste, especialmente para categorías con pocas muestras. Esto puede hacer que el modelo aprenda ruido en lugar de patrones reales en los datos. Para abordar este problema, se pueden emplear varias técnicas:
    • Suavizado: Aplica regularización añadiendo un factor de suavizado al cálculo de la codificación. Esto ayuda a equilibrar entre la media global y la media específica de la categoría, reduciendo el impacto de los valores atípicos o categorías raras.
    • Validación cruzada: Usa validación cruzada k-fold al realizar la codificación por objetivo para asegurar codificaciones más estables y generalizables.
    • Agregar ruido: Introduce pequeñas cantidades de ruido aleatorio a los valores codificados, lo que puede ayudar a evitar que el modelo se ajuste en exceso a valores codificados específicos.
    • Codificación leave-one-out: Para cada muestra, calcula la media de la variable objetivo excluyendo esa muestra, reduciendo el riesgo de sobreajuste a puntos de datos individuales.

Al abordar cuidadosamente estos desafíos, los científicos de datos pueden aprovechar el poder de la codificación por objetivo minimizando sus posibles desventajas, lo que lleva a modelos más robustos y precisos.

Ejemplo de código: Codificación por objetivo con suavizado

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'] * 10,
    'SalePrice': np.random.randint(200000, 600000, 100)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding with smoothing
def target_encode_smooth(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding with smoothing
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode_smooth(train, test, 'Neighborhood', 'SalePrice', alpha=5)

# View the encoded dataframes
print("Train Data:")
print(train[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())
print("\nTest Data:")
print(test[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())

# Demonstrate the impact on a simple model
# Model with original categorical data (One-Hot Encoding)
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with One-Hot Encoding: {mse_orig:.2f}")
print(f"MSE with Target Encoding: {mse_encoded:.2f}")

# Visualize the distribution of encoded values
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
train.groupby('Neighborhood')['NeighborhoodEncoded'].mean().plot(kind='bar')
plt.title('Average Encoded Value by Neighborhood')
plt.xlabel('Neighborhood')
plt.ylabel('Encoded Value')
plt.show()

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para selección de modelos, evaluación y regresión lineal.
    • Se crea un conjunto de datos de muestra más grande con "Vecindario" como característica categórica y "PrecioVenta" como variable objetivo. Usamos 100 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode_smooth que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode_smooth tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa la codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.
  6. Visualización:
    • Añadimos un gráfico de barras para visualizar el valor codificado promedio para cada vecindario, proporcionando información sobre cómo la codificación captura la relación entre los vecindarios y los precios de venta.

6.2.2 Codificación por frecuencia

La codificación por frecuencia es una técnica poderosa que reemplaza cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Este método es particularmente efectivo cuando la prevalencia de una categoría aporta información significativa para el modelo. Por ejemplo, en un modelo de predicción de abandono de clientes, la frecuencia de uso del producto de un cliente podría ser un indicador fuerte de su probabilidad de permanecer leal.

A diferencia de la codificación One-Hot, la codificación por frecuencia es notablemente eficiente en términos de memoria. Condensa la información categórica en una sola columna, independientemente del número de categorías únicas. Esta propiedad la hace especialmente valiosa cuando se trabaja con conjuntos de datos que contienen un gran número de variables categóricas o categorías con alta cardinalidad.

Cuándo usar la codificación por frecuencia

  • Características categóricas de alta cardinalidad: Cuando trabajas con variables que tienen numerosas categorías únicas, como códigos postales o IDs de productos, la codificación por frecuencia puede capturar la información sin la explosión de dimensionalidad asociada a la codificación One-Hot.
  • Importancia de la frecuencia de la categoría: En escenarios donde la frecuencia o rareza de una categoría es significativa para el modelo, la codificación por frecuencia incorpora directamente esta información. Por ejemplo, en la detección de fraudes, la frecuencia de un tipo de transacción podría ser una característica crucial.
  • Restricciones de memoria: Si tu modelo enfrenta limitaciones de memoria debido a la alta dimensionalidad de las características codificadas con One-Hot, la codificación por frecuencia puede ser una excelente alternativa para reducir el espacio de características manteniendo la información importante.
  • Preprocesamiento para modelos basados en árboles: Los modelos basados en árboles como Bosques Aleatorios o Máquinas de Gradiente de Impulso pueden beneficiarse de la codificación por frecuencia, ya que les proporciona una representación numérica de los datos categóricos que puede dividirse fácilmente.

Sin embargo, es importante notar que la codificación por frecuencia asume que existe una relación monótona entre la frecuencia de una categoría y la variable objetivo. Si esta suposición no se cumple para tus datos, otras técnicas de codificación podrían ser más apropiadas. Además, para nuevas o desconocidas categorías en el conjunto de prueba, deberás implementar una estrategia para manejarlas, como asignarles una frecuencia por defecto o usar la frecuencia media del conjunto de entrenamiento.

Ejemplo de código: Codificación por frecuencia

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# Sample data
np.random.seed(42)
data = {
    'City': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 1000),
    'Customer_Churn': np.random.choice([0, 1], 1000)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Perform frequency encoding on the training set
train['City_Frequency'] = train.groupby('City')['City'].transform('count')

# Normalize the frequency
train['City_Frequency_Normalized'] = train['City_Frequency'] / len(train)

# Apply the encoding to the test set
city_freq = train.groupby('City')['City_Frequency'].first()
test['City_Frequency'] = test['City'].map(city_freq).fillna(0)
test['City_Frequency_Normalized'] = test['City_Frequency'] / len(train)

# View the encoded dataframes
print("Train Data:")
print(train.head())
print("\nTest Data:")
print(test.head())

# Visualize the frequency distribution
plt.figure(figsize=(10, 6))
train['City'].value_counts().plot(kind='bar')
plt.title('Frequency of Cities in Training Data')
plt.xlabel('City')
plt.ylabel('Frequency')
plt.show()

# Train a simple model
model = LogisticRegression()
model.fit(train[['City_Frequency_Normalized']], train['Customer_Churn'])

# Make predictions
train_pred = model.predict(train[['City_Frequency_Normalized']])
test_pred = model.predict(test[['City_Frequency_Normalized']])

# Evaluate the model
print(f"\nTrain Accuracy: {accuracy_score(train['Customer_Churn'], train_pred):.4f}")
print(f"Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred):.4f}")

# Compare with one-hot encoding
train_onehot = pd.get_dummies(train['City'], prefix='City')
test_onehot = pd.get_dummies(test['City'], prefix='City')

# Ensure test set has all columns from train set
for col in train_onehot.columns:
    if col not in test_onehot.columns:
        test_onehot[col] = 0

test_onehot = test_onehot[train_onehot.columns]

# Train and evaluate one-hot encoded model
model_onehot = LogisticRegression()
model_onehot.fit(train_onehot, train['Customer_Churn'])

train_pred_onehot = model_onehot.predict(train_onehot)
test_pred_onehot = model_onehot.predict(test_onehot)

print(f"\nOne-Hot Encoding - Train Accuracy: {accuracy_score(train['Customer_Churn'], train_pred_onehot):.4f}")
print(f"One-Hot Encoding - Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred_onehot):.4f}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para manipulación de datos, numpy para generación de números aleatorios, matplotlib para visualización y scikit-learn para entrenamiento y evaluación de modelos.
    • Se crea un conjunto de datos de muestra más grande con "Ciudad" como característica categórica y "Abandono_Cliente" como variable objetivo. Usamos 1000 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Codificación por frecuencia:
    • Realizamos la codificación por frecuencia en el conjunto de entrenamiento usando las funciones groupby y transform de pandas.
    • La frecuencia bruta se normaliza dividiendo por el número total de muestras en el conjunto de entrenamiento.
    • Para el conjunto de prueba, mapeamos las frecuencias del conjunto de entrenamiento para asegurar la consistencia y manejar categorías desconocidas.
  3. Visualización de datos:
    • Usamos matplotlib para crear un gráfico de barras que muestra la distribución de frecuencia de las ciudades en los datos de entrenamiento.
  4. Entrenamiento y evaluación del modelo:
    • Se entrena un modelo de regresión logística usando la característica codificada por frecuencia.
    • Se hacen predicciones en ambos conjuntos (entrenamiento y prueba) y se calculan las puntuaciones de precisión.
  5. Comparación con codificación One-Hot:
    • Creamos versiones codificadas con One-Hot de los datos usando la función get_dummies de pandas.
    • Nos aseguramos de que el conjunto de prueba tenga todas las columnas presentes en el conjunto de entrenamiento, agregando columnas faltantes con valores cero si es necesario.
    • Se entrena y evalúa otro modelo de regresión logística usando los datos codificados con One-Hot.

Este ejemplo ofrece una demostración completa de la codificación por frecuencia, que incluye:

  • División de datos para prevenir fuga de datos
  • Normalización de los valores de frecuencia
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Visualización de las frecuencias de las categorías
  • Una comparación práctica con la codificación One-Hot

Este enfoque proporciona una comprensión práctica y detallada de la aplicación de la codificación por frecuencia en el mundo real y cómo se compara con otras técnicas de codificación en un flujo de trabajo típico de machine learning.

Ventajas de la codificación por frecuencia

  • Eficiencia: La codificación por frecuencia crea solo una columna, independientemente de la cantidad de categorías, lo que la hace eficiente en términos de memoria y cómputo. Esto es particularmente beneficioso cuando se trabaja con grandes conjuntos de datos o variables de alta cardinalidad, donde otros métodos de codificación podrían llevar a un aumento significativo de la dimensionalidad.
  • Fácil de implementar: Este método es sencillo de aplicar y funciona bien con variables de alta cardinalidad. Su simplicidad facilita su integración en los flujos de preprocesamiento de datos existentes y es menos propenso a errores de implementación.
  • Preservación de la información: La codificación por frecuencia retiene información sobre la importancia relativa o la prevalencia de cada categoría. Esto puede ser valioso en escenarios donde la frecuencia de una categoría es en sí misma una característica significativa para el modelo.
  • Manejo de nuevas categorías: Al encontrar nuevas categorías en los datos de prueba, la codificación por frecuencia puede manejarlas fácilmente asignándoles una frecuencia por defecto (por ejemplo, 0 o la frecuencia media del conjunto de entrenamiento), haciéndola robusta ante datos no vistos.
  • Compatibilidad con varios modelos: La naturaleza numérica de las características codificadas por frecuencia las hace compatibles con una amplia gama de algoritmos de machine learning, incluyendo tanto modelos basados en árboles como modelos lineales.

6.2.3 Codificación Ordinal

La codificación ordinal es una técnica sofisticada que se utiliza cuando las categorías en una variable poseen una relación ordenada inherente. Este método contrasta con la codificación One-Hot, que trata todas las categorías como nominalmente distintas. En su lugar, la codificación ordinal asigna a cada categoría un valor numérico que corresponde a su posición o rango dentro del conjunto ordenado.

Este enfoque de codificación es particularmente valioso para características que exhiben una estructura jerárquica clara. Por ejemplo:

  • Nivel educativo: Las categorías podrían codificarse como Secundaria (1), Licenciatura (2), Maestría (3) y Doctorado (4), reflejando niveles crecientes de logro académico.
  • Satisfacción del cliente: Las calificaciones podrían codificarse como Muy insatisfecho (1), Insatisfecho (2), Neutral (3), Satisfecho (4) y Muy satisfecho (5), capturando el espectro de la opinión del cliente.
  • Calificaciones de productos: Un sistema de calificación de cinco estrellas podría codificarse directamente como 1, 2, 3, 4 y 5, preservando la escala de calidad inherente.

Cuándo usar la codificación ordinal

  • Cuando la variable categórica tiene un orden natural (por ejemplo, bajo, medio, alto). Este orden debe ser significativo y consistente en todas las categorías.
  • Cuando el modelo debe tener en cuenta el rango o el orden de las categorías. Esto es particularmente importante para algoritmos que pueden aprovechar las relaciones numéricas entre los valores codificados.
  • En el análisis de series temporales donde la progresión de categorías a lo largo del tiempo es significativa (por ejemplo, etapas de un proyecto: planificación, desarrollo, pruebas, implementación).
  • Para características donde la distancia entre categorías es relativamente uniforme o puede aproximarse como tal.

Es crucial notar que la codificación ordinal introduce la suposición de equidistancia entre categorías, lo cual no siempre es cierto en la realidad. Por ejemplo, la diferencia en el logro académico entre un diploma de secundaria y una licenciatura podría no ser equivalente a la diferencia entre una maestría y un doctorado. Por lo tanto, es esencial considerar cuidadosamente el dominio y los requisitos específicos de la tarea de machine learning al aplicar este método de codificación.

Ejemplo de código: Codificación Ordinal

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OrdinalEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# Sample data
data = {
    'EducationLevel': ['High School', 'Bachelor', 'Master', 'PhD', 'Bachelor', 'High School', 'Master', 'PhD', 'Bachelor', 'Master'],
    'Salary': [30000, 50000, 70000, 90000, 55000, 35000, 75000, 95000, 52000, 72000]
}

df = pd.DataFrame(data)

# Define the ordinal mapping
education_order = {'High School': 1, 'Bachelor': 2, 'Master': 3, 'PhD': 4}

# Apply Manual Ordinal Encoding
df['EducationLevelEncoded'] = df['EducationLevel'].map(education_order)

# Apply Scikit-learn's OrdinalEncoder
ordinal_encoder = OrdinalEncoder(categories=[['High School', 'Bachelor', 'Master', 'PhD']])
df['EducationLevelEncodedSK'] = ordinal_encoder.fit_transform(df[['EducationLevel']])

# View the encoded dataframe
print("Encoded DataFrame:")
print(df)

# Visualize the encoding
plt.figure(figsize=(10, 6))
plt.scatter(df['EducationLevelEncoded'], df['Salary'], alpha=0.6)
plt.xlabel('Education Level (Encoded)')
plt.ylabel('Salary')
plt.title('Salary vs Education Level (Ordinal Encoding)')
plt.show()

# Prepare data for modeling
X = df[['EducationLevelEncoded']]
y = (df['Salary'] > df['Salary'].median()).astype(int)  # Binary classification: 1 if salary > median, else 0

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

# Train a simple decision tree
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)

# Make predictions
y_pred = clf.predict(X_test)

# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"\nModel Accuracy: {accuracy:.2f}")

# Demonstrate handling of unseen categories
new_data = pd.DataFrame({'EducationLevel': ['Associate', 'Bachelor', 'PhD']})
new_data['EducationLevelEncoded'] = new_data['EducationLevel'].map(education_order).fillna(0)
print("\nHandling Unseen Categories:")
print(new_data)

Explicación del desglose del código:

  • Preparación de datos:
    • Creamos un conjunto de datos de muestra más grande con "NivelEducativo" y "Salario" para demostrar el efecto de la codificación en una variable relacionada.
    • Los datos se almacenan en un DataFrame de pandas para facilitar su manipulación.
  • Codificación ordinal manual:
    • Definimos un diccionario 'orden_educativo' que asigna a cada nivel educativo un valor numérico.
    • Se utiliza la función 'map' de pandas para aplicar esta codificación a la columna "NivelEducativo".
  • Codificación ordinal con scikit-learn:
    • Demostramos un método alternativo usando el OrdinalEncoder de scikit-learn.
    • Este método es particularmente útil cuando se trabaja con múltiples columnas categóricas o al integrarse con los pipelines de scikit-learn.
  • Visualización:
    • Se crea un gráfico de dispersión para visualizar la relación entre los niveles educativos codificados y el salario.
    • Esto ayuda a entender cómo la codificación ordinal preserva el orden de las categorías.
  • Entrenamiento del modelo:
    • Creamos un problema de clasificación binaria: predecir si un salario está por encima de la mediana en función del nivel educativo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba para evaluar el rendimiento del modelo con datos no vistos.
    • Se entrena un clasificador de árbol de decisión con los datos codificados.
  • Evaluación del modelo:
    • Se realizan predicciones sobre el conjunto de prueba y se calcula la precisión del modelo.
    • Esto demuestra cómo la codificación ordinal puede ser utilizada eficazmente en una canalización de machine learning.
  • Manejo de categorías no vistas:
    • Creamos un nuevo DataFrame con una categoría no vista ("Asociado") para demostrar cómo manejar estos casos.
    • Se utiliza el método 'fillna(0)' para asignar un valor por defecto (0) a las categorías no vistas.

Este ejemplo integral muestra la aplicación práctica de la codificación ordinal, su visualización, uso en un modelo simple de machine learning y manejo de categorías no vistas. Proporciona una visión completa de cómo encaja la codificación ordinal en un flujo de trabajo de ciencia de datos.

Consideraciones para la codificación ordinal

  • La codificación ordinal solo debe utilizarse cuando las categorías tienen un orden claro. Aplicarla a categorías no ordenadas puede llevar a resultados erróneos, ya que el modelo puede asumir una relación entre categorías que no existe. Por ejemplo, codificar 'Rojo', 'Azul' y 'Verde' como 1, 2 y 3 respectivamente implicaría que 'Verde' es más similar a 'Azul' que a 'Rojo', lo cual no es necesariamente cierto.
  • Para modelos como los árboles de decisión y las máquinas de gradiente, el orden en la codificación ordinal puede proporcionar información útil. Estos modelos pueden aprovechar las relaciones numéricas entre los valores codificados para hacer divisiones y decisiones. Sin embargo, para modelos lineales, la codificación ordinal podría introducir relaciones no deseadas entre categorías. Los modelos lineales podrían interpretar las diferencias numéricas entre los valores codificados como significativas, lo que podría llevar a suposiciones incorrectas sobre los datos.
  • La elección de los valores de codificación puede afectar el rendimiento del modelo. Aunque es común usar enteros consecutivos (1, 2, 3,...), podría haber casos donde valores personalizados representen mejor la relación entre las categorías. Por ejemplo, codificar niveles educativos como 1, 2, 4, 8 en lugar de 1, 2, 3, 4 podría capturar mejor la creciente complejidad o la inversión de tiempo de los niveles educativos más altos.
  • Cuando se trabaja con nuevas categorías no vistas en el conjunto de prueba, es necesario tener una estrategia para manejarlas. Esto podría implicar asignar un valor por defecto, usar la media de los valores codificados existentes o crear una categoría separada para los valores 'desconocidos'.

Comprender estas consideraciones es crucial para implementar eficazmente la codificación ordinal e interpretar los resultados de los modelos entrenados con datos codificados ordinalmente. A menudo, es beneficioso comparar el rendimiento del modelo con diferentes técnicas de codificación para determinar el enfoque más adecuado para tu conjunto de datos y problema específicos.

6.2.4 Puntos clave: Explorando técnicas avanzadas de codificación

A medida que hemos explorado varios métodos de codificación para variables categóricas, es crucial entender sus fortalezas y casos de uso apropiados. Analicemos más a fondo estas técnicas y sus implicaciones:

  • Codificación por Objetivo: Este método aprovecha la relación entre las características categóricas y la variable objetivo, mejorando potencialmente el rendimiento del modelo. Sin embargo, requiere una implementación cuidadosa:
    • Usa validación cruzada o codificación fuera de pliegue para mitigar el sobreajuste.
    • Considera técnicas de suavizado para manejar categorías raras.
    • Ten cuidado con la posible fuga de datos, especialmente en problemas de series temporales.
  • Codificación por Frecuencia: Una solución eficiente para variables de alta cardinalidad, ofreciendo varias ventajas:
    • Reduce la dimensionalidad en comparación con la codificación One-Hot.
    • Captura un nivel de importancia basado en la ocurrencia de la categoría.
    • Funciona bien con modelos basados en árboles y modelos lineales.
  • Codificación Ordinal: Ideal para variables categóricas con un orden inherente:
    • Preserva el rango relativo de las categorías.
    • Especialmente efectiva para modelos basados en árboles.
    • Requiere conocimiento del dominio para determinar el orden adecuado.

La elección del método de codificación puede impactar significativamente el rendimiento y la interpretabilidad del modelo. Considera estos factores al seleccionar una técnica de codificación:

  • La naturaleza de la variable categórica (ordenada vs. no ordenada)
  • La cardinalidad de la variable
  • El algoritmo de machine learning elegido
  • El tamaño de tu conjunto de datos
  • La necesidad de interpretabilidad en tu modelo

En la próxima sección, exploraremos Codificación Hash y otras técnicas avanzadas diseñadas para manejar conjuntos de datos extremadamente grandes y variables categóricas complejas. Estos métodos ofrecen soluciones para escenarios donde los enfoques tradicionales de codificación pueden no ser suficientes, tales como:

  • Manejar millones de categorías únicas
  • Escenarios de aprendizaje en línea con datos en streaming
  • Entornos con limitaciones de memoria

Al dominar estas técnicas de codificación, los científicos de datos pueden preparar eficazmente datos categóricos para una amplia gama de tareas de machine learning, lo que lleva a modelos más robustos y precisos.

6.2 Métodos de codificación avanzada: Codificación por objetivo, frecuencia y ordinal

Si bien la codificación One-Hot es una técnica fundamental para manejar variables categóricas, no siempre es la opción óptima, especialmente cuando se trata de conjuntos de datos complejos o características de alta cardinalidad. En tales escenarios, métodos de codificación alternativos pueden ofrecer mayor eficiencia y rendimiento del modelo. Esta sección explora tres técnicas avanzadas de codificación: Codificación por Objetivo, Codificación por Frecuencia y Codificación Ordinal.

La codificación por objetivo reemplaza las categorías con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte relación entre la variable categórica y la variable objetivo, y ayuda a mitigar los problemas de dimensionalidad asociados con la codificación One-Hot en características de alta cardinalidad.

La codificación por frecuencia sustituye cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Esta técnica es especialmente útil cuando la prevalencia de una categoría aporta información significativa. Es eficiente en términos de memoria y no sufre del problema de explosión de columnas de la codificación One-Hot.

La codificación ordinal se aplica cuando las categorías tienen una relación natural y ordenada. A diferencia de la codificación One-Hot, que trata todas las categorías por igual, la codificación ordinal asigna valores numéricos que reflejan el rango o el orden de las categorías. Este método es particularmente valioso para características como niveles educativos o calificaciones de productos donde el orden es significativo.

Cada uno de estos métodos de codificación avanzada tiene sus propias fortalezas y es adecuado para diferentes tipos de datos categóricos y escenarios de modelado. Al comprender y aplicar estas técnicas, los científicos de datos pueden mejorar significativamente su conjunto de herramientas de ingeniería de características y potencialmente mejorar el rendimiento del modelo en una amplia gama de tareas de machine learning.

6.2.1 Codificación por Objetivo

La codificación por objetivo es una técnica avanzada de codificación que reemplaza cada categoría en una variable categórica con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte correlación entre la variable categórica y la variable objetivo. Ofrece varias ventajas sobre métodos de codificación tradicionales como la codificación One-Hot:

  1. Reducción de Dimensionalidad: A diferencia de la codificación One-Hot, que crea una nueva columna binaria para cada categoría, la codificación por objetivo mantiene una sola columna, reduciendo significativamente el espacio de características. Esto es especialmente beneficioso para conjuntos de datos de alta dimensión o cuando se trabaja con recursos computacionales limitados.
  2. Captura de Relaciones Complejas: La codificación por objetivo puede capturar relaciones no lineales entre categorías y la variable objetivo, lo que potencialmente mejora el rendimiento del modelo en ciertos algoritmos como modelos lineales o redes neuronales.
  3. Manejo de Categorías Raras: Proporciona una forma sensata de manejar categorías raras, ya que su codificación estará influenciada por la media global de la variable objetivo, reduciendo el riesgo de sobreajuste a eventos raros.

Cuándo usar la codificación por objetivo

  • Características de alta cardinalidad: La codificación por objetivo es particularmente útil cuando se trabaja con variables categóricas que tienen un gran número de categorías únicas. En tales casos, la codificación One-Hot llevaría a una explosión de características, lo que podría causar problemas de memoria y aumentar la complejidad del modelo.
  • Relación significativa entre categoría y objetivo: Este método es especialmente efectivo cuando existe una relación clara y significativa entre la variable categórica y la variable objetivo, aprovechando esta relación para crear características informativas.
  • Datos limitados para ciertas categorías: En situaciones donde algunas categorías tienen pocos puntos de datos, la codificación por objetivo puede proporcionar estimaciones más estables al incorporar información de todo el conjunto de datos.
  • Problemas de series temporales: La codificación por objetivo puede ser especialmente útil en tareas de pronóstico de series temporales, donde la relación histórica entre categorías y la variable objetivo puede informar predicciones futuras.

Ejemplo de código: Codificación por Objetivo

Supongamos que estamos trabajando con un conjunto de datos que incluye una columna de Vecindario y la variable objetivo es Precios de Vivienda.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'],
    'SalePrice': [300000, 450000, 350000, 500000, 470000, 320000, 480000, 460000, 400000, 420000]
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding
def target_encode(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode(train, test, 'Neighborhood', 'SalePrice')

# View the encoded dataframes
print("Train Data:")
print(train)
print("\nTest Data:")
print(test)

# Demonstrate the impact on a simple model
from sklearn.linear_model import LinearRegression

# Model with original categorical data
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with original data: {mse_orig}")
print(f"MSE with target encoded data: {mse_encoded}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para la selección y evaluación de modelos.
    • Se crea un conjunto de datos de muestra con "Vecindario" como característica categórica y "PrecioVenta" como la variable objetivo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.

Este ejemplo proporciona una visión integral de la codificación por objetivo, incluyendo:

  • División de datos para prevenir fuga de datos
  • Una función de codificación por objetivo reutilizable con suavizado
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Una comparación práctica del rendimiento del modelo con y sin codificación por objetivo

Este enfoque proporciona una comprensión realista y detallada de cómo funciona la codificación por objetivo en la práctica y sus posibles beneficios en una canalización de machine learning.

Consideraciones para la codificación por objetivo

  • Fuga de datos: Uno de los principales riesgos con la codificación por objetivo es la fuga de datos, donde la información del conjunto de prueba "se filtra" en el conjunto de entrenamiento. Esto puede llevar a estimaciones de rendimiento del modelo demasiado optimistas y una generalización deficiente. Para mitigar este riesgo, es crucial realizar la codificación por objetivo dentro de los pliegues de validación cruzada. Este enfoque asegura que la codificación se base solo en los datos de entrenamiento dentro de cada pliegue, manteniendo la integridad del proceso de validación.
  • Sobreajuste: Dado que la codificación por objetivo incorpora directamente la variable objetivo, existe un riesgo significativo de sobreajuste, especialmente para categorías con pocas muestras. Esto puede hacer que el modelo aprenda ruido en lugar de patrones reales en los datos. Para abordar este problema, se pueden emplear varias técnicas:
    • Suavizado: Aplica regularización añadiendo un factor de suavizado al cálculo de la codificación. Esto ayuda a equilibrar entre la media global y la media específica de la categoría, reduciendo el impacto de los valores atípicos o categorías raras.
    • Validación cruzada: Usa validación cruzada k-fold al realizar la codificación por objetivo para asegurar codificaciones más estables y generalizables.
    • Agregar ruido: Introduce pequeñas cantidades de ruido aleatorio a los valores codificados, lo que puede ayudar a evitar que el modelo se ajuste en exceso a valores codificados específicos.
    • Codificación leave-one-out: Para cada muestra, calcula la media de la variable objetivo excluyendo esa muestra, reduciendo el riesgo de sobreajuste a puntos de datos individuales.

Al abordar cuidadosamente estos desafíos, los científicos de datos pueden aprovechar el poder de la codificación por objetivo minimizando sus posibles desventajas, lo que lleva a modelos más robustos y precisos.

Ejemplo de código: Codificación por objetivo con suavizado

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'] * 10,
    'SalePrice': np.random.randint(200000, 600000, 100)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding with smoothing
def target_encode_smooth(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding with smoothing
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode_smooth(train, test, 'Neighborhood', 'SalePrice', alpha=5)

# View the encoded dataframes
print("Train Data:")
print(train[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())
print("\nTest Data:")
print(test[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())

# Demonstrate the impact on a simple model
# Model with original categorical data (One-Hot Encoding)
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with One-Hot Encoding: {mse_orig:.2f}")
print(f"MSE with Target Encoding: {mse_encoded:.2f}")

# Visualize the distribution of encoded values
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
train.groupby('Neighborhood')['NeighborhoodEncoded'].mean().plot(kind='bar')
plt.title('Average Encoded Value by Neighborhood')
plt.xlabel('Neighborhood')
plt.ylabel('Encoded Value')
plt.show()

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para selección de modelos, evaluación y regresión lineal.
    • Se crea un conjunto de datos de muestra más grande con "Vecindario" como característica categórica y "PrecioVenta" como variable objetivo. Usamos 100 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode_smooth que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode_smooth tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa la codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.
  6. Visualización:
    • Añadimos un gráfico de barras para visualizar el valor codificado promedio para cada vecindario, proporcionando información sobre cómo la codificación captura la relación entre los vecindarios y los precios de venta.

6.2.2 Codificación por frecuencia

La codificación por frecuencia es una técnica poderosa que reemplaza cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Este método es particularmente efectivo cuando la prevalencia de una categoría aporta información significativa para el modelo. Por ejemplo, en un modelo de predicción de abandono de clientes, la frecuencia de uso del producto de un cliente podría ser un indicador fuerte de su probabilidad de permanecer leal.

A diferencia de la codificación One-Hot, la codificación por frecuencia es notablemente eficiente en términos de memoria. Condensa la información categórica en una sola columna, independientemente del número de categorías únicas. Esta propiedad la hace especialmente valiosa cuando se trabaja con conjuntos de datos que contienen un gran número de variables categóricas o categorías con alta cardinalidad.

Cuándo usar la codificación por frecuencia

  • Características categóricas de alta cardinalidad: Cuando trabajas con variables que tienen numerosas categorías únicas, como códigos postales o IDs de productos, la codificación por frecuencia puede capturar la información sin la explosión de dimensionalidad asociada a la codificación One-Hot.
  • Importancia de la frecuencia de la categoría: En escenarios donde la frecuencia o rareza de una categoría es significativa para el modelo, la codificación por frecuencia incorpora directamente esta información. Por ejemplo, en la detección de fraudes, la frecuencia de un tipo de transacción podría ser una característica crucial.
  • Restricciones de memoria: Si tu modelo enfrenta limitaciones de memoria debido a la alta dimensionalidad de las características codificadas con One-Hot, la codificación por frecuencia puede ser una excelente alternativa para reducir el espacio de características manteniendo la información importante.
  • Preprocesamiento para modelos basados en árboles: Los modelos basados en árboles como Bosques Aleatorios o Máquinas de Gradiente de Impulso pueden beneficiarse de la codificación por frecuencia, ya que les proporciona una representación numérica de los datos categóricos que puede dividirse fácilmente.

Sin embargo, es importante notar que la codificación por frecuencia asume que existe una relación monótona entre la frecuencia de una categoría y la variable objetivo. Si esta suposición no se cumple para tus datos, otras técnicas de codificación podrían ser más apropiadas. Además, para nuevas o desconocidas categorías en el conjunto de prueba, deberás implementar una estrategia para manejarlas, como asignarles una frecuencia por defecto o usar la frecuencia media del conjunto de entrenamiento.

Ejemplo de código: Codificación por frecuencia

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# Sample data
np.random.seed(42)
data = {
    'City': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 1000),
    'Customer_Churn': np.random.choice([0, 1], 1000)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Perform frequency encoding on the training set
train['City_Frequency'] = train.groupby('City')['City'].transform('count')

# Normalize the frequency
train['City_Frequency_Normalized'] = train['City_Frequency'] / len(train)

# Apply the encoding to the test set
city_freq = train.groupby('City')['City_Frequency'].first()
test['City_Frequency'] = test['City'].map(city_freq).fillna(0)
test['City_Frequency_Normalized'] = test['City_Frequency'] / len(train)

# View the encoded dataframes
print("Train Data:")
print(train.head())
print("\nTest Data:")
print(test.head())

# Visualize the frequency distribution
plt.figure(figsize=(10, 6))
train['City'].value_counts().plot(kind='bar')
plt.title('Frequency of Cities in Training Data')
plt.xlabel('City')
plt.ylabel('Frequency')
plt.show()

# Train a simple model
model = LogisticRegression()
model.fit(train[['City_Frequency_Normalized']], train['Customer_Churn'])

# Make predictions
train_pred = model.predict(train[['City_Frequency_Normalized']])
test_pred = model.predict(test[['City_Frequency_Normalized']])

# Evaluate the model
print(f"\nTrain Accuracy: {accuracy_score(train['Customer_Churn'], train_pred):.4f}")
print(f"Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred):.4f}")

# Compare with one-hot encoding
train_onehot = pd.get_dummies(train['City'], prefix='City')
test_onehot = pd.get_dummies(test['City'], prefix='City')

# Ensure test set has all columns from train set
for col in train_onehot.columns:
    if col not in test_onehot.columns:
        test_onehot[col] = 0

test_onehot = test_onehot[train_onehot.columns]

# Train and evaluate one-hot encoded model
model_onehot = LogisticRegression()
model_onehot.fit(train_onehot, train['Customer_Churn'])

train_pred_onehot = model_onehot.predict(train_onehot)
test_pred_onehot = model_onehot.predict(test_onehot)

print(f"\nOne-Hot Encoding - Train Accuracy: {accuracy_score(train['Customer_Churn'], train_pred_onehot):.4f}")
print(f"One-Hot Encoding - Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred_onehot):.4f}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para manipulación de datos, numpy para generación de números aleatorios, matplotlib para visualización y scikit-learn para entrenamiento y evaluación de modelos.
    • Se crea un conjunto de datos de muestra más grande con "Ciudad" como característica categórica y "Abandono_Cliente" como variable objetivo. Usamos 1000 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Codificación por frecuencia:
    • Realizamos la codificación por frecuencia en el conjunto de entrenamiento usando las funciones groupby y transform de pandas.
    • La frecuencia bruta se normaliza dividiendo por el número total de muestras en el conjunto de entrenamiento.
    • Para el conjunto de prueba, mapeamos las frecuencias del conjunto de entrenamiento para asegurar la consistencia y manejar categorías desconocidas.
  3. Visualización de datos:
    • Usamos matplotlib para crear un gráfico de barras que muestra la distribución de frecuencia de las ciudades en los datos de entrenamiento.
  4. Entrenamiento y evaluación del modelo:
    • Se entrena un modelo de regresión logística usando la característica codificada por frecuencia.
    • Se hacen predicciones en ambos conjuntos (entrenamiento y prueba) y se calculan las puntuaciones de precisión.
  5. Comparación con codificación One-Hot:
    • Creamos versiones codificadas con One-Hot de los datos usando la función get_dummies de pandas.
    • Nos aseguramos de que el conjunto de prueba tenga todas las columnas presentes en el conjunto de entrenamiento, agregando columnas faltantes con valores cero si es necesario.
    • Se entrena y evalúa otro modelo de regresión logística usando los datos codificados con One-Hot.

Este ejemplo ofrece una demostración completa de la codificación por frecuencia, que incluye:

  • División de datos para prevenir fuga de datos
  • Normalización de los valores de frecuencia
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Visualización de las frecuencias de las categorías
  • Una comparación práctica con la codificación One-Hot

Este enfoque proporciona una comprensión práctica y detallada de la aplicación de la codificación por frecuencia en el mundo real y cómo se compara con otras técnicas de codificación en un flujo de trabajo típico de machine learning.

Ventajas de la codificación por frecuencia

  • Eficiencia: La codificación por frecuencia crea solo una columna, independientemente de la cantidad de categorías, lo que la hace eficiente en términos de memoria y cómputo. Esto es particularmente beneficioso cuando se trabaja con grandes conjuntos de datos o variables de alta cardinalidad, donde otros métodos de codificación podrían llevar a un aumento significativo de la dimensionalidad.
  • Fácil de implementar: Este método es sencillo de aplicar y funciona bien con variables de alta cardinalidad. Su simplicidad facilita su integración en los flujos de preprocesamiento de datos existentes y es menos propenso a errores de implementación.
  • Preservación de la información: La codificación por frecuencia retiene información sobre la importancia relativa o la prevalencia de cada categoría. Esto puede ser valioso en escenarios donde la frecuencia de una categoría es en sí misma una característica significativa para el modelo.
  • Manejo de nuevas categorías: Al encontrar nuevas categorías en los datos de prueba, la codificación por frecuencia puede manejarlas fácilmente asignándoles una frecuencia por defecto (por ejemplo, 0 o la frecuencia media del conjunto de entrenamiento), haciéndola robusta ante datos no vistos.
  • Compatibilidad con varios modelos: La naturaleza numérica de las características codificadas por frecuencia las hace compatibles con una amplia gama de algoritmos de machine learning, incluyendo tanto modelos basados en árboles como modelos lineales.

6.2.3 Codificación Ordinal

La codificación ordinal es una técnica sofisticada que se utiliza cuando las categorías en una variable poseen una relación ordenada inherente. Este método contrasta con la codificación One-Hot, que trata todas las categorías como nominalmente distintas. En su lugar, la codificación ordinal asigna a cada categoría un valor numérico que corresponde a su posición o rango dentro del conjunto ordenado.

Este enfoque de codificación es particularmente valioso para características que exhiben una estructura jerárquica clara. Por ejemplo:

  • Nivel educativo: Las categorías podrían codificarse como Secundaria (1), Licenciatura (2), Maestría (3) y Doctorado (4), reflejando niveles crecientes de logro académico.
  • Satisfacción del cliente: Las calificaciones podrían codificarse como Muy insatisfecho (1), Insatisfecho (2), Neutral (3), Satisfecho (4) y Muy satisfecho (5), capturando el espectro de la opinión del cliente.
  • Calificaciones de productos: Un sistema de calificación de cinco estrellas podría codificarse directamente como 1, 2, 3, 4 y 5, preservando la escala de calidad inherente.

Cuándo usar la codificación ordinal

  • Cuando la variable categórica tiene un orden natural (por ejemplo, bajo, medio, alto). Este orden debe ser significativo y consistente en todas las categorías.
  • Cuando el modelo debe tener en cuenta el rango o el orden de las categorías. Esto es particularmente importante para algoritmos que pueden aprovechar las relaciones numéricas entre los valores codificados.
  • En el análisis de series temporales donde la progresión de categorías a lo largo del tiempo es significativa (por ejemplo, etapas de un proyecto: planificación, desarrollo, pruebas, implementación).
  • Para características donde la distancia entre categorías es relativamente uniforme o puede aproximarse como tal.

Es crucial notar que la codificación ordinal introduce la suposición de equidistancia entre categorías, lo cual no siempre es cierto en la realidad. Por ejemplo, la diferencia en el logro académico entre un diploma de secundaria y una licenciatura podría no ser equivalente a la diferencia entre una maestría y un doctorado. Por lo tanto, es esencial considerar cuidadosamente el dominio y los requisitos específicos de la tarea de machine learning al aplicar este método de codificación.

Ejemplo de código: Codificación Ordinal

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OrdinalEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# Sample data
data = {
    'EducationLevel': ['High School', 'Bachelor', 'Master', 'PhD', 'Bachelor', 'High School', 'Master', 'PhD', 'Bachelor', 'Master'],
    'Salary': [30000, 50000, 70000, 90000, 55000, 35000, 75000, 95000, 52000, 72000]
}

df = pd.DataFrame(data)

# Define the ordinal mapping
education_order = {'High School': 1, 'Bachelor': 2, 'Master': 3, 'PhD': 4}

# Apply Manual Ordinal Encoding
df['EducationLevelEncoded'] = df['EducationLevel'].map(education_order)

# Apply Scikit-learn's OrdinalEncoder
ordinal_encoder = OrdinalEncoder(categories=[['High School', 'Bachelor', 'Master', 'PhD']])
df['EducationLevelEncodedSK'] = ordinal_encoder.fit_transform(df[['EducationLevel']])

# View the encoded dataframe
print("Encoded DataFrame:")
print(df)

# Visualize the encoding
plt.figure(figsize=(10, 6))
plt.scatter(df['EducationLevelEncoded'], df['Salary'], alpha=0.6)
plt.xlabel('Education Level (Encoded)')
plt.ylabel('Salary')
plt.title('Salary vs Education Level (Ordinal Encoding)')
plt.show()

# Prepare data for modeling
X = df[['EducationLevelEncoded']]
y = (df['Salary'] > df['Salary'].median()).astype(int)  # Binary classification: 1 if salary > median, else 0

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

# Train a simple decision tree
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)

# Make predictions
y_pred = clf.predict(X_test)

# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"\nModel Accuracy: {accuracy:.2f}")

# Demonstrate handling of unseen categories
new_data = pd.DataFrame({'EducationLevel': ['Associate', 'Bachelor', 'PhD']})
new_data['EducationLevelEncoded'] = new_data['EducationLevel'].map(education_order).fillna(0)
print("\nHandling Unseen Categories:")
print(new_data)

Explicación del desglose del código:

  • Preparación de datos:
    • Creamos un conjunto de datos de muestra más grande con "NivelEducativo" y "Salario" para demostrar el efecto de la codificación en una variable relacionada.
    • Los datos se almacenan en un DataFrame de pandas para facilitar su manipulación.
  • Codificación ordinal manual:
    • Definimos un diccionario 'orden_educativo' que asigna a cada nivel educativo un valor numérico.
    • Se utiliza la función 'map' de pandas para aplicar esta codificación a la columna "NivelEducativo".
  • Codificación ordinal con scikit-learn:
    • Demostramos un método alternativo usando el OrdinalEncoder de scikit-learn.
    • Este método es particularmente útil cuando se trabaja con múltiples columnas categóricas o al integrarse con los pipelines de scikit-learn.
  • Visualización:
    • Se crea un gráfico de dispersión para visualizar la relación entre los niveles educativos codificados y el salario.
    • Esto ayuda a entender cómo la codificación ordinal preserva el orden de las categorías.
  • Entrenamiento del modelo:
    • Creamos un problema de clasificación binaria: predecir si un salario está por encima de la mediana en función del nivel educativo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba para evaluar el rendimiento del modelo con datos no vistos.
    • Se entrena un clasificador de árbol de decisión con los datos codificados.
  • Evaluación del modelo:
    • Se realizan predicciones sobre el conjunto de prueba y se calcula la precisión del modelo.
    • Esto demuestra cómo la codificación ordinal puede ser utilizada eficazmente en una canalización de machine learning.
  • Manejo de categorías no vistas:
    • Creamos un nuevo DataFrame con una categoría no vista ("Asociado") para demostrar cómo manejar estos casos.
    • Se utiliza el método 'fillna(0)' para asignar un valor por defecto (0) a las categorías no vistas.

Este ejemplo integral muestra la aplicación práctica de la codificación ordinal, su visualización, uso en un modelo simple de machine learning y manejo de categorías no vistas. Proporciona una visión completa de cómo encaja la codificación ordinal en un flujo de trabajo de ciencia de datos.

Consideraciones para la codificación ordinal

  • La codificación ordinal solo debe utilizarse cuando las categorías tienen un orden claro. Aplicarla a categorías no ordenadas puede llevar a resultados erróneos, ya que el modelo puede asumir una relación entre categorías que no existe. Por ejemplo, codificar 'Rojo', 'Azul' y 'Verde' como 1, 2 y 3 respectivamente implicaría que 'Verde' es más similar a 'Azul' que a 'Rojo', lo cual no es necesariamente cierto.
  • Para modelos como los árboles de decisión y las máquinas de gradiente, el orden en la codificación ordinal puede proporcionar información útil. Estos modelos pueden aprovechar las relaciones numéricas entre los valores codificados para hacer divisiones y decisiones. Sin embargo, para modelos lineales, la codificación ordinal podría introducir relaciones no deseadas entre categorías. Los modelos lineales podrían interpretar las diferencias numéricas entre los valores codificados como significativas, lo que podría llevar a suposiciones incorrectas sobre los datos.
  • La elección de los valores de codificación puede afectar el rendimiento del modelo. Aunque es común usar enteros consecutivos (1, 2, 3,...), podría haber casos donde valores personalizados representen mejor la relación entre las categorías. Por ejemplo, codificar niveles educativos como 1, 2, 4, 8 en lugar de 1, 2, 3, 4 podría capturar mejor la creciente complejidad o la inversión de tiempo de los niveles educativos más altos.
  • Cuando se trabaja con nuevas categorías no vistas en el conjunto de prueba, es necesario tener una estrategia para manejarlas. Esto podría implicar asignar un valor por defecto, usar la media de los valores codificados existentes o crear una categoría separada para los valores 'desconocidos'.

Comprender estas consideraciones es crucial para implementar eficazmente la codificación ordinal e interpretar los resultados de los modelos entrenados con datos codificados ordinalmente. A menudo, es beneficioso comparar el rendimiento del modelo con diferentes técnicas de codificación para determinar el enfoque más adecuado para tu conjunto de datos y problema específicos.

6.2.4 Puntos clave: Explorando técnicas avanzadas de codificación

A medida que hemos explorado varios métodos de codificación para variables categóricas, es crucial entender sus fortalezas y casos de uso apropiados. Analicemos más a fondo estas técnicas y sus implicaciones:

  • Codificación por Objetivo: Este método aprovecha la relación entre las características categóricas y la variable objetivo, mejorando potencialmente el rendimiento del modelo. Sin embargo, requiere una implementación cuidadosa:
    • Usa validación cruzada o codificación fuera de pliegue para mitigar el sobreajuste.
    • Considera técnicas de suavizado para manejar categorías raras.
    • Ten cuidado con la posible fuga de datos, especialmente en problemas de series temporales.
  • Codificación por Frecuencia: Una solución eficiente para variables de alta cardinalidad, ofreciendo varias ventajas:
    • Reduce la dimensionalidad en comparación con la codificación One-Hot.
    • Captura un nivel de importancia basado en la ocurrencia de la categoría.
    • Funciona bien con modelos basados en árboles y modelos lineales.
  • Codificación Ordinal: Ideal para variables categóricas con un orden inherente:
    • Preserva el rango relativo de las categorías.
    • Especialmente efectiva para modelos basados en árboles.
    • Requiere conocimiento del dominio para determinar el orden adecuado.

La elección del método de codificación puede impactar significativamente el rendimiento y la interpretabilidad del modelo. Considera estos factores al seleccionar una técnica de codificación:

  • La naturaleza de la variable categórica (ordenada vs. no ordenada)
  • La cardinalidad de la variable
  • El algoritmo de machine learning elegido
  • El tamaño de tu conjunto de datos
  • La necesidad de interpretabilidad en tu modelo

En la próxima sección, exploraremos Codificación Hash y otras técnicas avanzadas diseñadas para manejar conjuntos de datos extremadamente grandes y variables categóricas complejas. Estos métodos ofrecen soluciones para escenarios donde los enfoques tradicionales de codificación pueden no ser suficientes, tales como:

  • Manejar millones de categorías únicas
  • Escenarios de aprendizaje en línea con datos en streaming
  • Entornos con limitaciones de memoria

Al dominar estas técnicas de codificación, los científicos de datos pueden preparar eficazmente datos categóricos para una amplia gama de tareas de machine learning, lo que lleva a modelos más robustos y precisos.

6.2 Métodos de codificación avanzada: Codificación por objetivo, frecuencia y ordinal

Si bien la codificación One-Hot es una técnica fundamental para manejar variables categóricas, no siempre es la opción óptima, especialmente cuando se trata de conjuntos de datos complejos o características de alta cardinalidad. En tales escenarios, métodos de codificación alternativos pueden ofrecer mayor eficiencia y rendimiento del modelo. Esta sección explora tres técnicas avanzadas de codificación: Codificación por Objetivo, Codificación por Frecuencia y Codificación Ordinal.

La codificación por objetivo reemplaza las categorías con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte relación entre la variable categórica y la variable objetivo, y ayuda a mitigar los problemas de dimensionalidad asociados con la codificación One-Hot en características de alta cardinalidad.

La codificación por frecuencia sustituye cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Esta técnica es especialmente útil cuando la prevalencia de una categoría aporta información significativa. Es eficiente en términos de memoria y no sufre del problema de explosión de columnas de la codificación One-Hot.

La codificación ordinal se aplica cuando las categorías tienen una relación natural y ordenada. A diferencia de la codificación One-Hot, que trata todas las categorías por igual, la codificación ordinal asigna valores numéricos que reflejan el rango o el orden de las categorías. Este método es particularmente valioso para características como niveles educativos o calificaciones de productos donde el orden es significativo.

Cada uno de estos métodos de codificación avanzada tiene sus propias fortalezas y es adecuado para diferentes tipos de datos categóricos y escenarios de modelado. Al comprender y aplicar estas técnicas, los científicos de datos pueden mejorar significativamente su conjunto de herramientas de ingeniería de características y potencialmente mejorar el rendimiento del modelo en una amplia gama de tareas de machine learning.

6.2.1 Codificación por Objetivo

La codificación por objetivo es una técnica avanzada de codificación que reemplaza cada categoría en una variable categórica con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte correlación entre la variable categórica y la variable objetivo. Ofrece varias ventajas sobre métodos de codificación tradicionales como la codificación One-Hot:

  1. Reducción de Dimensionalidad: A diferencia de la codificación One-Hot, que crea una nueva columna binaria para cada categoría, la codificación por objetivo mantiene una sola columna, reduciendo significativamente el espacio de características. Esto es especialmente beneficioso para conjuntos de datos de alta dimensión o cuando se trabaja con recursos computacionales limitados.
  2. Captura de Relaciones Complejas: La codificación por objetivo puede capturar relaciones no lineales entre categorías y la variable objetivo, lo que potencialmente mejora el rendimiento del modelo en ciertos algoritmos como modelos lineales o redes neuronales.
  3. Manejo de Categorías Raras: Proporciona una forma sensata de manejar categorías raras, ya que su codificación estará influenciada por la media global de la variable objetivo, reduciendo el riesgo de sobreajuste a eventos raros.

Cuándo usar la codificación por objetivo

  • Características de alta cardinalidad: La codificación por objetivo es particularmente útil cuando se trabaja con variables categóricas que tienen un gran número de categorías únicas. En tales casos, la codificación One-Hot llevaría a una explosión de características, lo que podría causar problemas de memoria y aumentar la complejidad del modelo.
  • Relación significativa entre categoría y objetivo: Este método es especialmente efectivo cuando existe una relación clara y significativa entre la variable categórica y la variable objetivo, aprovechando esta relación para crear características informativas.
  • Datos limitados para ciertas categorías: En situaciones donde algunas categorías tienen pocos puntos de datos, la codificación por objetivo puede proporcionar estimaciones más estables al incorporar información de todo el conjunto de datos.
  • Problemas de series temporales: La codificación por objetivo puede ser especialmente útil en tareas de pronóstico de series temporales, donde la relación histórica entre categorías y la variable objetivo puede informar predicciones futuras.

Ejemplo de código: Codificación por Objetivo

Supongamos que estamos trabajando con un conjunto de datos que incluye una columna de Vecindario y la variable objetivo es Precios de Vivienda.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'],
    'SalePrice': [300000, 450000, 350000, 500000, 470000, 320000, 480000, 460000, 400000, 420000]
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding
def target_encode(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode(train, test, 'Neighborhood', 'SalePrice')

# View the encoded dataframes
print("Train Data:")
print(train)
print("\nTest Data:")
print(test)

# Demonstrate the impact on a simple model
from sklearn.linear_model import LinearRegression

# Model with original categorical data
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with original data: {mse_orig}")
print(f"MSE with target encoded data: {mse_encoded}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para la selección y evaluación de modelos.
    • Se crea un conjunto de datos de muestra con "Vecindario" como característica categórica y "PrecioVenta" como la variable objetivo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.

Este ejemplo proporciona una visión integral de la codificación por objetivo, incluyendo:

  • División de datos para prevenir fuga de datos
  • Una función de codificación por objetivo reutilizable con suavizado
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Una comparación práctica del rendimiento del modelo con y sin codificación por objetivo

Este enfoque proporciona una comprensión realista y detallada de cómo funciona la codificación por objetivo en la práctica y sus posibles beneficios en una canalización de machine learning.

Consideraciones para la codificación por objetivo

  • Fuga de datos: Uno de los principales riesgos con la codificación por objetivo es la fuga de datos, donde la información del conjunto de prueba "se filtra" en el conjunto de entrenamiento. Esto puede llevar a estimaciones de rendimiento del modelo demasiado optimistas y una generalización deficiente. Para mitigar este riesgo, es crucial realizar la codificación por objetivo dentro de los pliegues de validación cruzada. Este enfoque asegura que la codificación se base solo en los datos de entrenamiento dentro de cada pliegue, manteniendo la integridad del proceso de validación.
  • Sobreajuste: Dado que la codificación por objetivo incorpora directamente la variable objetivo, existe un riesgo significativo de sobreajuste, especialmente para categorías con pocas muestras. Esto puede hacer que el modelo aprenda ruido en lugar de patrones reales en los datos. Para abordar este problema, se pueden emplear varias técnicas:
    • Suavizado: Aplica regularización añadiendo un factor de suavizado al cálculo de la codificación. Esto ayuda a equilibrar entre la media global y la media específica de la categoría, reduciendo el impacto de los valores atípicos o categorías raras.
    • Validación cruzada: Usa validación cruzada k-fold al realizar la codificación por objetivo para asegurar codificaciones más estables y generalizables.
    • Agregar ruido: Introduce pequeñas cantidades de ruido aleatorio a los valores codificados, lo que puede ayudar a evitar que el modelo se ajuste en exceso a valores codificados específicos.
    • Codificación leave-one-out: Para cada muestra, calcula la media de la variable objetivo excluyendo esa muestra, reduciendo el riesgo de sobreajuste a puntos de datos individuales.

Al abordar cuidadosamente estos desafíos, los científicos de datos pueden aprovechar el poder de la codificación por objetivo minimizando sus posibles desventajas, lo que lleva a modelos más robustos y precisos.

Ejemplo de código: Codificación por objetivo con suavizado

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'] * 10,
    'SalePrice': np.random.randint(200000, 600000, 100)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding with smoothing
def target_encode_smooth(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding with smoothing
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode_smooth(train, test, 'Neighborhood', 'SalePrice', alpha=5)

# View the encoded dataframes
print("Train Data:")
print(train[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())
print("\nTest Data:")
print(test[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())

# Demonstrate the impact on a simple model
# Model with original categorical data (One-Hot Encoding)
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with One-Hot Encoding: {mse_orig:.2f}")
print(f"MSE with Target Encoding: {mse_encoded:.2f}")

# Visualize the distribution of encoded values
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
train.groupby('Neighborhood')['NeighborhoodEncoded'].mean().plot(kind='bar')
plt.title('Average Encoded Value by Neighborhood')
plt.xlabel('Neighborhood')
plt.ylabel('Encoded Value')
plt.show()

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para selección de modelos, evaluación y regresión lineal.
    • Se crea un conjunto de datos de muestra más grande con "Vecindario" como característica categórica y "PrecioVenta" como variable objetivo. Usamos 100 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode_smooth que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode_smooth tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa la codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.
  6. Visualización:
    • Añadimos un gráfico de barras para visualizar el valor codificado promedio para cada vecindario, proporcionando información sobre cómo la codificación captura la relación entre los vecindarios y los precios de venta.

6.2.2 Codificación por frecuencia

La codificación por frecuencia es una técnica poderosa que reemplaza cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Este método es particularmente efectivo cuando la prevalencia de una categoría aporta información significativa para el modelo. Por ejemplo, en un modelo de predicción de abandono de clientes, la frecuencia de uso del producto de un cliente podría ser un indicador fuerte de su probabilidad de permanecer leal.

A diferencia de la codificación One-Hot, la codificación por frecuencia es notablemente eficiente en términos de memoria. Condensa la información categórica en una sola columna, independientemente del número de categorías únicas. Esta propiedad la hace especialmente valiosa cuando se trabaja con conjuntos de datos que contienen un gran número de variables categóricas o categorías con alta cardinalidad.

Cuándo usar la codificación por frecuencia

  • Características categóricas de alta cardinalidad: Cuando trabajas con variables que tienen numerosas categorías únicas, como códigos postales o IDs de productos, la codificación por frecuencia puede capturar la información sin la explosión de dimensionalidad asociada a la codificación One-Hot.
  • Importancia de la frecuencia de la categoría: En escenarios donde la frecuencia o rareza de una categoría es significativa para el modelo, la codificación por frecuencia incorpora directamente esta información. Por ejemplo, en la detección de fraudes, la frecuencia de un tipo de transacción podría ser una característica crucial.
  • Restricciones de memoria: Si tu modelo enfrenta limitaciones de memoria debido a la alta dimensionalidad de las características codificadas con One-Hot, la codificación por frecuencia puede ser una excelente alternativa para reducir el espacio de características manteniendo la información importante.
  • Preprocesamiento para modelos basados en árboles: Los modelos basados en árboles como Bosques Aleatorios o Máquinas de Gradiente de Impulso pueden beneficiarse de la codificación por frecuencia, ya que les proporciona una representación numérica de los datos categóricos que puede dividirse fácilmente.

Sin embargo, es importante notar que la codificación por frecuencia asume que existe una relación monótona entre la frecuencia de una categoría y la variable objetivo. Si esta suposición no se cumple para tus datos, otras técnicas de codificación podrían ser más apropiadas. Además, para nuevas o desconocidas categorías en el conjunto de prueba, deberás implementar una estrategia para manejarlas, como asignarles una frecuencia por defecto o usar la frecuencia media del conjunto de entrenamiento.

Ejemplo de código: Codificación por frecuencia

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# Sample data
np.random.seed(42)
data = {
    'City': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 1000),
    'Customer_Churn': np.random.choice([0, 1], 1000)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Perform frequency encoding on the training set
train['City_Frequency'] = train.groupby('City')['City'].transform('count')

# Normalize the frequency
train['City_Frequency_Normalized'] = train['City_Frequency'] / len(train)

# Apply the encoding to the test set
city_freq = train.groupby('City')['City_Frequency'].first()
test['City_Frequency'] = test['City'].map(city_freq).fillna(0)
test['City_Frequency_Normalized'] = test['City_Frequency'] / len(train)

# View the encoded dataframes
print("Train Data:")
print(train.head())
print("\nTest Data:")
print(test.head())

# Visualize the frequency distribution
plt.figure(figsize=(10, 6))
train['City'].value_counts().plot(kind='bar')
plt.title('Frequency of Cities in Training Data')
plt.xlabel('City')
plt.ylabel('Frequency')
plt.show()

# Train a simple model
model = LogisticRegression()
model.fit(train[['City_Frequency_Normalized']], train['Customer_Churn'])

# Make predictions
train_pred = model.predict(train[['City_Frequency_Normalized']])
test_pred = model.predict(test[['City_Frequency_Normalized']])

# Evaluate the model
print(f"\nTrain Accuracy: {accuracy_score(train['Customer_Churn'], train_pred):.4f}")
print(f"Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred):.4f}")

# Compare with one-hot encoding
train_onehot = pd.get_dummies(train['City'], prefix='City')
test_onehot = pd.get_dummies(test['City'], prefix='City')

# Ensure test set has all columns from train set
for col in train_onehot.columns:
    if col not in test_onehot.columns:
        test_onehot[col] = 0

test_onehot = test_onehot[train_onehot.columns]

# Train and evaluate one-hot encoded model
model_onehot = LogisticRegression()
model_onehot.fit(train_onehot, train['Customer_Churn'])

train_pred_onehot = model_onehot.predict(train_onehot)
test_pred_onehot = model_onehot.predict(test_onehot)

print(f"\nOne-Hot Encoding - Train Accuracy: {accuracy_score(train['Customer_Churn'], train_pred_onehot):.4f}")
print(f"One-Hot Encoding - Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred_onehot):.4f}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para manipulación de datos, numpy para generación de números aleatorios, matplotlib para visualización y scikit-learn para entrenamiento y evaluación de modelos.
    • Se crea un conjunto de datos de muestra más grande con "Ciudad" como característica categórica y "Abandono_Cliente" como variable objetivo. Usamos 1000 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Codificación por frecuencia:
    • Realizamos la codificación por frecuencia en el conjunto de entrenamiento usando las funciones groupby y transform de pandas.
    • La frecuencia bruta se normaliza dividiendo por el número total de muestras en el conjunto de entrenamiento.
    • Para el conjunto de prueba, mapeamos las frecuencias del conjunto de entrenamiento para asegurar la consistencia y manejar categorías desconocidas.
  3. Visualización de datos:
    • Usamos matplotlib para crear un gráfico de barras que muestra la distribución de frecuencia de las ciudades en los datos de entrenamiento.
  4. Entrenamiento y evaluación del modelo:
    • Se entrena un modelo de regresión logística usando la característica codificada por frecuencia.
    • Se hacen predicciones en ambos conjuntos (entrenamiento y prueba) y se calculan las puntuaciones de precisión.
  5. Comparación con codificación One-Hot:
    • Creamos versiones codificadas con One-Hot de los datos usando la función get_dummies de pandas.
    • Nos aseguramos de que el conjunto de prueba tenga todas las columnas presentes en el conjunto de entrenamiento, agregando columnas faltantes con valores cero si es necesario.
    • Se entrena y evalúa otro modelo de regresión logística usando los datos codificados con One-Hot.

Este ejemplo ofrece una demostración completa de la codificación por frecuencia, que incluye:

  • División de datos para prevenir fuga de datos
  • Normalización de los valores de frecuencia
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Visualización de las frecuencias de las categorías
  • Una comparación práctica con la codificación One-Hot

Este enfoque proporciona una comprensión práctica y detallada de la aplicación de la codificación por frecuencia en el mundo real y cómo se compara con otras técnicas de codificación en un flujo de trabajo típico de machine learning.

Ventajas de la codificación por frecuencia

  • Eficiencia: La codificación por frecuencia crea solo una columna, independientemente de la cantidad de categorías, lo que la hace eficiente en términos de memoria y cómputo. Esto es particularmente beneficioso cuando se trabaja con grandes conjuntos de datos o variables de alta cardinalidad, donde otros métodos de codificación podrían llevar a un aumento significativo de la dimensionalidad.
  • Fácil de implementar: Este método es sencillo de aplicar y funciona bien con variables de alta cardinalidad. Su simplicidad facilita su integración en los flujos de preprocesamiento de datos existentes y es menos propenso a errores de implementación.
  • Preservación de la información: La codificación por frecuencia retiene información sobre la importancia relativa o la prevalencia de cada categoría. Esto puede ser valioso en escenarios donde la frecuencia de una categoría es en sí misma una característica significativa para el modelo.
  • Manejo de nuevas categorías: Al encontrar nuevas categorías en los datos de prueba, la codificación por frecuencia puede manejarlas fácilmente asignándoles una frecuencia por defecto (por ejemplo, 0 o la frecuencia media del conjunto de entrenamiento), haciéndola robusta ante datos no vistos.
  • Compatibilidad con varios modelos: La naturaleza numérica de las características codificadas por frecuencia las hace compatibles con una amplia gama de algoritmos de machine learning, incluyendo tanto modelos basados en árboles como modelos lineales.

6.2.3 Codificación Ordinal

La codificación ordinal es una técnica sofisticada que se utiliza cuando las categorías en una variable poseen una relación ordenada inherente. Este método contrasta con la codificación One-Hot, que trata todas las categorías como nominalmente distintas. En su lugar, la codificación ordinal asigna a cada categoría un valor numérico que corresponde a su posición o rango dentro del conjunto ordenado.

Este enfoque de codificación es particularmente valioso para características que exhiben una estructura jerárquica clara. Por ejemplo:

  • Nivel educativo: Las categorías podrían codificarse como Secundaria (1), Licenciatura (2), Maestría (3) y Doctorado (4), reflejando niveles crecientes de logro académico.
  • Satisfacción del cliente: Las calificaciones podrían codificarse como Muy insatisfecho (1), Insatisfecho (2), Neutral (3), Satisfecho (4) y Muy satisfecho (5), capturando el espectro de la opinión del cliente.
  • Calificaciones de productos: Un sistema de calificación de cinco estrellas podría codificarse directamente como 1, 2, 3, 4 y 5, preservando la escala de calidad inherente.

Cuándo usar la codificación ordinal

  • Cuando la variable categórica tiene un orden natural (por ejemplo, bajo, medio, alto). Este orden debe ser significativo y consistente en todas las categorías.
  • Cuando el modelo debe tener en cuenta el rango o el orden de las categorías. Esto es particularmente importante para algoritmos que pueden aprovechar las relaciones numéricas entre los valores codificados.
  • En el análisis de series temporales donde la progresión de categorías a lo largo del tiempo es significativa (por ejemplo, etapas de un proyecto: planificación, desarrollo, pruebas, implementación).
  • Para características donde la distancia entre categorías es relativamente uniforme o puede aproximarse como tal.

Es crucial notar que la codificación ordinal introduce la suposición de equidistancia entre categorías, lo cual no siempre es cierto en la realidad. Por ejemplo, la diferencia en el logro académico entre un diploma de secundaria y una licenciatura podría no ser equivalente a la diferencia entre una maestría y un doctorado. Por lo tanto, es esencial considerar cuidadosamente el dominio y los requisitos específicos de la tarea de machine learning al aplicar este método de codificación.

Ejemplo de código: Codificación Ordinal

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OrdinalEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# Sample data
data = {
    'EducationLevel': ['High School', 'Bachelor', 'Master', 'PhD', 'Bachelor', 'High School', 'Master', 'PhD', 'Bachelor', 'Master'],
    'Salary': [30000, 50000, 70000, 90000, 55000, 35000, 75000, 95000, 52000, 72000]
}

df = pd.DataFrame(data)

# Define the ordinal mapping
education_order = {'High School': 1, 'Bachelor': 2, 'Master': 3, 'PhD': 4}

# Apply Manual Ordinal Encoding
df['EducationLevelEncoded'] = df['EducationLevel'].map(education_order)

# Apply Scikit-learn's OrdinalEncoder
ordinal_encoder = OrdinalEncoder(categories=[['High School', 'Bachelor', 'Master', 'PhD']])
df['EducationLevelEncodedSK'] = ordinal_encoder.fit_transform(df[['EducationLevel']])

# View the encoded dataframe
print("Encoded DataFrame:")
print(df)

# Visualize the encoding
plt.figure(figsize=(10, 6))
plt.scatter(df['EducationLevelEncoded'], df['Salary'], alpha=0.6)
plt.xlabel('Education Level (Encoded)')
plt.ylabel('Salary')
plt.title('Salary vs Education Level (Ordinal Encoding)')
plt.show()

# Prepare data for modeling
X = df[['EducationLevelEncoded']]
y = (df['Salary'] > df['Salary'].median()).astype(int)  # Binary classification: 1 if salary > median, else 0

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

# Train a simple decision tree
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)

# Make predictions
y_pred = clf.predict(X_test)

# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"\nModel Accuracy: {accuracy:.2f}")

# Demonstrate handling of unseen categories
new_data = pd.DataFrame({'EducationLevel': ['Associate', 'Bachelor', 'PhD']})
new_data['EducationLevelEncoded'] = new_data['EducationLevel'].map(education_order).fillna(0)
print("\nHandling Unseen Categories:")
print(new_data)

Explicación del desglose del código:

  • Preparación de datos:
    • Creamos un conjunto de datos de muestra más grande con "NivelEducativo" y "Salario" para demostrar el efecto de la codificación en una variable relacionada.
    • Los datos se almacenan en un DataFrame de pandas para facilitar su manipulación.
  • Codificación ordinal manual:
    • Definimos un diccionario 'orden_educativo' que asigna a cada nivel educativo un valor numérico.
    • Se utiliza la función 'map' de pandas para aplicar esta codificación a la columna "NivelEducativo".
  • Codificación ordinal con scikit-learn:
    • Demostramos un método alternativo usando el OrdinalEncoder de scikit-learn.
    • Este método es particularmente útil cuando se trabaja con múltiples columnas categóricas o al integrarse con los pipelines de scikit-learn.
  • Visualización:
    • Se crea un gráfico de dispersión para visualizar la relación entre los niveles educativos codificados y el salario.
    • Esto ayuda a entender cómo la codificación ordinal preserva el orden de las categorías.
  • Entrenamiento del modelo:
    • Creamos un problema de clasificación binaria: predecir si un salario está por encima de la mediana en función del nivel educativo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba para evaluar el rendimiento del modelo con datos no vistos.
    • Se entrena un clasificador de árbol de decisión con los datos codificados.
  • Evaluación del modelo:
    • Se realizan predicciones sobre el conjunto de prueba y se calcula la precisión del modelo.
    • Esto demuestra cómo la codificación ordinal puede ser utilizada eficazmente en una canalización de machine learning.
  • Manejo de categorías no vistas:
    • Creamos un nuevo DataFrame con una categoría no vista ("Asociado") para demostrar cómo manejar estos casos.
    • Se utiliza el método 'fillna(0)' para asignar un valor por defecto (0) a las categorías no vistas.

Este ejemplo integral muestra la aplicación práctica de la codificación ordinal, su visualización, uso en un modelo simple de machine learning y manejo de categorías no vistas. Proporciona una visión completa de cómo encaja la codificación ordinal en un flujo de trabajo de ciencia de datos.

Consideraciones para la codificación ordinal

  • La codificación ordinal solo debe utilizarse cuando las categorías tienen un orden claro. Aplicarla a categorías no ordenadas puede llevar a resultados erróneos, ya que el modelo puede asumir una relación entre categorías que no existe. Por ejemplo, codificar 'Rojo', 'Azul' y 'Verde' como 1, 2 y 3 respectivamente implicaría que 'Verde' es más similar a 'Azul' que a 'Rojo', lo cual no es necesariamente cierto.
  • Para modelos como los árboles de decisión y las máquinas de gradiente, el orden en la codificación ordinal puede proporcionar información útil. Estos modelos pueden aprovechar las relaciones numéricas entre los valores codificados para hacer divisiones y decisiones. Sin embargo, para modelos lineales, la codificación ordinal podría introducir relaciones no deseadas entre categorías. Los modelos lineales podrían interpretar las diferencias numéricas entre los valores codificados como significativas, lo que podría llevar a suposiciones incorrectas sobre los datos.
  • La elección de los valores de codificación puede afectar el rendimiento del modelo. Aunque es común usar enteros consecutivos (1, 2, 3,...), podría haber casos donde valores personalizados representen mejor la relación entre las categorías. Por ejemplo, codificar niveles educativos como 1, 2, 4, 8 en lugar de 1, 2, 3, 4 podría capturar mejor la creciente complejidad o la inversión de tiempo de los niveles educativos más altos.
  • Cuando se trabaja con nuevas categorías no vistas en el conjunto de prueba, es necesario tener una estrategia para manejarlas. Esto podría implicar asignar un valor por defecto, usar la media de los valores codificados existentes o crear una categoría separada para los valores 'desconocidos'.

Comprender estas consideraciones es crucial para implementar eficazmente la codificación ordinal e interpretar los resultados de los modelos entrenados con datos codificados ordinalmente. A menudo, es beneficioso comparar el rendimiento del modelo con diferentes técnicas de codificación para determinar el enfoque más adecuado para tu conjunto de datos y problema específicos.

6.2.4 Puntos clave: Explorando técnicas avanzadas de codificación

A medida que hemos explorado varios métodos de codificación para variables categóricas, es crucial entender sus fortalezas y casos de uso apropiados. Analicemos más a fondo estas técnicas y sus implicaciones:

  • Codificación por Objetivo: Este método aprovecha la relación entre las características categóricas y la variable objetivo, mejorando potencialmente el rendimiento del modelo. Sin embargo, requiere una implementación cuidadosa:
    • Usa validación cruzada o codificación fuera de pliegue para mitigar el sobreajuste.
    • Considera técnicas de suavizado para manejar categorías raras.
    • Ten cuidado con la posible fuga de datos, especialmente en problemas de series temporales.
  • Codificación por Frecuencia: Una solución eficiente para variables de alta cardinalidad, ofreciendo varias ventajas:
    • Reduce la dimensionalidad en comparación con la codificación One-Hot.
    • Captura un nivel de importancia basado en la ocurrencia de la categoría.
    • Funciona bien con modelos basados en árboles y modelos lineales.
  • Codificación Ordinal: Ideal para variables categóricas con un orden inherente:
    • Preserva el rango relativo de las categorías.
    • Especialmente efectiva para modelos basados en árboles.
    • Requiere conocimiento del dominio para determinar el orden adecuado.

La elección del método de codificación puede impactar significativamente el rendimiento y la interpretabilidad del modelo. Considera estos factores al seleccionar una técnica de codificación:

  • La naturaleza de la variable categórica (ordenada vs. no ordenada)
  • La cardinalidad de la variable
  • El algoritmo de machine learning elegido
  • El tamaño de tu conjunto de datos
  • La necesidad de interpretabilidad en tu modelo

En la próxima sección, exploraremos Codificación Hash y otras técnicas avanzadas diseñadas para manejar conjuntos de datos extremadamente grandes y variables categóricas complejas. Estos métodos ofrecen soluciones para escenarios donde los enfoques tradicionales de codificación pueden no ser suficientes, tales como:

  • Manejar millones de categorías únicas
  • Escenarios de aprendizaje en línea con datos en streaming
  • Entornos con limitaciones de memoria

Al dominar estas técnicas de codificación, los científicos de datos pueden preparar eficazmente datos categóricos para una amplia gama de tareas de machine learning, lo que lleva a modelos más robustos y precisos.

6.2 Métodos de codificación avanzada: Codificación por objetivo, frecuencia y ordinal

Si bien la codificación One-Hot es una técnica fundamental para manejar variables categóricas, no siempre es la opción óptima, especialmente cuando se trata de conjuntos de datos complejos o características de alta cardinalidad. En tales escenarios, métodos de codificación alternativos pueden ofrecer mayor eficiencia y rendimiento del modelo. Esta sección explora tres técnicas avanzadas de codificación: Codificación por Objetivo, Codificación por Frecuencia y Codificación Ordinal.

La codificación por objetivo reemplaza las categorías con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte relación entre la variable categórica y la variable objetivo, y ayuda a mitigar los problemas de dimensionalidad asociados con la codificación One-Hot en características de alta cardinalidad.

La codificación por frecuencia sustituye cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Esta técnica es especialmente útil cuando la prevalencia de una categoría aporta información significativa. Es eficiente en términos de memoria y no sufre del problema de explosión de columnas de la codificación One-Hot.

La codificación ordinal se aplica cuando las categorías tienen una relación natural y ordenada. A diferencia de la codificación One-Hot, que trata todas las categorías por igual, la codificación ordinal asigna valores numéricos que reflejan el rango o el orden de las categorías. Este método es particularmente valioso para características como niveles educativos o calificaciones de productos donde el orden es significativo.

Cada uno de estos métodos de codificación avanzada tiene sus propias fortalezas y es adecuado para diferentes tipos de datos categóricos y escenarios de modelado. Al comprender y aplicar estas técnicas, los científicos de datos pueden mejorar significativamente su conjunto de herramientas de ingeniería de características y potencialmente mejorar el rendimiento del modelo en una amplia gama de tareas de machine learning.

6.2.1 Codificación por Objetivo

La codificación por objetivo es una técnica avanzada de codificación que reemplaza cada categoría en una variable categórica con la media de la variable objetivo para esa categoría. Este método es particularmente efectivo cuando hay una fuerte correlación entre la variable categórica y la variable objetivo. Ofrece varias ventajas sobre métodos de codificación tradicionales como la codificación One-Hot:

  1. Reducción de Dimensionalidad: A diferencia de la codificación One-Hot, que crea una nueva columna binaria para cada categoría, la codificación por objetivo mantiene una sola columna, reduciendo significativamente el espacio de características. Esto es especialmente beneficioso para conjuntos de datos de alta dimensión o cuando se trabaja con recursos computacionales limitados.
  2. Captura de Relaciones Complejas: La codificación por objetivo puede capturar relaciones no lineales entre categorías y la variable objetivo, lo que potencialmente mejora el rendimiento del modelo en ciertos algoritmos como modelos lineales o redes neuronales.
  3. Manejo de Categorías Raras: Proporciona una forma sensata de manejar categorías raras, ya que su codificación estará influenciada por la media global de la variable objetivo, reduciendo el riesgo de sobreajuste a eventos raros.

Cuándo usar la codificación por objetivo

  • Características de alta cardinalidad: La codificación por objetivo es particularmente útil cuando se trabaja con variables categóricas que tienen un gran número de categorías únicas. En tales casos, la codificación One-Hot llevaría a una explosión de características, lo que podría causar problemas de memoria y aumentar la complejidad del modelo.
  • Relación significativa entre categoría y objetivo: Este método es especialmente efectivo cuando existe una relación clara y significativa entre la variable categórica y la variable objetivo, aprovechando esta relación para crear características informativas.
  • Datos limitados para ciertas categorías: En situaciones donde algunas categorías tienen pocos puntos de datos, la codificación por objetivo puede proporcionar estimaciones más estables al incorporar información de todo el conjunto de datos.
  • Problemas de series temporales: La codificación por objetivo puede ser especialmente útil en tareas de pronóstico de series temporales, donde la relación histórica entre categorías y la variable objetivo puede informar predicciones futuras.

Ejemplo de código: Codificación por Objetivo

Supongamos que estamos trabajando con un conjunto de datos que incluye una columna de Vecindario y la variable objetivo es Precios de Vivienda.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'],
    'SalePrice': [300000, 450000, 350000, 500000, 470000, 320000, 480000, 460000, 400000, 420000]
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding
def target_encode(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode(train, test, 'Neighborhood', 'SalePrice')

# View the encoded dataframes
print("Train Data:")
print(train)
print("\nTest Data:")
print(test)

# Demonstrate the impact on a simple model
from sklearn.linear_model import LinearRegression

# Model with original categorical data
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with original data: {mse_orig}")
print(f"MSE with target encoded data: {mse_encoded}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para la selección y evaluación de modelos.
    • Se crea un conjunto de datos de muestra con "Vecindario" como característica categórica y "PrecioVenta" como la variable objetivo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.

Este ejemplo proporciona una visión integral de la codificación por objetivo, incluyendo:

  • División de datos para prevenir fuga de datos
  • Una función de codificación por objetivo reutilizable con suavizado
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Una comparación práctica del rendimiento del modelo con y sin codificación por objetivo

Este enfoque proporciona una comprensión realista y detallada de cómo funciona la codificación por objetivo en la práctica y sus posibles beneficios en una canalización de machine learning.

Consideraciones para la codificación por objetivo

  • Fuga de datos: Uno de los principales riesgos con la codificación por objetivo es la fuga de datos, donde la información del conjunto de prueba "se filtra" en el conjunto de entrenamiento. Esto puede llevar a estimaciones de rendimiento del modelo demasiado optimistas y una generalización deficiente. Para mitigar este riesgo, es crucial realizar la codificación por objetivo dentro de los pliegues de validación cruzada. Este enfoque asegura que la codificación se base solo en los datos de entrenamiento dentro de cada pliegue, manteniendo la integridad del proceso de validación.
  • Sobreajuste: Dado que la codificación por objetivo incorpora directamente la variable objetivo, existe un riesgo significativo de sobreajuste, especialmente para categorías con pocas muestras. Esto puede hacer que el modelo aprenda ruido en lugar de patrones reales en los datos. Para abordar este problema, se pueden emplear varias técnicas:
    • Suavizado: Aplica regularización añadiendo un factor de suavizado al cálculo de la codificación. Esto ayuda a equilibrar entre la media global y la media específica de la categoría, reduciendo el impacto de los valores atípicos o categorías raras.
    • Validación cruzada: Usa validación cruzada k-fold al realizar la codificación por objetivo para asegurar codificaciones más estables y generalizables.
    • Agregar ruido: Introduce pequeñas cantidades de ruido aleatorio a los valores codificados, lo que puede ayudar a evitar que el modelo se ajuste en exceso a valores codificados específicos.
    • Codificación leave-one-out: Para cada muestra, calcula la media de la variable objetivo excluyendo esa muestra, reduciendo el riesgo de sobreajuste a puntos de datos individuales.

Al abordar cuidadosamente estos desafíos, los científicos de datos pueden aprovechar el poder de la codificación por objetivo minimizando sus posibles desventajas, lo que lleva a modelos más robustos y precisos.

Ejemplo de código: Codificación por objetivo con suavizado

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression

# Sample data
data = {
    'Neighborhood': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'D', 'D'] * 10,
    'SalePrice': np.random.randint(200000, 600000, 100)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Function to perform target encoding with smoothing
def target_encode_smooth(train, test, column, target, alpha=5):
    # Calculate global mean
    global_mean = train[target].mean()
    
    # Calculate the mean of the target for each category
    category_means = train.groupby(column)[target].agg(['mean', 'count'])
    
    # Apply smoothing
    smoothed_means = (category_means['mean'] * category_means['count'] + global_mean * alpha) / (category_means['count'] + alpha)
    
    # Apply encoding to train set
    train_encoded = train[column].map(smoothed_means)
    
    # Apply encoding to test set
    test_encoded = test[column].map(smoothed_means)
    
    # Handle unknown categories in test set
    test_encoded.fillna(global_mean, inplace=True)
    
    return train_encoded, test_encoded

# Apply Target Encoding with smoothing
train['NeighborhoodEncoded'], test['NeighborhoodEncoded'] = target_encode_smooth(train, test, 'Neighborhood', 'SalePrice', alpha=5)

# View the encoded dataframes
print("Train Data:")
print(train[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())
print("\nTest Data:")
print(test[['Neighborhood', 'NeighborhoodEncoded', 'SalePrice']].head())

# Demonstrate the impact on a simple model
# Model with original categorical data (One-Hot Encoding)
model_orig = LinearRegression()
model_orig.fit(pd.get_dummies(train['Neighborhood']), train['SalePrice'])
pred_orig = model_orig.predict(pd.get_dummies(test['Neighborhood']))
mse_orig = mean_squared_error(test['SalePrice'], pred_orig)

# Model with target encoded data
model_encoded = LinearRegression()
model_encoded.fit(train[['NeighborhoodEncoded']], train['SalePrice'])
pred_encoded = model_encoded.predict(test[['NeighborhoodEncoded']])
mse_encoded = mean_squared_error(test['SalePrice'], pred_encoded)

print(f"\nMSE with One-Hot Encoding: {mse_orig:.2f}")
print(f"MSE with Target Encoding: {mse_encoded:.2f}")

# Visualize the distribution of encoded values
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
train.groupby('Neighborhood')['NeighborhoodEncoded'].mean().plot(kind='bar')
plt.title('Average Encoded Value by Neighborhood')
plt.xlabel('Neighborhood')
plt.ylabel('Encoded Value')
plt.show()

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para la manipulación de datos, numpy para operaciones numéricas y scikit-learn para selección de modelos, evaluación y regresión lineal.
    • Se crea un conjunto de datos de muestra más grande con "Vecindario" como característica categórica y "PrecioVenta" como variable objetivo. Usamos 100 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Función de codificación por objetivo:
    • Definimos una función personalizada target_encode_smooth que realiza la codificación por objetivo con suavizado.
    • La función calcula la media global de la variable objetivo y la media para cada categoría.
    • Se aplica el suavizado usando la fórmula: (media_categoria * cantidad_categoria + media_global * alpha) / (cantidad_categoria + alpha).
    • La función maneja categorías desconocidas en el conjunto de prueba rellenándolas con la media global.
  3. Aplicación de la codificación por objetivo:
    • Aplicamos la función target_encode_smooth tanto al conjunto de entrenamiento como al de prueba.
    • Los valores codificados se almacenan en una nueva columna "VecindarioCodificado".
  4. Visualización de resultados:
    • Imprimimos ambos dataframes de entrenamiento y prueba para mostrar los valores originales y codificados uno al lado del otro.
  5. Comparación de modelos:
    • Para demostrar el impacto de la codificación por objetivo, comparamos dos modelos de regresión lineal simples.
    • El primer modelo usa la codificación One-Hot (pd.get_dummies) en la columna original "Vecindario".
    • El segundo modelo usa la columna codificada "VecindarioCodificado".
    • Ajustamos ambos modelos en los datos de entrenamiento y hacemos predicciones en los datos de prueba.
    • Se calcula el Error Cuadrático Medio (MSE) para ambos modelos para comparar su rendimiento.
  6. Visualización:
    • Añadimos un gráfico de barras para visualizar el valor codificado promedio para cada vecindario, proporcionando información sobre cómo la codificación captura la relación entre los vecindarios y los precios de venta.

6.2.2 Codificación por frecuencia

La codificación por frecuencia es una técnica poderosa que reemplaza cada categoría con su frecuencia de ocurrencia en el conjunto de datos. Este método es particularmente efectivo cuando la prevalencia de una categoría aporta información significativa para el modelo. Por ejemplo, en un modelo de predicción de abandono de clientes, la frecuencia de uso del producto de un cliente podría ser un indicador fuerte de su probabilidad de permanecer leal.

A diferencia de la codificación One-Hot, la codificación por frecuencia es notablemente eficiente en términos de memoria. Condensa la información categórica en una sola columna, independientemente del número de categorías únicas. Esta propiedad la hace especialmente valiosa cuando se trabaja con conjuntos de datos que contienen un gran número de variables categóricas o categorías con alta cardinalidad.

Cuándo usar la codificación por frecuencia

  • Características categóricas de alta cardinalidad: Cuando trabajas con variables que tienen numerosas categorías únicas, como códigos postales o IDs de productos, la codificación por frecuencia puede capturar la información sin la explosión de dimensionalidad asociada a la codificación One-Hot.
  • Importancia de la frecuencia de la categoría: En escenarios donde la frecuencia o rareza de una categoría es significativa para el modelo, la codificación por frecuencia incorpora directamente esta información. Por ejemplo, en la detección de fraudes, la frecuencia de un tipo de transacción podría ser una característica crucial.
  • Restricciones de memoria: Si tu modelo enfrenta limitaciones de memoria debido a la alta dimensionalidad de las características codificadas con One-Hot, la codificación por frecuencia puede ser una excelente alternativa para reducir el espacio de características manteniendo la información importante.
  • Preprocesamiento para modelos basados en árboles: Los modelos basados en árboles como Bosques Aleatorios o Máquinas de Gradiente de Impulso pueden beneficiarse de la codificación por frecuencia, ya que les proporciona una representación numérica de los datos categóricos que puede dividirse fácilmente.

Sin embargo, es importante notar que la codificación por frecuencia asume que existe una relación monótona entre la frecuencia de una categoría y la variable objetivo. Si esta suposición no se cumple para tus datos, otras técnicas de codificación podrían ser más apropiadas. Además, para nuevas o desconocidas categorías en el conjunto de prueba, deberás implementar una estrategia para manejarlas, como asignarles una frecuencia por defecto o usar la frecuencia media del conjunto de entrenamiento.

Ejemplo de código: Codificación por frecuencia

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# Sample data
np.random.seed(42)
data = {
    'City': np.random.choice(['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 1000),
    'Customer_Churn': np.random.choice([0, 1], 1000)
}

df = pd.DataFrame(data)

# Split the data into train and test sets
train, test = train_test_split(df, test_size=0.2, random_state=42)

# Perform frequency encoding on the training set
train['City_Frequency'] = train.groupby('City')['City'].transform('count')

# Normalize the frequency
train['City_Frequency_Normalized'] = train['City_Frequency'] / len(train)

# Apply the encoding to the test set
city_freq = train.groupby('City')['City_Frequency'].first()
test['City_Frequency'] = test['City'].map(city_freq).fillna(0)
test['City_Frequency_Normalized'] = test['City_Frequency'] / len(train)

# View the encoded dataframes
print("Train Data:")
print(train.head())
print("\nTest Data:")
print(test.head())

# Visualize the frequency distribution
plt.figure(figsize=(10, 6))
train['City'].value_counts().plot(kind='bar')
plt.title('Frequency of Cities in Training Data')
plt.xlabel('City')
plt.ylabel('Frequency')
plt.show()

# Train a simple model
model = LogisticRegression()
model.fit(train[['City_Frequency_Normalized']], train['Customer_Churn'])

# Make predictions
train_pred = model.predict(train[['City_Frequency_Normalized']])
test_pred = model.predict(test[['City_Frequency_Normalized']])

# Evaluate the model
print(f"\nTrain Accuracy: {accuracy_score(train['Customer_Churn'], train_pred):.4f}")
print(f"Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred):.4f}")

# Compare with one-hot encoding
train_onehot = pd.get_dummies(train['City'], prefix='City')
test_onehot = pd.get_dummies(test['City'], prefix='City')

# Ensure test set has all columns from train set
for col in train_onehot.columns:
    if col not in test_onehot.columns:
        test_onehot[col] = 0

test_onehot = test_onehot[train_onehot.columns]

# Train and evaluate one-hot encoded model
model_onehot = LogisticRegression()
model_onehot.fit(train_onehot, train['Customer_Churn'])

train_pred_onehot = model_onehot.predict(train_onehot)
test_pred_onehot = model_onehot.predict(test_onehot)

print(f"\nOne-Hot Encoding - Train Accuracy: {accuracy_score(train['Customer_Churn'], train_pred_onehot):.4f}")
print(f"One-Hot Encoding - Test Accuracy: {accuracy_score(test['Customer_Churn'], test_pred_onehot):.4f}")

Explicación del desglose del código:

  1. Preparación de datos:
    • Importamos las bibliotecas necesarias: pandas para manipulación de datos, numpy para generación de números aleatorios, matplotlib para visualización y scikit-learn para entrenamiento y evaluación de modelos.
    • Se crea un conjunto de datos de muestra más grande con "Ciudad" como característica categórica y "Abandono_Cliente" como variable objetivo. Usamos 1000 muestras para demostrar mejor los efectos de la codificación.
    • Los datos se dividen en conjuntos de entrenamiento y prueba usando train_test_split para simular un escenario real y evitar la fuga de datos.
  2. Codificación por frecuencia:
    • Realizamos la codificación por frecuencia en el conjunto de entrenamiento usando las funciones groupby y transform de pandas.
    • La frecuencia bruta se normaliza dividiendo por el número total de muestras en el conjunto de entrenamiento.
    • Para el conjunto de prueba, mapeamos las frecuencias del conjunto de entrenamiento para asegurar la consistencia y manejar categorías desconocidas.
  3. Visualización de datos:
    • Usamos matplotlib para crear un gráfico de barras que muestra la distribución de frecuencia de las ciudades en los datos de entrenamiento.
  4. Entrenamiento y evaluación del modelo:
    • Se entrena un modelo de regresión logística usando la característica codificada por frecuencia.
    • Se hacen predicciones en ambos conjuntos (entrenamiento y prueba) y se calculan las puntuaciones de precisión.
  5. Comparación con codificación One-Hot:
    • Creamos versiones codificadas con One-Hot de los datos usando la función get_dummies de pandas.
    • Nos aseguramos de que el conjunto de prueba tenga todas las columnas presentes en el conjunto de entrenamiento, agregando columnas faltantes con valores cero si es necesario.
    • Se entrena y evalúa otro modelo de regresión logística usando los datos codificados con One-Hot.

Este ejemplo ofrece una demostración completa de la codificación por frecuencia, que incluye:

  • División de datos para prevenir fuga de datos
  • Normalización de los valores de frecuencia
  • Manejo de categorías desconocidas en el conjunto de prueba
  • Visualización de las frecuencias de las categorías
  • Una comparación práctica con la codificación One-Hot

Este enfoque proporciona una comprensión práctica y detallada de la aplicación de la codificación por frecuencia en el mundo real y cómo se compara con otras técnicas de codificación en un flujo de trabajo típico de machine learning.

Ventajas de la codificación por frecuencia

  • Eficiencia: La codificación por frecuencia crea solo una columna, independientemente de la cantidad de categorías, lo que la hace eficiente en términos de memoria y cómputo. Esto es particularmente beneficioso cuando se trabaja con grandes conjuntos de datos o variables de alta cardinalidad, donde otros métodos de codificación podrían llevar a un aumento significativo de la dimensionalidad.
  • Fácil de implementar: Este método es sencillo de aplicar y funciona bien con variables de alta cardinalidad. Su simplicidad facilita su integración en los flujos de preprocesamiento de datos existentes y es menos propenso a errores de implementación.
  • Preservación de la información: La codificación por frecuencia retiene información sobre la importancia relativa o la prevalencia de cada categoría. Esto puede ser valioso en escenarios donde la frecuencia de una categoría es en sí misma una característica significativa para el modelo.
  • Manejo de nuevas categorías: Al encontrar nuevas categorías en los datos de prueba, la codificación por frecuencia puede manejarlas fácilmente asignándoles una frecuencia por defecto (por ejemplo, 0 o la frecuencia media del conjunto de entrenamiento), haciéndola robusta ante datos no vistos.
  • Compatibilidad con varios modelos: La naturaleza numérica de las características codificadas por frecuencia las hace compatibles con una amplia gama de algoritmos de machine learning, incluyendo tanto modelos basados en árboles como modelos lineales.

6.2.3 Codificación Ordinal

La codificación ordinal es una técnica sofisticada que se utiliza cuando las categorías en una variable poseen una relación ordenada inherente. Este método contrasta con la codificación One-Hot, que trata todas las categorías como nominalmente distintas. En su lugar, la codificación ordinal asigna a cada categoría un valor numérico que corresponde a su posición o rango dentro del conjunto ordenado.

Este enfoque de codificación es particularmente valioso para características que exhiben una estructura jerárquica clara. Por ejemplo:

  • Nivel educativo: Las categorías podrían codificarse como Secundaria (1), Licenciatura (2), Maestría (3) y Doctorado (4), reflejando niveles crecientes de logro académico.
  • Satisfacción del cliente: Las calificaciones podrían codificarse como Muy insatisfecho (1), Insatisfecho (2), Neutral (3), Satisfecho (4) y Muy satisfecho (5), capturando el espectro de la opinión del cliente.
  • Calificaciones de productos: Un sistema de calificación de cinco estrellas podría codificarse directamente como 1, 2, 3, 4 y 5, preservando la escala de calidad inherente.

Cuándo usar la codificación ordinal

  • Cuando la variable categórica tiene un orden natural (por ejemplo, bajo, medio, alto). Este orden debe ser significativo y consistente en todas las categorías.
  • Cuando el modelo debe tener en cuenta el rango o el orden de las categorías. Esto es particularmente importante para algoritmos que pueden aprovechar las relaciones numéricas entre los valores codificados.
  • En el análisis de series temporales donde la progresión de categorías a lo largo del tiempo es significativa (por ejemplo, etapas de un proyecto: planificación, desarrollo, pruebas, implementación).
  • Para características donde la distancia entre categorías es relativamente uniforme o puede aproximarse como tal.

Es crucial notar que la codificación ordinal introduce la suposición de equidistancia entre categorías, lo cual no siempre es cierto en la realidad. Por ejemplo, la diferencia en el logro académico entre un diploma de secundaria y una licenciatura podría no ser equivalente a la diferencia entre una maestría y un doctorado. Por lo tanto, es esencial considerar cuidadosamente el dominio y los requisitos específicos de la tarea de machine learning al aplicar este método de codificación.

Ejemplo de código: Codificación Ordinal

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OrdinalEncoder
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

# Sample data
data = {
    'EducationLevel': ['High School', 'Bachelor', 'Master', 'PhD', 'Bachelor', 'High School', 'Master', 'PhD', 'Bachelor', 'Master'],
    'Salary': [30000, 50000, 70000, 90000, 55000, 35000, 75000, 95000, 52000, 72000]
}

df = pd.DataFrame(data)

# Define the ordinal mapping
education_order = {'High School': 1, 'Bachelor': 2, 'Master': 3, 'PhD': 4}

# Apply Manual Ordinal Encoding
df['EducationLevelEncoded'] = df['EducationLevel'].map(education_order)

# Apply Scikit-learn's OrdinalEncoder
ordinal_encoder = OrdinalEncoder(categories=[['High School', 'Bachelor', 'Master', 'PhD']])
df['EducationLevelEncodedSK'] = ordinal_encoder.fit_transform(df[['EducationLevel']])

# View the encoded dataframe
print("Encoded DataFrame:")
print(df)

# Visualize the encoding
plt.figure(figsize=(10, 6))
plt.scatter(df['EducationLevelEncoded'], df['Salary'], alpha=0.6)
plt.xlabel('Education Level (Encoded)')
plt.ylabel('Salary')
plt.title('Salary vs Education Level (Ordinal Encoding)')
plt.show()

# Prepare data for modeling
X = df[['EducationLevelEncoded']]
y = (df['Salary'] > df['Salary'].median()).astype(int)  # Binary classification: 1 if salary > median, else 0

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

# Train a simple decision tree
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)

# Make predictions
y_pred = clf.predict(X_test)

# Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"\nModel Accuracy: {accuracy:.2f}")

# Demonstrate handling of unseen categories
new_data = pd.DataFrame({'EducationLevel': ['Associate', 'Bachelor', 'PhD']})
new_data['EducationLevelEncoded'] = new_data['EducationLevel'].map(education_order).fillna(0)
print("\nHandling Unseen Categories:")
print(new_data)

Explicación del desglose del código:

  • Preparación de datos:
    • Creamos un conjunto de datos de muestra más grande con "NivelEducativo" y "Salario" para demostrar el efecto de la codificación en una variable relacionada.
    • Los datos se almacenan en un DataFrame de pandas para facilitar su manipulación.
  • Codificación ordinal manual:
    • Definimos un diccionario 'orden_educativo' que asigna a cada nivel educativo un valor numérico.
    • Se utiliza la función 'map' de pandas para aplicar esta codificación a la columna "NivelEducativo".
  • Codificación ordinal con scikit-learn:
    • Demostramos un método alternativo usando el OrdinalEncoder de scikit-learn.
    • Este método es particularmente útil cuando se trabaja con múltiples columnas categóricas o al integrarse con los pipelines de scikit-learn.
  • Visualización:
    • Se crea un gráfico de dispersión para visualizar la relación entre los niveles educativos codificados y el salario.
    • Esto ayuda a entender cómo la codificación ordinal preserva el orden de las categorías.
  • Entrenamiento del modelo:
    • Creamos un problema de clasificación binaria: predecir si un salario está por encima de la mediana en función del nivel educativo.
    • Los datos se dividen en conjuntos de entrenamiento y prueba para evaluar el rendimiento del modelo con datos no vistos.
    • Se entrena un clasificador de árbol de decisión con los datos codificados.
  • Evaluación del modelo:
    • Se realizan predicciones sobre el conjunto de prueba y se calcula la precisión del modelo.
    • Esto demuestra cómo la codificación ordinal puede ser utilizada eficazmente en una canalización de machine learning.
  • Manejo de categorías no vistas:
    • Creamos un nuevo DataFrame con una categoría no vista ("Asociado") para demostrar cómo manejar estos casos.
    • Se utiliza el método 'fillna(0)' para asignar un valor por defecto (0) a las categorías no vistas.

Este ejemplo integral muestra la aplicación práctica de la codificación ordinal, su visualización, uso en un modelo simple de machine learning y manejo de categorías no vistas. Proporciona una visión completa de cómo encaja la codificación ordinal en un flujo de trabajo de ciencia de datos.

Consideraciones para la codificación ordinal

  • La codificación ordinal solo debe utilizarse cuando las categorías tienen un orden claro. Aplicarla a categorías no ordenadas puede llevar a resultados erróneos, ya que el modelo puede asumir una relación entre categorías que no existe. Por ejemplo, codificar 'Rojo', 'Azul' y 'Verde' como 1, 2 y 3 respectivamente implicaría que 'Verde' es más similar a 'Azul' que a 'Rojo', lo cual no es necesariamente cierto.
  • Para modelos como los árboles de decisión y las máquinas de gradiente, el orden en la codificación ordinal puede proporcionar información útil. Estos modelos pueden aprovechar las relaciones numéricas entre los valores codificados para hacer divisiones y decisiones. Sin embargo, para modelos lineales, la codificación ordinal podría introducir relaciones no deseadas entre categorías. Los modelos lineales podrían interpretar las diferencias numéricas entre los valores codificados como significativas, lo que podría llevar a suposiciones incorrectas sobre los datos.
  • La elección de los valores de codificación puede afectar el rendimiento del modelo. Aunque es común usar enteros consecutivos (1, 2, 3,...), podría haber casos donde valores personalizados representen mejor la relación entre las categorías. Por ejemplo, codificar niveles educativos como 1, 2, 4, 8 en lugar de 1, 2, 3, 4 podría capturar mejor la creciente complejidad o la inversión de tiempo de los niveles educativos más altos.
  • Cuando se trabaja con nuevas categorías no vistas en el conjunto de prueba, es necesario tener una estrategia para manejarlas. Esto podría implicar asignar un valor por defecto, usar la media de los valores codificados existentes o crear una categoría separada para los valores 'desconocidos'.

Comprender estas consideraciones es crucial para implementar eficazmente la codificación ordinal e interpretar los resultados de los modelos entrenados con datos codificados ordinalmente. A menudo, es beneficioso comparar el rendimiento del modelo con diferentes técnicas de codificación para determinar el enfoque más adecuado para tu conjunto de datos y problema específicos.

6.2.4 Puntos clave: Explorando técnicas avanzadas de codificación

A medida que hemos explorado varios métodos de codificación para variables categóricas, es crucial entender sus fortalezas y casos de uso apropiados. Analicemos más a fondo estas técnicas y sus implicaciones:

  • Codificación por Objetivo: Este método aprovecha la relación entre las características categóricas y la variable objetivo, mejorando potencialmente el rendimiento del modelo. Sin embargo, requiere una implementación cuidadosa:
    • Usa validación cruzada o codificación fuera de pliegue para mitigar el sobreajuste.
    • Considera técnicas de suavizado para manejar categorías raras.
    • Ten cuidado con la posible fuga de datos, especialmente en problemas de series temporales.
  • Codificación por Frecuencia: Una solución eficiente para variables de alta cardinalidad, ofreciendo varias ventajas:
    • Reduce la dimensionalidad en comparación con la codificación One-Hot.
    • Captura un nivel de importancia basado en la ocurrencia de la categoría.
    • Funciona bien con modelos basados en árboles y modelos lineales.
  • Codificación Ordinal: Ideal para variables categóricas con un orden inherente:
    • Preserva el rango relativo de las categorías.
    • Especialmente efectiva para modelos basados en árboles.
    • Requiere conocimiento del dominio para determinar el orden adecuado.

La elección del método de codificación puede impactar significativamente el rendimiento y la interpretabilidad del modelo. Considera estos factores al seleccionar una técnica de codificación:

  • La naturaleza de la variable categórica (ordenada vs. no ordenada)
  • La cardinalidad de la variable
  • El algoritmo de machine learning elegido
  • El tamaño de tu conjunto de datos
  • La necesidad de interpretabilidad en tu modelo

En la próxima sección, exploraremos Codificación Hash y otras técnicas avanzadas diseñadas para manejar conjuntos de datos extremadamente grandes y variables categóricas complejas. Estos métodos ofrecen soluciones para escenarios donde los enfoques tradicionales de codificación pueden no ser suficientes, tales como:

  • Manejar millones de categorías únicas
  • Escenarios de aprendizaje en línea con datos en streaming
  • Entornos con limitaciones de memoria

Al dominar estas técnicas de codificación, los científicos de datos pueden preparar eficazmente datos categóricos para una amplia gama de tareas de machine learning, lo que lleva a modelos más robustos y precisos.