Pipeline · 3 de 10
Baseline model
Antes de invertir tiempo en infraestructura, un modelo rápido —
hiperparámetros por defecto, directo sobre features.parquet, sin Feast
ni Docker — confirma que el problema se puede aprender.
XGBoost sobre LightGBM
Decidido sin necesitar una comparación empírica — en un dataset de ~6,800
filas, ambos darían calidad similar. Dos motivos concretos: su export a
ONNX es más maduro (necesario más adelante para servir desde Node.js), y
su soporte nativo de categóricas (enable_categorical=True) evita tener
que decidir un encoding manual. Categóricas nativas terminaron ganando
por R² y MAE contra one-hot, con 5 columnas en vez de 34.
Dos modelos separados para Venta y Alquiler en vez de uno con
operation_type como feature más (la razón real está en Decisiones
técnicas), y target en log(price_usd) — mejora el MAE en
ambos modelos.
Resultado: MAPE 15.6% en Venta, 18.0% en Alquiler — contra un baseline trivial (predecir la media) de 117% y 130%. El modelo aprende algo real.
Overfitting encontrado, no ignorado
Feedback externo de un ingeniero ML señaló que el baseline solo reportaba métricas de test. Comparar train vs. test reveló overfitting real: train R²=0.987 vs. test R²=0.759 en Venta, train R²=0.997 vs. test R²=0.534 en Alquiler. Una validación Out-of-Time (entrenar excluyendo febrero 2020, evaluar sobre ese mes) confirmó que el problema era real, no ruido de un solo split — y de paso encontró un bug de datos genuino (13 filas con superficie casi cero y precio/m² absurdo, ver detalle).
5-fold CV reveló algo más serio: con los hiperparámetros por defecto, el R² promedio de Venta entre folds era -0.26 (std 2.16) — el split 80/20 único que se venía usando daba, por pura casualidad, un resultado que se veía bien. La regularización que terminó adoptándose se eligió por estabilidad entre folds, no por el mejor score en un split.
Este modelo — con esta misma feature de precio-por-distrito, sabiendo ya que tiene el caveat de leakage mencionado en el paso anterior — es el que sigue de largo hasta la infraestructura y el feature store. El leakage real no aparece hasta recalcular la feature de forma honesta, en el modelo definitivo.
Artefactos de este paso
| Artefacto | Tipo | Qué es |
|---|---|---|
ml/training/train.py (versión baseline) | Script | Entrena directo sobre features.parquet — todavía sin leer de Feast, esa versión llega en el paso 6. |
data/processed/models/{venta,alquiler}_xgb.json | Modelo | Dos modelos XGBoost nativos (formato propio, no ONNX todavía). Gitignored. |
notebooks/03_baseline_model.ipynb | Notebook | Comparaciones reales: encoding nativo vs. one-hot, un modelo vs. dos, target crudo vs. log, y las 5-fold CV que revelaron el overfitting. |