# eda — Exploratory Data Analysis por tabla y base Grupo de capacidad para perfilar tablas y bases de datos completas y entender datasets nuevos rápido, repetible y sin reinventar lógica. Motor **DuckDB SQL push-down**: los agregados (`SUMMARIZE`, `COUNT DISTINCT`, `corr()`, percentiles) se calculan en SQL sin traer las filas a RAM; solo una muestra pequeña baja a Python para lo estadístico fino (skew, kurtosis, histograma, correlación mixta, modelos). Orquestadores one-shot: - `profile_table_py_pipelines` — "hazme un EDA de esta tabla" → `TableProfile` completo + report markdown + JSON (+ PDF móvil con `emit_pdf`). Flags `run_models` (modelos baratos), `run_llm` (interpretación LLM), `run_series` (análisis de serie temporal por columna numérica) y `emit_pdf` (PDF vertical legible en móvil). Re-expresión sugerida por columna y avisos exploratorios se añaden siempre. - `profile_database_py_pipelines` — "hazme un EDA de esta base" → perfila todas las tablas + infiere FK + join graph (mermaid). > Cuando Enmanuel pide un EDA, el flujo acordado es: perfilar con este grupo, escribir el report, y **generar un analysis Jupyter lanzado en el navegador colaborativo y ejecutado por Claude** para verlo en vivo. Ver la memoria `eda-workflow-registry` y la regla `notebook_collaboration.md`. ## Funciones ### Perfilado base (tabla y columna) | ID | Pureza | Qué hace | |---|---|---| | `summarize_table_duckdb_py_datascience` | impure | Corazón (DuckDB): `SUMMARIZE` push-down + `COUNT DISTINCT` exacto (≤200k filas) → esqueleto del `TableProfile`. | | `summarize_table_pg_py_datascience` | impure | Adaptador PostgreSQL: mismo esqueleto `TableProfile` vía SQL push-down (information_schema + count/distinct/min/max/avg/stddev/percentile_cont). | | `describe_numeric_py_datascience` | pure | Bloque numérico: min/max/mean/median/std/cv, p1-p99, IQR, skew, kurtosis, outliers, distribución, histograma. | | `summarize_categorical_py_datascience` | pure | top-k frecuencias, mode, distinct, entropía, imbalance, longitudes. | | `infer_semantic_type_py_datascience` | pure | Tipo semántico por regex (email/url/ip/uuid/iban/currency/datetime/...). | | `column_quality_score_py_datascience` | pure | Score 0-100 (completeness/validity/consistency) + issues. | | `render_eda_markdown_py_datascience` | pure | `TableProfile` → report markdown con sparklines ASCII. | | `summary_stats_py_datascience` | pure | Descriptiva mínima (n, mean, median, p25, p75). | ### Correlación / asociación | ID | Pureza | Qué hace | |---|---|---| | `pearson_py_datascience` | pure | Correlación lineal num↔num (preexistente). | | `spearman_corr_py_datascience` | pure | Correlación de rangos (monotónica no lineal) num↔num. | | `cramers_v_py_datascience` | pure | Asociación simétrica cat↔cat (corrección Bergsma-Wicher). | | `theils_u_py_datascience` | pure | Asociación direccional U(a\|b) cat↔cat. | | `correlation_ratio_py_datascience` | pure | η: cuánto explica una categórica a una numérica. | | `mutual_info_columns_py_datascience` | pure | Información mutua (no lineal, general) entre cualquier par. | | `association_matrix_py_datascience` | pure | Matriz unificada: elige métrica por par de tipos + pares fuertes. | | `correlation_matrix_duckdb_py_datascience` | impure | Matriz Pearson push-down (`corr()` SQL) para muchas filas. | ### Relaciones inter-tabla | ID | Pureza | Qué hace | |---|---|---| | `infer_fk_containment_duckdb_py_datascience` | impure | Infiere FK candidatas por containment de valores (inclusion coefficient). | | `build_join_graph_py_datascience` | pure | FK candidates → grafo (roles fact/dimension) + diagrama Mermaid. | ### Modelos baratos (flag `run_models`) | ID | Pureza | Qué hace | |---|---|---| | `pca_explained_py_datascience` | pure | PCA: varianza explicada + loadings + proyección. | | `kmeans_segments_py_datascience` | pure | Segmentos naturales, auto-k por silhouette. | | `isolation_forest_outliers_py_datascience` | pure | Outliers multivariante (filas anómalas). | | `normality_tests_py_datascience` | pure | Jarque-Bera + D'Agostino + Shapiro → ¿normal? | | `trend_slope_py_datascience` | pure | Tendencia de una serie (up/down/flat) por regresión lineal. | | `run_eda_models_py_datascience` | pure | Wrapper: compone PCA + KMeans + IsolationForest + normalidad → bloque `models`. | ### Series temporales (flag `run_series`) | ID | Pureza | Qué hace | |---|---|---| | `adf_kpss_stationarity_py_datascience` | pure | Estacionariedad por consenso ADF + KPSS (hipótesis nulas opuestas) → veredicto `stationary`/`non_stationary`/`inconclusive` + aviso de correlación espuria. | | `acf_pacf_py_datascience` | pure | ACF + PACF con bandas de confianza + lags significativos + Ljung-Box (¿ruido blanco?). Detecta autocorrelación que infla los p-valores OLS. | | `stl_decompose_py_datascience` | pure | Descomposición STL (tendencia/estacional/resto) + fuerza de tendencia y estacional de Hyndman. Auto-infiere el periodo por autocorrelación. | | `to_returns_py_datascience` | pure | Convierte una serie de niveles (precios) a retornos log/simples. Los niveles no son estacionarios; los retornos sí (unidad correcta para correlacionar/modelar). | ### Rigor y disciplina exploratoria | ID | Pureza | Qué hace | |---|---|---| | `fdr_correction_py_datascience` | pure | Corrige p-valores por comparaciones múltiples (Benjamini-Hochberg FDR / Bonferroni FWER) → controla el data-mining bias. Ya integrada en `association_matrix`. | | `suggest_reexpression_py_datascience` | pure | Escalera de potencias de Tukey: qué transformación (log/sqrt/Yeo-Johnson/...) simetriza mejor una columna numérica según su skew y dominio. No la ejecuta, la sugiere. | | `exploratory_caveats_py_datascience` | pure | Genera las advertencias de que el EDA es exploratorio (correlación≠causalidad, overfitting in-sample, comparaciones múltiples, outliers, muestra pequeña, MNAR) según lo que el perfil realmente contiene. | ### Capa LLM y entrega | ID | Pureza | Qué hace | |---|---|---| | `eda_llm_insights_py_datascience` | impure | 1 call LLM sobre el perfil agregado (no filas crudas): data dictionary, resumen, granularidad de fila, PII/RGPD, limpieza, análisis sugeridos. | | `build_eda_notebook_py_datascience` | impure | Genera un `.ipynb` (nbformat v4) que perfila la tabla, listo para lanzar en Jupyter colaborativo. | | `render_eda_pdf_py_datascience` | impure | Renderiza el `TableProfile` a un PDF multipágina **vertical (A5), legible en móvil** (estilo Tufte: histogramas como small multiples, top-k, heatmap de asociación). 4ª salida del workflow, junto a JSON/Markdown/notebook. | ### Orquestadores (pipelines) | ID | Qué hace | |---|---| | `profile_table_py_pipelines` | EDA de una tabla end-to-end, `backend="duckdb"` (default) o `"postgres"` (base + correlación con FDR + `run_models` + `run_llm` + `run_series` + re-expresión + caveats) → JSON + markdown (+ PDF móvil con `emit_pdf`). | | `profile_database_py_pipelines` | EDA de una base entera: todas las tablas + FK + join graph. | ## Contrato de datos ``` TableProfile = {table, source, profiled_at, n_rows, n_cols, size_bytes, duplicate_rows, duplicate_pct, constant_cols, all_null_cols, null_cell_pct, type_breakdown:{numeric,categorical,datetime,text,boolean}, columns:[ColumnProfile], correlations, key_candidates, quality_score, llm, models, series:{