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:
@@ -477,9 +477,18 @@ def profile_table(
|
||||
if vals and (len(ok) / len(vals)) >= _PROMOTE_MIN_PARSE:
|
||||
col["inferred_type"] = "numeric"
|
||||
inferred = "numeric"
|
||||
# Tasa de parseo real de la muestra: alimenta la
|
||||
# dimension validity de column_quality_score (fraccion
|
||||
# de valores conformes al tipo numerico promovido).
|
||||
col["validity_rate"] = len(ok) / len(vals)
|
||||
elif semantic in _DATETIME_SEMANTIC:
|
||||
col["inferred_type"] = "datetime"
|
||||
inferred = "datetime"
|
||||
# Tasa de parseo de la muestra a fecha (mismo papel que el
|
||||
# parse rate numerico) para la dimension validity.
|
||||
parsed_dt = [_to_ordinal_days(v) for v in vals]
|
||||
ok_dt = [d for d in parsed_dt if d is not None]
|
||||
col["validity_rate"] = (len(ok_dt) / len(vals)) if vals else None
|
||||
|
||||
# 4) Enriquecer segun el inferred_type final.
|
||||
if inferred == "numeric":
|
||||
@@ -506,11 +515,36 @@ def profile_table(
|
||||
# 5) Score de calidad por columna.
|
||||
col["quality_score"] = column_quality_score(col).get("score")
|
||||
|
||||
# 6) Score agregado de la tabla (media de columnas).
|
||||
# 6) Score agregado de la tabla (report 2046): NO media simple.
|
||||
# cell_quality = media de los scores de columna, en [0,1].
|
||||
# row_uniqueness = 1 - duplicate_pct (unicidad de registro).
|
||||
# score = 100 * (0.85*cell_quality + 0.15*row_uniqueness).
|
||||
# Renormaliza a solo cell_quality si duplicate_pct no se pudo calcular.
|
||||
scores = [
|
||||
c["quality_score"] for c in cols if c.get("quality_score") is not None
|
||||
]
|
||||
prof["quality_score"] = round(sum(scores) / len(scores), 1) if scores else None
|
||||
if scores:
|
||||
cell_quality = (sum(scores) / len(scores)) / 100.0
|
||||
dup_pct = prof.get("duplicate_pct")
|
||||
if dup_pct is not None:
|
||||
try:
|
||||
d = float(dup_pct)
|
||||
except (TypeError, ValueError):
|
||||
d = None
|
||||
else:
|
||||
d = None
|
||||
if d is not None:
|
||||
# Tolerar escala 0-100 por si algun backend la entrega asi.
|
||||
if d > 1.0:
|
||||
d = d / 100.0
|
||||
row_uniqueness = max(0.0, min(1.0, 1.0 - d))
|
||||
prof["quality_score"] = round(
|
||||
100.0 * (0.85 * cell_quality + 0.15 * row_uniqueness), 1
|
||||
)
|
||||
else:
|
||||
prof["quality_score"] = round(100.0 * cell_quality, 1)
|
||||
else:
|
||||
prof["quality_score"] = None
|
||||
|
||||
# 7) Candidatos a clave.
|
||||
key_candidates = []
|
||||
|
||||
Reference in New Issue
Block a user