8 · Caso práctico: feature engineering de precios de vuelo
Parsea fechas y duraciones, codifica aerolíneas y transforma logarítmicamente un objetivo de precio sesgado — el pipeline completo de feature engineering para un problema de regresión de precios de vuelo.
EDA es la mitad del trabajo — la otra mitad es feature engineering: parsear fechas, extraer duraciones, codificar nombres de aerolíneas y crear ratios.
Sin esto:
Sin feature engineering, tu columna cruda 'date of journey: 24/03/2019' es inútil para un modelo numérico.
El dataset de calidad de vino era limpio y numérico — un EDA de caso ideal. Los datasets reales de Kaggle no se parecen en nada a eso.
El dataset Flight Price es un primer encuentro común con el desorden de los datos tabulares reales:
- Las fechas llegan como strings:
"24/03/2019" - Las duraciones llegan como strings:
"2h 50m","1h 5m" - Los conteos de escalas llegan como strings:
"non-stop","1 stop","2 stops" - El objetivo de precio está fuertemente sesgado a la derecha
- Los nombres de aerolíneas son nominales con cardinalidad moderada (~5 portadores)
El feature engineering convierte estos strings inutilizables en las columnas numéricas que necesita un modelo. La salida de esta lección es una matriz X lista para el modelo con columnas como journey_day, duration_min, total_stops, airline_freq — y un objetivo log_price.
Python (in browser)
El DataFrame crudo expone el desafío de parseo: `date_of_journey`, `duration` y `total_stops` son todos de dtype `object`. `df.dtypes` es el primer diagnóstico — te muestra qué columnas necesitan ingeniería antes de que cualquier modelo pueda usarlas.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`pd.to_datetime(..., format='%d/%m/%Y')` parsea la columna string; `.dt.day`, `.dt.month`, `.dt.dayofweek` extraen los componentes numéricos. Fin de semana = `dayofweek >= 5` — una variable binaria que frecuentemente predice incrementos de precio.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
Una pequeña función `to_minutes` divide en 'h' y 'm' para extraer horas y minutos de strings como `'2h 50m'`. El resultado `duration_min` es una única variable continua lista para el modelo.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`stops_map = {'non-stop': 0, '1 stop': 1, '2 stops': 2}` — un simple `.map()` de pandas convierte el string ordinal a entero en una línea. Las escalas son genuinamente ordinales (más escalas = viaje más largo = generalmente precio más alto), por lo que un código entero es apropiado aquí.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`np.log1p(price)` comprime la cola derecha y reduce la asimetría de ~2 hacia 0. El objetivo transformado está mucho más cerca de la Normal — un requisito para residuos bien calibrados en regresión lineal.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
Frequency encoding de aerolínea con `df['airline'].map(df['airline'].value_counts())` — una línea, sin riesgo de leakage, captura la cuota de mercado del transportista. Útil cuando la popularidad del transportista es en sí misma un predictor de precio (aerolíneas económicas vs premium).
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
El pipeline post-feature-engineering: las columnas crudas se convierten en columnas numéricas X, el precio transformado logarítmicamente se convierte en y. Nota `np.expm1()` para invertir la transformación logarítmica en tiempo de predicción.
¿Por qué transformar logarítmicamente el objetivo de precio antes de ajustar una regresión lineal?
- `pd.to_datetime(..., format='...')` + `.dt.day` / `.dt.month` / `.dt.dayofweek` convierte un string de fecha en múltiples variables numéricas — día, mes, día de semana, es_fin_de_semana.
- Los strings de duración como `'2h 50m'` requieren una pequeña función de parseo que divide en `'h'` y `'m'` para producir un único entero `duration_min` — un patrón que se repite en todo dataset de logística.
- Para un objetivo numérico con sesgo derecho (precio de vuelo, precio de vivienda, salario), aplica `np.log1p(y)` antes de ajustar y `np.expm1(y_pred)` para recuperar la escala original después de la predicción.
- El feature engineering en datos tabulares consistentemente entrega más mejora que cambiar de modelos — prioriza las variables diseñadas por encima de la arquitectura del modelo.
Los pipelines reales de ML gastan el 60-80% del tiempo de ingeniería en EDA + feature engineering. Las competencias de ML tabulares en Kaggle son ganadas por ingenieros de variables, no por quienes ajustan modelos.
Si lo quitas: Las columnas de strings crudas son inútiles — tu model.fit() o falla o trata los códigos hexadecimales como ordinales.