feat(eda): render AutomaticEDA por capítulos sueltos con resolución de dependencias
Permite renderizar un SUBCONJUNTO de capítulos del informe AutomaticEDA (only_chapters=[...]) para iterar/testear un capítulo concreto sin generar el documento entero, garantizando que el capítulo pedido SIEMPRE llegue poblado. - Nuevo módulo automatic_eda/chapter_deps.py: mapa central CHAPTER_DEPS (fuente de verdad) que declara, por capítulo de CHAPTER_ORDER, qué flags de cómputo (run_models/run_series/run_llm) y qué piezas de ctx (raw_numeric, timeseries_raw, geo_points, head_rows, db_path/table) necesita para no salir degradado. Helpers puros: resolve_requirements, resolve_profile_flags, needs_render_ctx, resolve_ctx_data_keys, validate_chapter_ids. - build_document(profile, ctx, only=None): parámetro only opcional que restringe el cuerpo a esos capítulos (portada primera + glosario última siempre). Lee la clave reservada ctx['_only_chapters'] cuando only es None, para propagar la selección a través de los renderers sin modificarlos. Retrocompatible. - render_automatic_eda(..., only_chapters=None): valida los ids (error claro dict-no-throw), resuelve las dependencias activando el cómputo necesario aunque el caller no lo pidiera (un flag explícito siempre prima) y construyendo solo las piezas de ctx que los capítulos pedidos leen (salta build_eda_render_ctx entero si ninguno necesita datos crudos). only_chapters=None produce el documento completo idéntico al de hoy. - Tests: chapter_deps_test.py (resolución pura), build_document_only_test.py (filtro), render_automatic_eda_only_test.py (golden con DuckDB: outliers suelto con IsolationForest poblado por resolución; timeseries activa run_series; eficiencia geospatial sin modelos; edge cases). - .md del pipeline: documenta only_chapters + emit_md; version 1.1.0 -> 1.2.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,8 +4,8 @@ kind: pipeline
|
||||
lang: py
|
||||
domain: pipelines
|
||||
purity: impure
|
||||
version: "1.1.0"
|
||||
signature: "def render_automatic_eda(db_path: str, table: str, backend: str = \"duckdb\", sample: int = None, run_models: bool = None, run_series: bool = None, run_llm: bool = None, profile_level: str = \"standard\", out_dir: str = \"reports\", basename: str = None, ctx_extra: dict = None) -> dict"
|
||||
version: "1.2.0"
|
||||
signature: "def render_automatic_eda(db_path: str, table: str, backend: str = \"duckdb\", sample: int = None, run_models: bool = None, run_series: bool = None, run_llm: bool = None, profile_level: str = \"standard\", out_dir: str = \"reports\", basename: str = None, ctx_extra: dict = None, emit_md: bool = True, only_chapters: list = None) -> dict"
|
||||
description: "Informe AutomaticEDA COMPLETO one-shot de una tabla DuckDB/PostgreSQL: perfila con profile_table, construye el ctx con los datos crudos (build_eda_render_ctx: raw_numeric para modelos/geo, timeseries_raw para series, geo_points para el mapa, db_path/table para la agregacion push-down) y emite PDF (A5 movil) Y PPTX (16:9) del mismo documento por capitulos, con los 11 capitulos POBLADOS de verdad (clusters pintados sobre el PCA, evolucion temporal, mapa geografico y tablas de agregacion), no degradados. El parametro profile_level es un preset de consumo CPU/LLM (lite/standard/full) que mapea a los flags run_models/run_series/run_llm/sample; un flag explicito siempre prima sobre el preset. lite=bajo consumo (sin LLM, sin serie, modelos solo PCA+normalidad sin KMeans/IsolationForest, sample reducido); standard=comportamiento historico; full=standard+narrativa LLM. Devuelve las rutas de PDF/PPTX y el manifiesto de versiones por capitulo."
|
||||
tags: [eda, duckdb, postgres, profiling, pipeline, dataops, report, pdf, pptx]
|
||||
uses_functions:
|
||||
@@ -46,6 +46,10 @@ params:
|
||||
desc: "Nombre base de los archivos sin extension. Default 'aeda_<table>_<timestamp>'."
|
||||
- name: ctx_extra
|
||||
desc: "Dict opcional con claves de presentacion/contexto extra que se mezclan en el ctx (dataset_name, description, source_origin, ...); no pisan las claves de datos calculadas por build_eda_render_ctx."
|
||||
- name: emit_md
|
||||
desc: "Ademas del PDF y el PPTX, emite un Markdown autocontenido del mismo documento por capitulos (texto + tablas markdown, sin binarios) para pegar a un LLM. Default True. La ruta sale en aeda_md_path."
|
||||
- name: only_chapters
|
||||
desc: "Lista opcional de ids de capitulo a renderizar (subconjunto de CHAPTER_ORDER) para iterar/testear un capitulo suelto sin generar el documento entero. Default None => documento COMPLETO (retrocompatible). Cuando se pasa una lista: (1) se VALIDA contra CHAPTER_ORDER, un id desconocido o lista vacia devuelve error claro listando los validos; (2) se RESUELVEN las dependencias de computo de esos capitulos (automatic_eda.chapter_deps) activando los flags que necesiten (run_models/run_series/run_llm) aunque el caller no los pidiera y construyendo SOLO las piezas de ctx que leen, de modo que el capitulo suelto SIEMPRE llega poblado (p.ej. ['outliers'] activa run_models y conserva raw_numeric -> Isolation Forest completo) sin malgastar CPU/LLM en lo que ningun capitulo pedido usa; (3) el documento y su manifest contienen SOLO esos capitulos MAS portada (primera) y glosario (ultima, cuando hay terminos clicables). Un flag explicito del caller prima sobre la resolucion de dependencias."
|
||||
output: "dict {status:'ok', pdf_path:str, pptx_path:str, manifest_path:str|None, n_pages:int, n_slides:int, pdf_note:str, pptx_note:str, profile:<TableProfile>} o {status:'error', error:str} (dict-no-throw)."
|
||||
---
|
||||
|
||||
@@ -69,6 +73,21 @@ r = render_automatic_eda("/tmp/ventas.duckdb", "ventas", profile_level="full")
|
||||
# Precedencia: el flag explicito SIEMPRE prima sobre el preset. lite pero con LLM:
|
||||
r = render_automatic_eda("/tmp/ventas.duckdb", "ventas",
|
||||
profile_level="lite", run_llm=True) # el LLM SI se ejecuta
|
||||
|
||||
# Capitulo SUELTO: itera/testea un capitulo sin generar el documento entero. La
|
||||
# resolucion de dependencias activa el computo que el capitulo necesita aunque no
|
||||
# se pase explicito. Pedir solo 'outliers' activa run_models y conserva
|
||||
# raw_numeric -> el bloque Isolation Forest sale COMPLETO. Documento = portada +
|
||||
# outliers + glosario.
|
||||
r = render_automatic_eda("/tmp/ventas.duckdb", "ventas", only_chapters=["outliers"])
|
||||
|
||||
# Varios capitulos sueltos a la vez (se unen sus dependencias):
|
||||
r = render_automatic_eda("/tmp/ventas.duckdb", "ventas",
|
||||
only_chapters=["correlacion", "missingness"])
|
||||
|
||||
# id desconocido -> error claro listando los validos (dict-no-throw, no lanza):
|
||||
r = render_automatic_eda("/tmp/ventas.duckdb", "ventas", only_chapters=["nope"])
|
||||
# {'status': 'error', 'error': 'only_chapters con ids desconocidos: nope. Capitulos validos: portada, overview, ...'}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
@@ -86,6 +105,16 @@ Para un EDA **barato/rapido** (CI, vistazo previo, maquina sin GPU o sin red) us
|
||||
temporal y el LLM. Para el **maximo** con interpretacion narrativa por capitulo,
|
||||
`profile_level="full"`. El default `"standard"` mantiene el comportamiento previo.
|
||||
|
||||
Cuando estes **iterando o testeando UN capitulo concreto** (afinar el render de
|
||||
outliers, comprobar el mapa geoespacial, depurar la agregacion) usa
|
||||
`only_chapters=[...]`: genera el documento con solo esos capitulos (+ portada y
|
||||
glosario), pero **resuelve sus dependencias de computo** para que el capitulo
|
||||
suelto nunca salga degradado — pedir `['outliers']` activa run_models y conserva
|
||||
`raw_numeric` aunque no los pases, y a la vez no malgasta CPU/LLM en lo que ningun
|
||||
capitulo pedido necesita (pedir `['geospatial']` no corre modelos). Es mucho mas
|
||||
rapido que renderizar el informe entero en cada iteracion. El mapa central de
|
||||
dependencias vive en `automatic_eda/chapter_deps.py` (fuente de verdad).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Impura: ESCRIBE el PDF, el PPTX y `automatic_eda_manifest.json` en `out_dir`.
|
||||
@@ -111,9 +140,29 @@ temporal y el LLM. Para el **maximo** con interpretacion narrativa por capitulo,
|
||||
- Los datos crudos del ctx se muestrean con `sample` (LIMIT), no se trae la tabla
|
||||
entera a RAM; con tablas enormes sube `sample` si quieres mas representatividad
|
||||
(coste: mas memoria).
|
||||
- **`only_chapters` y el glosario**: el glosario (ultimo capitulo) solo aparece si
|
||||
algun capitulo del cuerpo registro terminos clicables. Un capitulo suelto que no
|
||||
registra terminos (p.ej. `timeseries`, `geospatial`) sale como portada + ese
|
||||
capitulo, sin glosario, porque no hay nada que enlazar — es correcto, no un fallo.
|
||||
- **`only_chapters` con `profile_level="lite"`**: en capitulos sueltos el preset
|
||||
solo gobierna `sample`; los modelos NO usan el camino "lite" (que podaria
|
||||
`ctx['raw_numeric']` y dejaria a outliers sin su multivariante en vivo). Quien
|
||||
manda en capitulos sueltos es la resolucion de dependencias, no el preset de
|
||||
coste de modelos.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.2.0 (2026-06-30) — anade el parametro `only_chapters`: renderiza un
|
||||
SUBCONJUNTO de capitulos (para iterar/testear uno suelto) resolviendo sus
|
||||
dependencias de computo via `automatic_eda/chapter_deps.py` (mapa central
|
||||
CHAPTER_DEPS): activa los flags de coste que el capitulo necesita (run_models/
|
||||
run_series/run_llm) aunque el caller no los pase y construye solo las piezas de
|
||||
ctx que lee, de modo que el capitulo suelto SIEMPRE llega poblado (golden:
|
||||
['outliers'] -> Isolation Forest completo) sin malgastar en lo que no usa. La
|
||||
seleccion viaja a build_document por la clave reservada `ctx['_only_chapters']`
|
||||
(los renderers no cambian). Valida ids (error claro dict-no-throw). Cambio
|
||||
aditivo y retro-compatible: `only_chapters=None` produce el documento completo
|
||||
identico a v1.1.0.
|
||||
- v1.1.0 (2026-06-30) — anade el parametro `profile_level` (lite/standard/full),
|
||||
preset de consumo CPU/LLM que mapea a los flags run_models/run_series/run_llm/
|
||||
sample. lite limita los modelos a PCA+normalidad (cableado a run_eda_models con
|
||||
|
||||
Reference in New Issue
Block a user