Predicción de precios de plantas de colección
Un pipeline de regresión sobre ~27 mil anuncios web: baseline honesto, modelos comparados y un diagnóstico claro de por qué el R² es 0.23.
R² en test
0.232
Baseline (mediana): −0.007
MAE en test
$37.65
RMSE ≈ $81.68
Anuncios limpios
26,581
De 27,097 raspados, recorte P1–P99
Modelos comparados
4 + baseline
Ridge, Random Forest, Gradient Boosting y RF ajustado
El problema
Los vendedores de plantas de colección (Monstera, Philodendron, Aglaonema y otras) no saben a qué precio listar una pieza rara. A partir de ~27 mil anuncios obtenidos por scraping de marketplaces como Etsy, eBay, Mercari y Amazon, construí un modelo de regresión que sugiere un rango de precio competitivo.
El foco no fue el algoritmo sino el proceso completo: limpiar datos ruidosos de la web, construir variables desde texto libre, comparar contra un baseline honesto y entender por qué el modelo tiene el techo de desempeño que tiene.
Pipeline de punta a punta
- 1
Limpieza
Parseo del precio (texto con símbolo y comas) a número, conversión numérica de columnas mal tipadas y parseo de fechas.
- 2
Outliers
Recorte a los percentiles 1 y 99 ($4 a $809.11) porque el scraping trae errores extremos que dominan la pérdida cuadrática. Quedan 26,581 filas.
- 3
Target en escala log
Usé log1p(precio): los precios son aproximadamente log-normales y entrenar sobre precio crudo genera heterocedasticidad y deja que las plantas caras dominen el entrenamiento.
- 4
Feature engineering
Tamaño de maceta rescatado del título con regex, flags por palabras clave (rara, grande, chica), días desde la última actualización, largo de título y descripción, y plataforma agrupada en las 10 principales más "otras".
- 5
Preprocesamiento
ColumnTransformer con StandardScaler para numéricas y OneHotEncoder con handle_unknown='ignore' para que producción no falle ante una plataforma nueva.
- 6
Split 70/15/15
Train ajusta parámetros, validación compara modelos y ajusta hiperparámetros, y test se usa una única vez al final.
R² por modelo
Ridge, Random Forest y Gradient Boosting en validación; el Random Forest ajustado con RandomizedSearchCV (20 iteraciones, cv=3) en test.
Qué señales encontró el modelo
Con permutation importance (preferida a feature_importances_ de los árboles, que sobrevalora variables de alta cardinalidad):
- La plataforma de venta es la variable más importante, y un mismo listado vale distinto según el marketplace.
- El largo de la descripción y del título se asocian a precios más altos, probablemente porque los vendedores profesionales describen más.
- Marcar una planta como rara multiplica el precio recomendado (en un ejemplo de Etsy en maceta de 4 pulgadas, de $27 a $64, ~2.4×), y el efecto del tamaño es mayor en plantas raras.
El diagnóstico: por qué el R² es 0.23
El análisis de residuos muestra heterocedasticidad marcada: el modelo es preciso en gama baja y falla en la alta, con errores de más de $700 en plantas de $750–$800 que predice en $40–$60. La distribución de residuos tiene una cola positiva mucho más larga que la negativa, es decir que subestima las piezas caras mucho más de lo que sobreestima las baratas.
El borde diagonal del gráfico de residuos contra predicho no es un defecto del modelo sino un artefacto de haber recortado el precio en $809: el residuo máximo posible es 809 menos la predicción, una recta de pendiente −1.
La causa raíz es de datos: falta la variable más predictiva del dominio, la especie o variedad exacta (una Monstera Albo no vale lo que una genérica). Esa señal vive en el título como texto libre que este pipeline no vectoriza.
Qué se puede afirmar con este modelo
- Sí: un rango de precio aproximado (una banda alrededor de la predicción) y la dirección y magnitud relativa de los efectos de rareza, plataforma y tamaño.
- Sí: ordenar anuncios para detectar cuáles parecen sobrepreciados o subpreciados frente al mercado.
- No: el precio exacto de piezas raras o caras, ni diferencias entre especies concretas, ni valores fuera del rango de entrenamiento.
Extracción de datos con LLMs
Parte del trabajo fue construir los datos que alimentan estos modelos.
- 1
Recolección
Scraping con Beautiful Soup y Selenium de múltiples fuentes web, con datos no estructurados y de calidad dispar.
- 2
Extracción con Gemini
Automaticé la extracción de fichas de producto (nombre, precio, tamaño de maceta) con la API de Gemini sobre HTML parseado, de forma independiente de la estructura de cada sitio.
- 3
Carga estructurada
Salida en JSON validada y cargada en SQL (PostgreSQL) para análisis y modelado.
Qué haría a continuación
- Vectorizar título y descripción (TF-IDF o embeddings) para capturar la especie, que es el mayor impacto esperado.
- Target encoding de la especie o variedad como variable propia.
- Probar boosting moderno (LightGBM) y desplegar la estimación como API con monitoreo de drift.