Quita la frase descriptiva del cuerpo del capítulo ('Cada columna categórica
ocupa su propia página — ...: cardinalidad, top de categorías y gráfico de
barras. El dataset tiene N filas...'); ya vivía duplicada en la entrada de
glosario 'pagina_categorica'. El intro deja solo los términos clicables
mínimos ([[term:entropia]] · [[term:pagina_categorica]]) bajo el heading
'Entropía y cardinalidad'. El total de filas del dataset sigue disponible por
columna en la tabla de cardinalidad ('Total filas (dataset)').
CAP4 num_distr:
- Mueve el párrafo introductorio largo del histograma/boxplot al glosario
(nuevo término clicable "histograma_boxplot"); el cuerpo del capítulo solo
nombra el término con [[term:histograma_boxplot]] y la explicación completa
(código de colores, 1,5·IQR, lectura de asimetría) vive en la entrada del
glosario. La información se traslada, no se pierde.
- Añade por columna numérica la descripción de negocio del LLM y la unidad,
leídas de profile['llm']['dictionary'] (empareja por nombre de columna).
Sin bloque LLM el bloque de descripción se omite limpiamente.
CAP5 cat_distr:
- Mueve el párrafo "Cada columna categórica ocupa su propia página..." al
glosario (nuevo término clicable "pagina_categorica"); el intro solo nombra
los términos entropía y pagina_categorica.
- Añade descripción LLM + unidad por columna (misma fuente que CAP4).
- Cambia el donut/pie por gráfico de barras horizontales (nueva función del
registry categorical_top_bar_figure_py_datascience, contrato de entrada
idéntico al donut para swap directo) más su fallback inline de barras.
- Marca cada Group de columna con layout="side_by_side": en PPTX la tabla de
cardinalidad queda a la izquierda y la barra a la derecha; en PDF se apila
(A5 estrecho). No toca los renderers — el soporte de layout ya existía.
Glosario:
- Catálogo canónico _BASELINE_TERMS con las definiciones de los dos términos
nuevos; build_glosario completa la definición de un término registrado sin
ella desde el catálogo (los chapters solo registran clave+label).
Tests actualizados (donut→barras, side_by_side, LLM desc/unidad, glosario) y
nueva función con sus tests. Suite del subsistema + acceptance verde.
Mejoras transversales del motor AutomaticEDA (PDF + PPTX) sobre el modelo de bloques:
1. DPI alto global: toda figura/imagen embebida se rasteriza a 220 dpi (antes 150,
y en PDF la página se guardaba a ~100 dpi re-rasterizando los imshow). En PDF se
aplica savefig.dpi=220 a la página; el texto sigue vectorial y seleccionable.
Permite ampliar en el móvil sin pixelar. Imagen embebida medida: ~1081px (antes ~492px).
2. Tabla ancha → imagen de alta resolución: cuando un DataTable tiene demasiadas
columnas para ser legible como texto (criterio _table_fits_as_text), se dibuja entera
como una imagen nítida (nueva función render_table_as_figure_py_datascience: cabecera
sombreada + zebra) escalada para caber completa, de modo que el lector hace zoom y la
lee sin perder datos. Las tablas que sí caben siguen como texto seleccionable / tabla
nativa. Aplica en PDF y PPTX. El df.head de 19 columnas del dataset sintético ya no se
corta: sale como imagen.
3. Group.layout: nuevo hint retrocompatible (default "stack"). "side_by_side" coloca la
tabla a la izquierda (~55%) y la figura a la derecha (~45%) en la misma slide PPTX
(cae a apilado si no hay par tabla+figura o no caben); en PDF se trata como "stack"
(el ancho A5 móvil no admite dos columnas). Pensado para que el capítulo cat_distr
ponga el gráfico al lado de la tabla en PPT.
4. Portada con índice clicable: la lista de capítulos pasa de "Este informe incluye..."
(markdown) a un Heading "Índice" + un TocEntry por capítulo. El renderer registra el
inicio de cada capítulo y cablea cada entrada como salto real (PDF: link GOTO PyMuPDF;
PPTX: salto a slide nativo), reutilizando el mecanismo del glosario clicable.
Modelo: Group gana `layout`; nuevo bloque TocEntry; normalizers y __init__ actualizados.
Contrato: documentado en docs/automatic_eda_contract.md §11.4 (incluye el contrato exacto
del campo layout para el agente de cat_distr).
Tests: nuevo render_quality_test.py (13 golden: DPI alto real, tabla ancha→imagen PDF/PPTX,
narrow→texto, side_by_side PPTX dos columnas / PDF apilado, índice clicable PDF+PPTX,
retrocompatibilidad layout por defecto). render_features_test actualizado al índice nuevo.
Suite: 188 passed (módulo) + 38 passed/1 skipped (acceptance + pipeline).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La tabla DICCIONARIO de columnas del capitulo overview gana columnas
"Descripcion" y "Unidad", y la tabla DESCRIBE gana "Unidad", consumiendo
profile['llm']['dictionary'] (entradas column/description/business_meaning/unit
producidas por eda_llm_insights) emparejadas por nombre de columna. Lectura
defensiva: sin bloque LLM (run_llm no corrio) las celdas degradan a "—" y las
tablas siguen renderizando. No recalcula nada ni llama al LLM.
CHAPTER_VERSION 1.1.0 -> 1.2.0. Tests: golden (descripcion+unidad pobladas para
income), edge (sin LLM -> "—"), fallback ctx['llm'], y render PDF con las
columnas nuevas visibles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Itera el capítulo PORTADA del AutomaticEDA y dos mejoras globales de los
renderers PDF/PPTX:
1. Zebra global (PDF): _place_kv_table ahora sombrea las filas pares igual que
las DataTable, así toda tabla del documento queda rayada (no solo las
DataTable). Mismo patrón coherente al partir/repetir cabecera.
2. Portada usa la descripción LLM rica (profile['llm']['summary']) cuando el
perfil la tiene; se elimina del fallback derivado el texto ruido
"active la interpretación LLM (run_llm)…". No fuerza llamadas LLM en el
capítulo, solo consume profile['llm'] si está.
3. Se quita el bloque "Criterios de calidad" de la portada (PDF y PPTX);
el score "Calidad" se mantiene.
4. "Resumen del análisis" (PDF): los valores se alinean al margen derecho via
el nuevo KVTable.value_align="right".
5. Nombre del dataset en la portada PPTX más grande (44pt) y subrayado via los
nuevos hints Heading.underline / Heading.size_pt (el PDF los ignora).
Bump CHAPTER_VERSION de portada 1.2.0 -> 1.3.0.
Verificado: suite 213 passed / 1 skipped (incl. aceptación de los 16 capítulos);
golden zebra = 185 filas zebra en 13 capítulos del PDF completo; portada con
run_llm sin "Criterios de calidad", con descripción LLM rica y valores a la
derecha; PPTX con nombre 44pt subrayado; edge sin LLM cae al fallback derivado
sin ruido; fn index sin error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bateria que blinda el subsistema: cobertura de los 16 capitulos sobre el dataset
sintetico Faker, contenido esencial por capitulo (needles parametrizados),
capitulos sueltos con resolucion de dependencias (only_chapters=[outliers] puebla
IsolationForest sin run_models; timeseries; correlacion), None cuando no aplica,
folder multi-tabla con FK, completitud del MD (matriz de correlacion completa +
skew/kurtosis), 3 salidas no vacias, determinismo. Test full+LLM skippeable.
29 passed, 1 skipped. Sin hallazgos: los 16 capitulos salen como deben.
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>
Nuevo capítulo dedicado `outliers` para el motor AutomaticEDA que reúne y
profundiza en un solo sitio el análisis de valores atípicos, hoy disperso entre
`num_distr` (conteo por columna) y `modelos` (IsolationForest). Se registra en
`chapters_registry.py` entre `missingness` y `correlacion` (bloque de calidad de
datos: calidad → missingness → outliers).
Contenido del capítulo:
- Resumen univariante por columna: nº y % de atípicos por Tukey (1.5·IQR) y por
z-score (|z| > 3), con vallas inferior/superior y valores extremos. Ordenado
por contaminación y marcando las columnas más afectadas. Reusa las funciones
del registry `build_boxplot_stats` (vallas desde los percentiles del profile)
y `detect_outliers` (regla z-score sobre la muestra cruda de `ctx`).
- Boxplots de Tukey de las columnas más contaminadas (caja, bigotes y puntos
atípicos), delegados a la función nueva `build_boxplots_figure`.
- Multivariante: filas anómalas considerando todas las columnas a la vez con
`isolation_forest_outliers` — nº y % de filas, las más anómalas con su score y
las dimensiones que las hacen raras (top columnas por |z|, vía la función nueva
`summarize_outlier_dims`). El detector se corre en vivo sobre `raw_numeric`
para que el indexado de filas coincida exactamente con el de las dimensiones;
cae al bloque precomputado del perfil cuando no hay muestra cruda (preset lite).
- Interpretación exploratoria: un atípico no es necesariamente un error
(distingue error de dato vs dato real extremo) y recomendaciones (revisar,
winsorizar o re-expresar, enlazando con la re-expresión de Tukey del perfil).
Términos clicables registrados en el glosario compartido: `outlier`,
`tukey_fence`, `zscore`, `isolation_forest`.
Funciones nuevas del registry (dominio datascience, grupo eda):
- `build_boxplots_figure_py_datascience` (figure helper, impura)
- `summarize_outlier_dims_py_datascience` (pura)
El capítulo se activa con ≥1 columna numérica y devuelve None en su ausencia;
lee todo defensivo y nunca lanza. Tests: capítulo (golden + edges + error path +
render PDF/PPTX) y ambas funciones nuevas. Suite de no-regresión de AutomaticEDA
verde. Verificado end-to-end con el dataset Titanic (Fare/Parch/SibSp como las
columnas más contaminadas).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
draw_join_graph_figure (datascience, grupo eda): dibuja el join graph de la base
como una matplotlib Figure real (networkx spring_layout seed=42, nodos = tablas,
hubs destacados, flechas dirigidas con etiqueta from_col->to_col + cardinalidad).
Nunca lanza: devuelve una Figure de error si algo falla; entrada vacia -> Figure
'Sin relaciones FK detectadas'.
render_automatic_eda_folder ahora inserta esa Figure (bloque Figure lazy via make)
en el capitulo de relaciones cuando hay edges, ademas del texto Mermaid (util para
el MD/LLM). Antes solo se volcaba el texto del grafo; ahora el PDF/PPTX muestran el
diagrama dibujado. Tests nuevos: la Figure real se construye con edges y se omite
sin edges.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Subsistema de papers reproducibles (grupo de capacidad `papers`). Añade las
funciones estadísticas que un paper honesto necesita y la función que congela la
hipótesis antes de mirar los datos (anti-HARKing).
Nuevas funciones (puras salvo la última):
- effect_size_cohens_d: Cohen's d + Hedges' g (corrección de sesgo para N
pequeño) + interpretación cualitativa (negligible/small/medium/large por los
umbrales de Cohen). Dict-no-throw ante varianza cero / N insuficiente.
- confidence_interval_mean: intervalo de confianza de una media (t de Student) o
de la diferencia de medias con Welch (df de Welch–Satterthwaite, sin asumir
varianzas iguales). Dict-no-throw; el IC colapsa al punto cuando la varianza es
cero.
- preregister_hypothesis (impura): congela hipótesis + plan de análisis en
papers/<slug>/preregistration.md con frozen_at (UTC) y content_hash (sha256 del
cuerpo normalizado, no del frontmatter). Inmutabilidad: una vez frozen, un
contenido distinto se RECHAZA sin sobrescribir (mata el HARKing); idempotente si
el contenido es idéntico. Siempre dict-no-throw.
Extensión:
- fdr_correction 1.0.0 -> 1.1.0: añade method="holm" (Holm-Bonferroni step-down,
controla FWER, más potente que Bonferroni simple). Reúsa la maquinaria de
alineación 1:1 con None/inválidos; no rompe los métodos bh/bonferroni.
Reutiliza del registry: fdr_correction (BH + Bonferroni ya existían) como base
para Holm. pearson y spearman_corr ya cubrían correlación.
Tests: 36 pytest verdes (cohen/hedges 8, confidence/welch 8, fdr/holm/bonferroni
12, preregister 4 + extras), golden contra valores conocidos y validados con
scipy. Golden manual del preregistro: congela, idempotente, rechaza edición
(bytes en disco idénticos al congelado).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Subsistema papers/: pieza de entrega + control de calidad.
- render_paper_pdf_py_datascience (Python, impure, dominio datascience, grupo
`papers`): convierte papers/<slug>/paper.md (frontmatter YAML + cuerpo IMRaD)
en papers/<slug>/out/paper.pdf. Reutiliza el motor de paginación de flujo del
paquete automatic_eda (matplotlib PdfPages, el mismo PDF móvil A5 de los
informes EDA) — no reimplementa paginación ni toca matplotlib, y no añade
dependencias. Cada sección IMRaD (# H1) → un Chapter en página nueva; portada
desde el frontmatter (title/authors/date europea/abstract); detecta las
imágenes Markdown  que el motor no entiende y las parte en bloques
Image resueltos contra base_dir y base_dir/figures/. dict-no-throw estricto.
5 tests verdes (golden + edges: sin frontmatter, path inexistente, figura
inexistente, ruta directa al .md).
- .claude/agents/paper-reviewer: revisor académico adversarial read-only (gate
anti paper-mill). Puntúa novedad/rigor/reproducibilidad/validez (0-5), intenta
refutar cada claim contra la evidencia citada, detecta HARKing contra el
preregistration.md, exige limitaciones declaradas y claims ≤ evidencia, y
emite veredicto estructurado JSON (accept|major_revision|reject) con default
conservador. Tools: Read, Grep, Glob, Bash (sin Edit/Write: solo juzga).
Diseño completo: reports/0001-2026-06-30-papers-system-design.md (agente C).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade el capítulo `missingness` al motor AutomaticEDA, complemento natural de
`calidad`: donde calidad reporta cuánto falta por columna, este capítulo analiza
el PATRÓN de los nulos — dónde faltan y si las columnas faltan juntas
(co-ocurrencia de ausencias), la señal que distingue MCAR de MAR antes de imputar.
Capítulo (`chapters/missingness.py`), registrado en `chapters_registry.py` justo
tras `calidad`:
- Resumen global: % de celdas faltantes, columnas con nulos, filas completas vs
incompletas.
- Ranking por columna (tabla + barras horizontales).
- Co-ocurrencia: correlación de las máscaras is-null entre columnas (heatmap +
tabla de los pares que co-faltan, con co-faltantes y Jaccard).
- Patrones de fila más frecuentes (estilo matriz de missingno).
- Lectura MCAR/MAR exploratoria (heurística por correlación/solape de ausencias,
no confirmatoria), que cita la evidencia concreta.
- Términos de glosario clicables: missingness, MCAR, MAR.
La máscara is-null por fila de TODAS las columnas (numéricas y categóricas) se
construye con un push-down DuckDB sobre ctx['db_path']/table (mismo patrón que el
capítulo agregación), con fallback a ctx['raw_numeric'] cuando no hay BD. Activa
solo si la tabla tiene nulos; si no, devuelve None.
Funciones nuevas del grupo `eda` (dominio datascience):
- extract_null_mask (impura): máscara is-null por fila vía query_fn.
- missingness_overview (pura): resumen global + filas completas/incompletas.
- missingness_correlation (pura): correlación de ausencias + pares + Jaccard,
reutiliza pearson.
- missingness_row_patterns (pura): patrones de fila más comunes.
- missingness_corr_heatmap_figure / missingness_rank_bar_figure (impuras): figuras.
Verificado: EDA de titanic genera el capítulo en PDF + PPTX + MD con Cabin 77.1%,
Age 19.9% y la co-ocurrencia Age↔Cabin (158 filas). Suite completa de AutomaticEDA
+ render_automatic_eda en verde (125 passed); tests por función y por capítulo;
fn index sin error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nuevo tipo de artefacto para papers académicos reproducibles (papers/<NNNN-slug>/):
- Plantillas docs/templates/paper.md (IMRaD completo con guías por sección:
Abstract, Introduction, Related work, Methods, Results, Discussion con
Limitaciones + Amenazas a la validez, Conclusion + Future work) y
docs/templates/preregistration.md (H0/H1 falsable, variables, diseño, plan
de análisis con test exacto + effect size + corrección múltiple, predicción
cuantitativa; nota anti-HARKing de congelado).
- Pipeline init_paper (bash/functions/pipelines/init_paper.sh + .md): calcula el
siguiente NNNN, crea las subcarpetas (experiments data figures reviews out),
copia las plantillas rellenando el frontmatter (title, slug, date, phase=question,
status=draft) y crea references.md. No hace git init (fase interna local).
- Función atómica reutilizable next_numbered_dir (bash/functions/io): siguiente
prefijo NNNN- escaneando un directorio numerado (reutilizable por papers/reports/issues).
- papers/ como artefacto local gitignored (bloque en .gitignore + papers/.gitkeep):
un paper en fase interna no contamina el repo padre; al promocionar a publishable
se vuelve sub-repo Gitea propio.
- Página de capacidad docs/capabilities/papers.md + fila en el INDEX: tabla de
funciones del grupo papers (disponibles + en construcción por la flota), ejemplo
canónico end-to-end y fronteras.
Reutiliza slugify_ascii del registry. Diseño: reports/0001-2026-06-30-papers-system-design.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade el capítulo `text_distr` al motor AutomaticEDA: perfila columnas de texto
libre largo (reseñas, descripciones, comentarios) que la distribución categórica
no resume bien. Sigue el patrón de cat_distr/num_distr (build_text_distr(profile,
ctx) -> Chapter | None) y se registra en CHAPTER_ORDER tras cat_distr.
Activación en dos fases: gate barato desde el perfil (columna no numérica con
len_mean >= 50 chars) + confirmación con muestra cruda (mediana de palabras >= 20).
Un dataset sin texto largo (p.ej. titanic) devuelve None sin tocar el informe.
Bloques por columna (Group con page_break): resumen (longitudes, vocabulario con
TTR y % hapax, idioma dominante, % duplicados, legibilidad), histograma de
longitudes, top términos (tabla + barras), bigramas/trigramas, idiomas detectados
y nube de palabras opcional. Términos ttr/hapax enganchados al glosario clicable.
Lógica delegada a 7 funciones nuevas del registry (datascience, tag eda),
estilo dict-no-throw:
- extract_text_sample (impura, push-down SQL DuckDB/Postgres)
- compute_text_length_stats, compute_vocabulary_stats, compute_top_ngrams (puras, stdlib)
- detect_corpus_language (langdetect opcional), compute_text_readability (textstat
opcional), compute_text_duplicates (hash + datasketch opcional)
Versión barata sin modelos pesados: las piezas que dependen de una librería
opcional (langdetect, textstat, wordcloud, datasketch) degradan a omitidas sin
lanzar. Añade langdetect y textstat (ligeras) al pyproject + uv.lock.
Verificado: golden sobre dataset de reviews multi-idioma (capítulo presente en
PDF+PPTX+MD con métricas reales), titanic sin capítulo (None), degradación sin
libs, suite automatic_eda + pipeline verde (128 passed), fn index OK.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade al capítulo `correlacion` del AutomaticEDA la visualización con scatters de
los pares numérico-numérico más correlacionados (positiva y negativamente) y,
para cada uno, la clasificación del tipo de relación: lineal, polinómica
(grado 2/3), monótona no-lineal o débil/sin forma.
Funciones nuevas del registry (dominio datascience, grupo eda):
- classify_relationship_type_py_datascience (pura): dadas dos listas numéricas
pareadas, cruza Pearson r (lineal), Spearman ρ (monótona) y ajustes
polinómicos de grado 2 y 3 (numpy.polyfit + R² manual) para etiquetar la
forma. Reusa pearson y spearman_corr del registry. Umbrales calibrados para
datos reales discretos/ruidosos (orden: débil → monótona → polinómica →
lineal). Devuelve los coeficientes del mejor modelo para pintar la curva.
No-throw.
- relationship_scatter_figure_py_datascience (impure): construye la Figure
matplotlib del scatter de un par con su recta/curva de ajuste y una anotación
del tipo + métricas (r, ρ, R²lin, R²poly). Backend Agg sin pyplot global,
downsample determinista de los puntos dibujados, tendencia ordenada (binned /
por valor) para el caso monótona sin polinomio. Defensiva ante vacío.
Capítulo correlacion.py (1.0.0 → 1.1.0): nueva sección "Relaciones más fuertes
(scatter)" tras la matriz + tablas top. Toma los top-K pares num↔num por |valor|
de profile['correlations']['pairs'], obtiene los datos crudos de cada par desde
ctx['raw_numeric'] y emite, por par, un Figure dentro de un Group keep-together
junto a una nota de texto con el tipo de relación (extraíble por pdftotext).
Solo num↔num: los pares cat↔cat (Cramér's V) y num↔cat (razón de correlación)
no llevan scatter. Cuando no hay raw_numeric (perfil lite/agregado o ctx None)
los scatters se omiten sin lanzar; la matriz + tablas siguen.
Verificado: golden EDA de titanic (run_models) — el capítulo Correlación del PDF
y PPTX incluye los scatters (pclass↔fare → monótona no-lineal, sibsp↔parch →
lineal, …) con su ajuste y etiqueta de tipo en texto. Tests de clasificación
sintética (lineal, y=x² → polinómica, y=exp(x) → monótona, ruido → débil) +
tests del capítulo (golden con raw_numeric, edge sin raw, par sin columna). Suite
automatic_eda + pipeline render_automatic_eda verde (141 passed). fn index sin
error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pipeline render_automatic_eda_folder: apunta el AutomaticEDA a una CARPETA de
archivos tabulares (CSV/Parquet/JSON) o a una DuckDB existente y emite el informe
de la BASE por capitulos en PDF (A5 movil) + PPTX (16:9) + Markdown. Documento-base
con portada-base, resumen de todas las tablas y relaciones inter-tabla (FK
candidatas por containment + diagrama Mermaid del join graph). Flag per_table_eda
anexa el mini-EDA de cada tabla. Aditivo: render_automatic_eda (tabla unica) intacto.
Funcion nueva load_folder_to_duckdb (infra, grupo eda+duckdb): carga una carpeta a
una DuckDB (temp si no se da path), CREATE TABLE por archivo con read_csv_auto/
read_parquet/read_json_auto. dict-no-throw.
Compone profile_database + los 3 renderers del motor AutomaticEDA + build_document
(per-tabla), sin reimplementar su logica. Tests: golden 3 CSV relacionados (FK
orders.customer_id->customers.id detectada) + edges (carpeta vacia, 1 tabla,
DuckDB existente, path inexistente). fn index sin error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El .md del grupo `eda` es la salida pensada para pegar a un LLM, así que debe
contener todo lo que el motor computó, aunque el PDF/PPTX (vista humana) resuman.
La evaluación 2053 detectó 6 datos que el .md perdía respecto al profile. Se
cierran de forma aditiva (el .md tiene MÁS que el PDF/PPTX, sin tocar esos
renderers ni los capítulos).
render_automatic_eda.py pasa el profile al serializador Markdown vía
meta['profile'] (un meta propio del MD; el de PDF/PPTX queda intacto).
render_md_impl.py añade un "Apéndice — Datos completos del perfil" al final del
documento, emitido solo cuando hay profile y degradando limpio cuando falta una
sección (lite sin modelos, profile sin correlaciones). El apéndice no se acopla
a los ids de capítulo (que editan otros agentes en paralelo).
Pérdidas cerradas:
1. Matriz de asociación COMPLETA: los N pares de correlations.pairs (no solo el
top-17), incluidos correlation_ratio (num↔cat) y cramers_v (cat↔cat).
2. Numéricas: describe completo por columna — mean/median/mode/std/variance/cv,
skew y kurtosis para TODAS (no solo las asimétricas), p1/p5/p25/p50/p75/p95/
p99, iqr, min/max, outliers, distribution_type.
3. Re-expresión: nombra la transformación concreta (log1p/sqrt/yeo-johnson) con
potencia, razón y alternativas, no un vago "considerar re-expresión".
4. KMeans: tabla scores_by_k (silhouette + inercia por k) marcando el k elegido.
5. Normalidad: el estadístico (stat) de cada test junto al p-value.
6. Encabezados de figuras de barras/scree dejan de heredar
"Desde/Hasta/Frecuencia" del histograma; usan "Inicio/Fin/Valor" cuando el
caption no es un histograma.
Test nuevo md_completeness_test.py: profile sintético, asserta los N pares de
correlación, skew/kurtosis de cada numérica, percentiles extendidos, log1p,
scores_by_k, stat de normalidad, headers de barras y los edges (sin modelos /
sin correlaciones / sin profile, defensivo).
Verificado con titanic (profile_level=full): 28 pares en la tabla (incl.
Sex↔Embarked cramers_v), 7 numéricas con skew+kurtosis, p5/p95/p99, scores_by_k
y JB/D'Agostino/Shapiro stat presentes. PDF/PPTX/manifest siguen saliendo.
Suite automatic_eda + render_automatic_eda_test: 134 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La verificación adversarial detectó que, en PPTX (slide 16:9, corto), las columnas
categóricas de ALTA cardinalidad NO id-like (Ticket, Cabin) ocupaban 3 slides cada
una con el donut SEPARADO de su tabla: el top-k de 8 filas largas no cabía junto al
donut y el keep-together partía la columna. (El PDF, en A5, ya estaba 1:1 correcto.)
Arreglo SOLO en render_pptx_impl.py:
- `_fit_group_blocks` (nuevo): para un Group con figura + DataTable que no cabe en el
slide, reserva un alto mínimo para el donut (`_GROUP_MIN_FIG_H`) y recorta las filas
de la DataTable a lo que queda, de modo que el gráfico se queda en el MISMO slide,
junto a su tabla. No-op cuando ya cabe o no hay par figura+tabla (p.ej. columnas
id-like, que ya omiten la top-k).
- `_trim_data_table_to_budget` (nuevo): devuelve una COPIA de la DataTable con las
filas que caben (al menos una) + nota honesta "top N de M categorías mostradas
(recortado para caber en el slide; el PDF muestra más)". NUNCA muta el bloque
original, que es compartido con el renderer PDF (el PDF sigue mostrando la tabla
completa en A5).
- `_place_group`: aplica `_fit_group_blocks` antes de `_shrink_group_figures`.
Refuerzo de cat_distr_test.py:
- `test_golden_pptx_una_slide_por_columna_con_su_grafico`: perfil con una columna
categórica de alta cardinalidad no-id-like (40 valores largos sobre 5000 filas,
0.8% distinto) que reproduce el caso Ticket/Cabin. Asierta que CADA columna
categórica aparece en EXACTAMENTE UN slide del capítulo y que ese mismo slide lleva
su tabla (Cardinalidad/distintos) Y su donut (caption + shape Picture) — el gráfico
nunca se separa de su tabla. Sustituye al laxo `n_slides >= 2`.
Verificado con titanic_train.csv (render_automatic_eda run_models=True): 5 columnas
categóricas (Name, Sex, Ticket, Cabin, Embarked); PDF 6 páginas y PPTX 6 slides del
capítulo (intro + 1 por columna), cada columna con su donut junto a su tabla en una
sola página/slide. Ticket y Cabin pasaron de 3 slides a 1. Suite verde (122 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cada columna categórica del capítulo CAT DISTR ocupa ahora su propia página
(PDF) / slide (PPTX) con su gráfico junto a su tabla, y se elimina la
explicación larga de la entropía que duplicaba el capítulo GLOSARIO.
Cambios:
- model.Group: nuevo campo aditivo `page_break_before` (default False). Cuando
es True el renderer fuerza al grupo a empezar en página/slide nueva (salvo que
la actual esté vacía). Comportamiento de todos los capítulos existentes
intacto. Soportado también en el normalizador dict-defensivo `as_block`.
- render_pdf_impl / render_pptx_impl `_place_group`: respetan `page_break_before`.
- render_pdf_impl / render_pptx_impl `_measure_block`: medición fiel de KVTable y
DataTable (replica `_place_*`: título-heading, wrap del valor/celdas por
columna, nota). La estimación previa asumía una línea por fila e ignoraba el
título, así que el keep-together infra-presupuestaba la figura y el gráfico se
desbordaba a la página siguiente. Helpers `_measure_kv_table`/`_measure_data_table`.
- render_pptx_impl `_shrink_group_figures`: umbrales más bajos (budget>0.6,
per>0.35) para que en el slide corto 16:9 la figura se encoja y conviva con la
tabla en lugar de partir la columna (misma filosofía keep-together del PDF).
- cat_distr.py:
- build envuelve cada columna en un `Group(page_break_before=idx>0)`: una
columna por página/slide, con su tabla de cardinalidad, su top-k y su donut
juntos. La primera comparte página con la intro para no dejar una casi vacía.
- intro recortada: se elimina el párrafo que explicaba qué es la entropía
(vive en el capítulo GLOSARIO, donde el término `[[term:entropia]]` enlaza);
se conserva el término clicable y el total de filas de referencia.
- `_cardinality_block`: métricas relacionadas agrupadas por fila (distintos·%·
únicos; entropía bits·máx·norm; desbalance·longitud) sin perder ningún dato,
para que tabla + gráfico quepan en el slide 16:9.
- columnas id-like (≈100% distintas): se omite la top-k (sería una lista de
valores únicos; la nota lo explica) y el donut ocupa ese hueco.
- CHAPTER_VERSION 1.1.0 -> 1.2.0.
Verificado con titanic (render_automatic_eda run_models=True): PDF 5 páginas y
PPTX 5 slides del capítulo (intro + 1 por columna: Name, Sex, Ticket, Embarked),
cada columna con su gráfico junto a su tabla, sin cortes. Suite verde
(121 passed): pytest automatic_eda/ + render_automatic_eda_test.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ahora que el AutomaticEDA tiene un capítulo GLOSARIO con las definiciones de los
términos técnicos (enganchados como links clicables desde el cuerpo), los
capítulos calidad/correlacion/modelos/agregacion/relaciones ya no repiten inline
esas explicaciones largas: se deja el TÉRMINO marcado (clicable, sigue saltando
al glosario) y se elimina el párrafo/oración de definición redundante. Los
HALLAZGOS y datos concretos del análisis se mantienen intactos; solo se quitan
las definiciones generales que el glosario ya cubre.
- calidad: _criteria_intro pasa de un bullet-list con las definiciones de
completitud/validez/unicidad/calidad + fórmula renormalizada + párrafo de
outliers a una frase que nombra las dimensiones, sus pesos (60/40) y el
principio de outliers; los 4 términos siguen marcados.
- modelos: la nota de normalización deja de explicar la fórmula del z-score; la
intro de PCA ya no define "componentes ortogonales ordenados por varianza"; la
de KMeans quita "rango −1 a 1: cuanto más alto..." (silhouette); la sección de
Isolation Forest quita la descripción de árboles/cortes/umbral. Términos
marcados intactos.
- correlacion: la intro deja de describir cada método y consolida la duplicación
signo/dirección; los 4 métodos + FDR siguen marcados.
- agregacion: la intro quita la definición de pivot ("cruzan dos categóricas
sobre una medida") y abrevia la selección de claves; groupby y pivot marcados.
- relaciones: la intro y la sección de candidatas/inter-tabla quitan las
definiciones de PK ("identifica cada fila"), FK ("referencian a otra tabla") y
containment ("valores contenidos en la clave de otra"); pk/fk/cardinalidad/
containment siguen marcados.
Verificado sobre el EDA de titanic (run_models + run_llm, 48 págs): los 23 link
annotations término→glosario se conservan (PyMuPDF), el glosario mantiene las 20
definiciones, y el texto visible de los 5 capítulos baja un 34.7% en conjunto
(calidad −67%, modelos −33%, relaciones −19%, agregacion −15%, correlacion −8%).
Tests actualizados (calidad_test asertaba el texto viejo). Suite EDA + pipeline
verde (118 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade un tercer formato de salida al AutomaticEDA, junto al PDF y el PPTX:
un Markdown autocontenido del MISMO documento por capítulos
(chapters_registry.build_document), optimizado para incorporar a un LLM
(texto plano + tablas markdown reales, sin binarios incrustados).
- render_md_impl.render_md(chapters, out_path, meta): serializa los bloques
del modelo (Heading/Markdown/KVTable/DataTable/Figure/Image/Caption/Note/
Group/GlossaryEntry) a Markdown. Cabecera con metadatos + índice navegable
con anclas GitHub; tablas volcadas enteras (el MD no pagina); marcadores de
glosario eliminados conservando la negrita; glosario al final.
- Figuras: un LLM no ve la imagen, así que se prioriza texto + datos. Se emite
el caption y, cuando la figura tiene barras (histograma), se extrae la tabla
de bins (Desde/Hasta/Frecuencia) de los artistas matplotlib. La banda ±1σ
(axvspan) se descarta por ancho para que no aparezca como un falso bin.
PNG opcional vía meta['embed_figures'] (off por defecto → sin binarios).
- render_automatic_eda_markdown: función pública del registry (tag eda),
espejo de render_automatic_eda_pdf/pptx, acepta lista de capítulos o un
TableProfile (build_document). dict-no-throw.
- render_automatic_eda (pipeline): emite también el .md (emit_md=True por
defecto, clave de retorno aeda_md_path). Cambio aditivo: PDF/PPTX/manifest
siguen saliendo igual.
Tests: golden de todos los kinds + regresión del filtro de la banda ±1σ +
edge documento vacío + profile path. Suite del paquete y del pipeline verde
(122 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade el parámetro profile_level a render_automatic_eda como preset de
consumo CPU/LLM que mapea a los flags existentes (run_models, run_series,
run_llm, sample). Tres niveles:
- lite (bajo consumo): run_llm=False, run_series=False, sample=2000 y modelos
limitados a PCA + normalidad, SIN KMeans ni IsolationForest (lo caro en CPU).
Para un vistazo rápido y barato.
- standard (default): comportamiento histórico — modelos completos, serie,
sin LLM.
- full: standard + narrativa LLM por capítulo.
Precedencia: un flag explícito del caller (run_llm=..., run_models=..., etc.)
siempre prima sobre el default que fija el preset; el preset solo aplica al
parámetro que se deja en None.
Cableado del modo lite sin tocar profile_table (lo tocan otros agentes en
paralelo): profile_table NO corre los modelos (evita pagar KMeans +
IsolationForest); este pipeline los corre con run_eda_models(run_kmeans=False,
run_isolation=False) reusando ctx['raw_numeric'], y quita raw_numeric del ctx
para que el capítulo modelos no reproyecte clusters KMeans en vivo
(project_clusters_2d). geo_points ya queda derivado, así que geospatial no se
afecta.
Cambio aditivo y retro-compatible: sin profile_level el comportamiento es
idéntico al de v1.0.0 (standard). Tests nuevos cubren lite/standard, la
precedencia flag-sobre-preset, y la equivalencia del default con el histórico.
Bump 1.0.0 -> 1.1.0 + growth log en el .md. Skill /eda documenta --lite/--full.
Verificación: golden lite/standard/full sobre titanic — lite 4.8s (PCA+norm,
sin KMeans/iso/LLM/serie), standard 7.8s (modelos completos), full 38.3s
(+LLM). Suite render_automatic_eda + automatic_eda: 96 passed. fn index sin
error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade el capítulo `relaciones` al motor AutomaticEDA: analiza las
relaciones de clave de la tabla/base y se coloca tras `correlacion`,
antes de `modelos`, en CHAPTER_ORDER.
Capas que renderiza (solo las que aplican; None si no hay nada que decir):
- Claves declaradas: PK/FK/UNIQUE reales del esquema DuckDB, vía la nueva
función `detect_declared_keys_duckdb` (lee `duckdb_constraints()`).
- Candidatos a clave primaria: los `key_candidates` del TableProfile.
- FK candidatas inter-tabla: reusa `infer_fk_containment_duckdb`
(containment + señal de nombre) y `build_join_graph` (roles de nodos +
diagrama Mermaid pegable). Solo si la fuente DuckDB tiene varias tablas.
- FK candidatas intra-tabla: heurística nombre + cardinalidad, vía la nueva
función pura `suggest_intratable_fk_candidates`, marcada como sugerencia.
Engancha al glosario clicable los términos PK, FK, containment/inclusión y
cardinalidad (contrato §11.1) y usa Group (keep-together) para el grafo.
Funciones nuevas del registry (grupo `eda`):
- detect_declared_keys_duckdb (impure, datascience) + test.
- suggest_intratable_fk_candidates (pure, datascience) + test.
Tests: relaciones_test.py (golden intra + inter, edges, no-cut render) +
los tests de ambas funciones. Suite automatic_eda + render_automatic_eda
verde (89 passed). Golden end-to-end con el pipeline render_automatic_eda
verificado sobre titanic (intra) y una BD customers/orders (inter).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implementa el modelo de calidad del report 2046 en el grupo eda.
Score de columna: 0.6·completeness + 0.4·validity con renormalización por
aplicabilidad (si la validez no es medible —texto libre o columna 100% nula— el
score se basa solo en completeness). Validez = conformidad real al tipo: nativo
numérico/fecha/bool = 1.0; texto promovido a número/fecha = parse rate
(validity_rate); texto con semantic_type = match_rate; texto libre = no aplica.
Outliers, columnas constantes e identificadores salen del score a un bloque de
observaciones analíticas (no son defectos de calidad). Se elimina el doble
conteo de la falta de datos (mostly_null ya no castiga validez) y el bug de
escala de outliers (que además ya no entran en el score).
Score de dataset: 100·(0.85·cell_quality + 0.15·row_uniqueness) en vez de la
media simple. Se pobla duplicate_rows/duplicate_pct push-down en
summarize_table_duckdb (COUNT sobre DISTINCT *, sin RAM) para habilitar la
unicidad de registro; renormaliza a solo cell_quality si no se puede calcular.
Capítulo calidad (v2.0.0): intro de dos dimensiones (60/40) que declara que los
outliers no bajan el score; tabla de scores Columna|Calidad|Completitud|Validez
(sin Consistencia, n/a cuando no aplica); DOS tablas separadas (Problemas de
calidad vs Observaciones analíticas); resumen con Unicidad de registro; glosario
clicable de completitud, validez, unicidad de registro y calidad de datos.
Verificado: 123 tests verdes (automatic_eda + render_automatic_eda +
column_quality_score + summarize_table_duckdb + profile_table). Golden EDA de
titanic (run_models+run_llm) con score recomputado a mano, outliers separados en
observaciones y glosario clicable (5 links GOTO en el PDF).
column_quality_score v2.0.0, summarize_table_duckdb v1.1.0, profile_table v1.1.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>