a2074a0167
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>
126 lines
7.9 KiB
Markdown
126 lines
7.9 KiB
Markdown
---
|
|
name: profile_table
|
|
kind: pipeline
|
|
lang: py
|
|
domain: pipelines
|
|
purity: impure
|
|
version: "1.1.0"
|
|
signature: "def profile_table(db_path: str, table: str, backend: str = \"duckdb\", sample: int = 5000, run_models: bool = False, run_llm: bool = False, run_series: bool = False, emit_pdf: bool = False, emit_automatic: bool = False, report_dir: str = \"reports\", write_report: bool = True) -> dict"
|
|
description: "Orquestador one-shot del grupo de capacidad eda: perfila UNA tabla (DuckDB o PostgreSQL) end-to-end componiendo las funciones del grupo (perfil base SQL + muestreo read-only + inferencia semantica + promocion de tipo + estadistica numerica/categorica + score de calidad + correlaciones con correccion FDR + re-expresion de Tukey + avisos exploratorios) y, opcional, modelos baratos (run_models), interpretacion LLM (run_llm) y analisis de serie temporal por columna (run_series: estacionariedad ADF+KPSS, ACF/PACF, STL, retornos). Emite el TableProfile completo mas (opcional) report markdown + JSON sidecar + PDF movil (emit_pdf). Es la composicion canonica para hazme un EDA de esta tabla."
|
|
tags: [eda, duckdb, postgres, profiling, data-quality, pipeline, dataops, timeseries]
|
|
uses_functions:
|
|
- summarize_table_duckdb_py_datascience
|
|
- summarize_table_pg_py_datascience
|
|
- describe_numeric_py_datascience
|
|
- summarize_categorical_py_datascience
|
|
- infer_semantic_type_py_datascience
|
|
- column_quality_score_py_datascience
|
|
- association_matrix_py_datascience
|
|
- run_eda_models_py_datascience
|
|
- eda_llm_insights_py_datascience
|
|
- adf_kpss_stationarity_py_datascience
|
|
- acf_pacf_py_datascience
|
|
- stl_decompose_py_datascience
|
|
- to_returns_py_datascience
|
|
- suggest_reexpression_py_datascience
|
|
- exploratory_caveats_py_datascience
|
|
- render_eda_markdown_py_datascience
|
|
- render_eda_pdf_py_datascience
|
|
- build_eda_render_ctx_py_datascience
|
|
- render_automatic_eda_pdf_py_datascience
|
|
- render_automatic_eda_pptx_py_datascience
|
|
- duckdb_query_readonly_py_infra
|
|
- pg_query_py_infra
|
|
uses_types: []
|
|
returns: []
|
|
returns_optional: false
|
|
error_type: error_go_core
|
|
imports: []
|
|
tested: true
|
|
tests:
|
|
- "VARCHAR-entera se promociona a numeric con bloque numeric y key_candidates es lista"
|
|
test_file_path: "python/functions/pipelines/profile_table_test.py"
|
|
file_path: "python/functions/pipelines/profile_table.py"
|
|
params:
|
|
- name: db_path
|
|
desc: "Ruta al archivo DuckDB (read-only, debe existir; no se crea) o DSN PostgreSQL si backend='postgres'."
|
|
- name: table
|
|
desc: "Nombre de la tabla a perfilar."
|
|
- name: backend
|
|
desc: "'duckdb' (default) o 'postgres'. Selecciona el motor de perfilado base (summarize) y de muestreo read-only."
|
|
- name: sample
|
|
desc: "Maximo de valores no nulos muestreados por columna para el enriquecimiento (describe_numeric / summarize_categorical / infer_semantic_type). Default 5000."
|
|
- name: run_models
|
|
desc: "Si True (default False) corre los modelos baratos (PCA/KMeans/IsolationForest/normalidad) y guarda el bloque en prof['models']."
|
|
- name: run_llm
|
|
desc: "Si True (default False) hace 1 llamada LLM sobre el perfil agregado y guarda el resultado en prof['llm']."
|
|
- name: run_series
|
|
desc: "Si True (default False) calcula por columna numerica un bloque de serie temporal (estacionariedad ADF+KPSS, ACF/PACF, STL y, si parece de niveles, retornos). Ordena por la primera columna datetime si existe; si no, por el orden fisico. Guardado en col['series'] y agregado en prof['series']."
|
|
- name: emit_pdf
|
|
desc: "Si True (default False) renderiza un PDF multipagina vertical (legible en movil) del perfil junto al report markdown y devuelve su ruta en pdf_path."
|
|
- name: emit_automatic
|
|
desc: "Si True (default False) emite ADEMAS el informe AutomaticEDA completo en PDF (A5 movil) Y PPTX (16:9) con los 11 capitulos del motor; construye el ctx de datos crudos con build_eda_render_ctx para que modelos/timeseries/geospatial/agregacion salgan poblados. Aditivo: no sustituye a emit_pdf. Rutas en aeda_pdf_path / aeda_pptx_path / aeda_manifest_path."
|
|
- name: report_dir
|
|
desc: "Directorio donde escribir los reports si write_report (y el PDF si emit_pdf). Default 'reports'. Se crea si no existe."
|
|
- name: write_report
|
|
desc: "Si True (default) escribe report markdown + JSON sidecar timestamped en report_dir; si False no toca disco y los paths markdown/json del retorno son None (emit_pdf es independiente)."
|
|
output: "dict {status:'ok', profile:<TableProfile enriquecido con quality_score, key_candidates, type_breakdown recalculado, correlaciones con FDR, reexpression por columna numerica, caveats, y (con run_series) series>, report_md_path:str|None, report_json_path:str|None, pdf_path:str|None, aeda_pdf_path:str|None, aeda_pptx_path:str|None, aeda_manifest_path:str|None (estos tres solo con emit_automatic)} o {status:'error', error:str} (dict-no-throw)."
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```python
|
|
import os
|
|
from pipelines.profile_table import profile_table
|
|
|
|
# Tabla real: freelance_projects (35 filas) en la DuckDB del monitor de captacion.
|
|
db = os.path.expanduser("~/.fn_freelance/freelance.duckdb")
|
|
|
|
r = profile_table(db, "freelance_projects", sample=5000, write_report=False)
|
|
print(r["status"], r["profile"]["quality_score"], r["profile"]["type_breakdown"])
|
|
# ok 98.9 {'numeric': 1, 'categorical': 9, 'datetime': 2, 'text': 0, 'boolean': 1}
|
|
# ^ 'bids' (VARCHAR '1'..'107') se promociono a numeric via semantic_type=integer.
|
|
|
|
# Con report a disco (markdown + JSON sidecar en reports/):
|
|
r = profile_table(db, "freelance_projects")
|
|
print(r["report_md_path"], r["report_json_path"])
|
|
# reports/eda_freelance_projects_20260620-101500.md reports/eda_freelance_projects_20260620-101500.json
|
|
```
|
|
|
|
## Cuando usarla
|
|
|
|
Cuando necesites un EDA completo de una tabla DuckDB en una sola llamada: perfil
|
|
por columna + estadistica fina + calidad + report listo para leer. Usala como
|
|
primer paso al recibir un dataset desconocido, antes de modelar o limpiar, o
|
|
para auditar la calidad de una tabla ya productiva. Reemplaza orquestar a mano
|
|
`summarize_table_duckdb` -> muestreo -> `describe_numeric`/`summarize_categorical`
|
|
-> `column_quality_score` -> `render_eda_markdown` columna por columna.
|
|
|
|
## Gotchas
|
|
|
|
- Impura: con `write_report=True` (default) ESCRIBE dos archivos a `report_dir`
|
|
(markdown + JSON). Pasa `write_report=False` para un dry-run sin tocar disco.
|
|
- La promocion de tipo es una HEURISTICA sobre la muestra: una columna VARCHAR se
|
|
reclasifica a `numeric` solo si su `semantic_type` es integer/decimal/currency
|
|
y al menos el 80% de la muestra parsea a float; a `datetime` si el
|
|
`semantic_type` es datetime_iso/date_eu. Tablas con datos sucios o muestras no
|
|
representativas pueden quedar mal clasificadas; sube `sample` para muestras mas
|
|
fiables (coste: mas filas traidas a RAM por columna).
|
|
- Las columnas promovidas a `datetime` aun NO reciben perfil fino:
|
|
`col["datetime"]` queda en `None` (la funcion `profile_datetime` del grupo
|
|
llega en otra fase). Su `semantic_type` si se conserva.
|
|
- El parseo numerico limpia simbolos de moneda (€/$/£/EUR/USD/GBP), espacios y
|
|
separadores de miles; con coma y punto juntos asume punto=miles, coma=decimal.
|
|
Formatos exoticos pueden descartarse silenciosamente del calculo numerico.
|
|
- `db_path` debe existir: DuckDB read-only NO crea la base. El muestreo usa el
|
|
sandbox por defecto de `duckdb_query_readonly` (sin acceso a FS/red).
|
|
- **Score de calidad (report 2046, desde v1.1.0).** Paso 5: cada columna recibe
|
|
`quality_score` de `column_quality_score` con la formula 60/40
|
|
(completeness/validity); al promocionar texto a numero/fecha se expone
|
|
`col["validity_rate"]` (parse rate de la muestra) para alimentar la dimension
|
|
validity. Paso 6: el score de dataset NO es la media simple — es
|
|
`100 * (0.85*cell_quality + 0.15*row_uniqueness)`, donde
|
|
`cell_quality = media(score_col/100)` y `row_uniqueness = 1 - duplicate_pct`.
|
|
Si `duplicate_pct` es `None` (backend sin calcularlo) el score se renormaliza
|
|
a solo `cell_quality`. Los outliers NO bajan el score (van a `observations`).
|