feat(eda): nueva fórmula de calidad de datos (report 2046) + capítulo calidad
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>
This commit is contained in:
@@ -196,6 +196,21 @@ def summarize_table_duckdb(
|
||||
sum(c["null_pct"] for c in columns) / len(columns) if columns else 0.0
|
||||
)
|
||||
|
||||
# Unicidad de registro: filas duplicadas via COUNT de filas distintas
|
||||
# push-down (DISTINCT *), sin traer filas a RAM. Habilita la dimension
|
||||
# de uniqueness del score de dataset (1 - duplicate_pct). Degrada a None
|
||||
# si la tabla tiene tipos no comparables con DISTINCT (BLOB/LIST/MAP).
|
||||
duplicate_rows = None
|
||||
duplicate_pct = None
|
||||
if n_rows > 0:
|
||||
dup_res = duckdb_query_readonly(
|
||||
db_path, f"SELECT count(*) AS c FROM (SELECT DISTINCT * FROM {quoted})"
|
||||
)
|
||||
if dup_res["status"] == "ok" and dup_res["rows"]:
|
||||
distinct_rows = int(dup_res["rows"][0]["c"])
|
||||
duplicate_rows = max(0, n_rows - distinct_rows)
|
||||
duplicate_pct = duplicate_rows / n_rows # fraccion 0-1
|
||||
|
||||
profile = {
|
||||
"table": table,
|
||||
"source": "duckdb",
|
||||
@@ -203,8 +218,8 @@ def summarize_table_duckdb(
|
||||
"n_rows": n_rows,
|
||||
"n_cols": len(columns),
|
||||
"size_bytes": None,
|
||||
"duplicate_rows": None,
|
||||
"duplicate_pct": None,
|
||||
"duplicate_rows": duplicate_rows,
|
||||
"duplicate_pct": duplicate_pct,
|
||||
"constant_cols": constant_cols,
|
||||
"all_null_cols": all_null_cols,
|
||||
"null_cell_pct": null_cell_pct,
|
||||
|
||||
Reference in New Issue
Block a user