Límites reales del feature engineering para árboles y ensambles
Introducción
El feature engineering es una etapa crucial en cualquier proyecto de machine learning, donde transformamos datos brutos en características que mejoran la precisión y la generalización de modelos. Sin embargo, los árboles de decisión y sus variantes (como bosques aleatorios o gradient boosting) presentan ciertas limitaciones a la hora de aprovechar al máximo el feature engineering. En este artículo, exploraremos cómo estos modelos pueden afectar nuestro enfoque en la creación de características y cuáles son las mejores prácticas para maximizar su rendimiento.
Explicación principal con ejemplos
Sensibilidad al escalado
Uno de los mayores desafíos que enfrentan los árboles de decisión es la sensibilidad al escalado. Diferentes escalas entre características pueden afectar a la forma en que se dividen las ramas del árbol, lo cual no necesariamente refleja el efecto real sobre la variable objetivo.
Ejemplo:
Supongamos un conjunto de datos con dos características: edad y recaudación. Si la edad está en años (rango 0-120) y la recaudación en miles de euros (rango 0-500), los árboles pueden interpretar diferencias en la edad como más importantes que las mismas diferencias en recaudación. Sin embargo, en realidad, una diferencia de 1 euro puede ser mucho más significativa para el modelo.
import pandas as pd
# Ejemplo de datos
data = {
'edad': [25, 30, 40, 50],
'recaudación': [1000, 1500, 2000, 2500]
}
df = pd.DataFrame(data)
# Escalando la recaudación
df['recaudación'] = df['recaudación'].apply(lambda x: x / 1000)
Captura automática de interacciones
A diferencia de algunos modelos lineales que requieren explícitamente la creación de características interactuantes, los árboles y ensambles pueden capturar estas interacciones automáticamente durante el entrenamiento. Sin embargo, esto tiene sus propias limitaciones.
Ejemplo:
Consideremos una característica edad y otra edad * recaudación. Si creamos manualmente esta característica, podemos asegurarnos de que el modelo la evalúe correctamente. Sin embargo, si no la incluimos, los árboles pueden aún capturar estas interacciones indirectamente a través de las ramas del árbol.
# Crear una nueva columna con la interacción
df['edad_recaudación'] = df['edad'] * df['recaudación']
Riesgos en series temporales
Los árboles y ensambles no son los mejores modelos para trabajar directamente con datos de series temporales. Estos modelos no tienen la capacidad de capturar patrones temporales o dependencias entre observaciones espaciales o temporales.
Ejemplo:
Imaginemos un conjunto de datos con una columna visitas y otra fecha. Si intentamos predecir las visitas en base a estas dos columnas, los árboles no podrán capturar el patrón diario, semanal o mensual que podría existir.
import pandas as pd
# Ejemplo de datos con fecha
df = pd.read_csv('visitas.csv')
df['fecha'] = pd.to_datetime(df['fecha'])
Errores típicos / trampas
Over-engineering de características interactivas
Un común error es crear demasiadas características interactivas, lo cual puede llevar a overfitting y al coste computacional innecesario.
Ejemplo:
Si se crean todas las posibles interacciones entre todas las características disponibles, el árbol podría capturar patrones muy específicos del conjunto de entrenamiento que no serán generalizables.
# Crear una gran cantidad de interacciones
from itertools import combinations
def create_interactions(df):
cols = df.columns[:-1] # Excluyendo la columna objetivo
for combo in combinations(cols, 2):
df[combo[0] + '_x_' + combo[1]] = df[combo[0]] * df[combo[1]]
Ignorar características no lineales
A veces, las relaciones entre características pueden ser no lineales. Los árboles y ensambles son buenos para capturar estas relaciones, pero solo si se presentan en forma de interacciones explícitas.
Ejemplo:
Si la recaudación depende en realidad del logaritmo de edad, un árbol puede no capturar esta relación sin transformaciones previas.
# Transformando una característica
df['log_recaudación'] = df['recaudación'].apply(lambda x: np.log(x))
Ignorar características temporales
Como mencionamos anteriormente, los árboles no son adecuados para series temporales. Sin embargo, se pueden incluir variables temporales si se procesan correctamente.
Ejemplo:
Si queremos usar la fecha como característica, debemos transformarla en una forma que pueda ser útil para el modelo, por ejemplo, extraer el día de la semana o el mes.
df['día_semana'] = df['fecha'].dt.dayofweek
Checklist accionable
- Analiza las escalas: Asegúrate de que todas tus características tienen una escala similar para evitar sesgos en el árbol.
- Crea interacciones significativas: No todos los productos y cocientes de características son necesariamente útiles, selecciona cuidadosamente aquellas que sean relevantes para la tarea.
- Transforma variables no lineales: Si existen relaciones no lineales entre tus características, considera transformarlas (log, sqrt, etc.).
- Procesa variables temporales correctamente: Convierte las fechas en variables útiles, como el día de la semana o el mes.
- Evita over-engineering: No incluyas demasiadas interacciones sin sentido que solo afeiten al rendimiento del modelo.
Siguientes pasos
- Optimiza tu pipeline: Asegúrate de tener un flujo de trabajo automatizado y reproducible para feature engineering.
- Evalúa el rendimiento: Compara constantemente los modelos con y sin nuevas características para asegurarte de que están mejorando la precisión.
- Considera la interpretación: Si estás trabajando en aplicaciones donde la interpretabilidad es crucial, considera modelos más simples o métodos adicionales de feature importance.
Siguiendo estas recomendaciones, podrás aprovechar al máximo el potencial de los árboles y ensambles en tus proyectos de machine learning.