Files
fn_registry/python/functions/datascience/summarize_table_duckdb.md
T
egutierrez 763e06c127 feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-20 18:22:23 +02:00

6.5 KiB

name, kind, lang, domain, version, purity, signature, description, tags, params, output, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags params output uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path
summarize_table_duckdb function py datascience 1.0.0 impure def summarize_table_duckdb(db_path: str, table: str, high_card_ratio: float = 0.9) -> dict Perfila una tabla DuckDB en una sola pasada SQL (SUMMARIZE, push-down sin traer filas a RAM) y devuelve el esqueleto de un TableProfile con el perfil base por columna. Corazon del grupo eda: base barata sobre la que otras funciones anaden lo estadistico fino (skew/kurtosis/histograma sobre muestra).
eda
duckdb
profiling
datascience
exploratory-data-analysis
table-profile
name desc
db_path Ruta al archivo DuckDB. Debe existir (lectura read-only via duckdb_query_readonly; no se crea).
name desc
table Nombre de la tabla a perfilar. Se valida contra ^[A-Za-z_][A-Za-z0-9_]*$ y se cita en el SQL (SUMMARIZE no admite parametros posicionales para el identificador).
name desc
high_card_ratio Umbral de unicidad (unique_pct, 0-1) a partir del cual una columna categorical recibe el flag high_cardinality. Default 0.9.
dict dict-no-throw. En exito {status:'ok', profile: TableProfile} con perfil base por columna (n_rows/n_cols, type_breakdown, constant_cols, all_null_cols, null_cell_pct y columns[] de ColumnProfile). En error {status:'error', error:str}. Claves estadisticas finas (skew, kurtosis, histograma, percentiles finos, moda, outliers, correlaciones, key_candidates, quality_score) quedan en None/[] para que otras funciones del grupo eda las completen.
duckdb_query_readonly_py_infra
false error_go_core
true
test_shape_y_metadatos_tabla
test_column_profile_shape
test_type_breakdown
test_tabla_invalida_devuelve_error
test_tabla_inexistente_devuelve_error
test_distinct_no_excede_filas
test_columna_unica_da_possible_id
python/functions/datascience/summarize_table_duckdb_test.py python/functions/datascience/summarize_table_duckdb.py

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from datascience import summarize_table_duckdb

# Perfila la tabla `keywords` de una base DuckDB de SEO.
res = summarize_table_duckdb(
    db_path=os.path.expanduser("~/.fn_seo/seo.duckdb"),
    table="keywords",
    high_card_ratio=0.9,
)

if res["status"] == "ok":
    p = res["profile"]
    print(f"{p['table']}: {p['n_rows']} filas x {p['n_cols']} cols")
    print("type_breakdown:", p["type_breakdown"])
    for col in p["columns"]:
        print(col["name"], col["inferred_type"], "nulls=", col["null_pct"], col["flags"])
else:
    print("error:", res["error"])

Cuando usarla

  • Cuando empieces a explorar una tabla DuckDB que no conoces y necesites el esqueleto barato de su perfil (tipos inferidos, nulos, cardinalidad, flags) antes de gastar en estadistica fina.
  • Como primer paso del grupo eda: construye el TableProfile base que describe_numeric y otras funciones del grupo enriquecen luego sobre una muestra.
  • Cuando quieras perfilar tablas grandes sin traer filas a RAM: SUMMARIZE hace push-down en el motor de DuckDB.

Gotchas

  • Impura: lee de disco via duckdb_query_readonly (modo read-only, no crea ni modifica la base). El db_path debe existir.
  • distinct_count exacto para tablas <=200k filas, aproximado+capado por encima: SUMMARIZE usa HyperLogLog (approx_unique), que SOBREESTIMA y en tablas pequenas puede reportar mas distintos que filas (inflando unique_pct por encima de 1.0 y disparando flags possible_id falsos). Por eso, para n_rows <= 200000 la funcion calcula COUNT(DISTINCT) EXACTO en una sola query combinada (barata) y usa ese valor. Para tablas mas grandes mantiene approx_unique pero lo CAPA a n_rows (distinct_count = min(approx_unique, n_rows)). En ambos casos unique_pct = min(distinct_count / n_rows, 1.0), asi que distinct_count nunca supera las filas ni unique_pct pasa de 1.0. Los flags possible_id / high_cardinality derivan de ese distinct_count ya corregido (exacto y fiable por debajo de 200k filas; aproximado y conservador por encima).
  • SUMMARIZE NO da skew, kurtosis ni histograma, ni percentiles finos (p1/p5/p95/p99), moda, outliers, correlaciones, key_candidates ni quality_score. Esas claves quedan en None/[] a proposito: las rellena otra funcion del grupo eda sobre una muestra. El sub-dict numeric solo trae min, max, mean, std, p25, p50, p75.
  • SUMMARIZE.count es el total de filas, no el no-nulo: la funcion deriva el count no-nulo del ColumnProfile como n_rows - null_count (con null_count redondeado de null_percentage).
  • min/max/avg/std/q25/q50/q75 vienen como strings desde DuckDB; se convierten a float (None si la columna no es numerica).
  • Requiere DuckDB 1.5.2 (columnas de SUMMARIZE validadas con esa version: column_name, column_type, min, max, approx_unique, avg, std, q25, q50, q75, count, null_percentage).
  • El identificador de tabla se interpola (no parametrizable en SUMMARIZE): por eso se valida contra ^[A-Za-z_][A-Za-z0-9_]*$ antes de citarlo. Un nombre invalido (p.ej. con ; o espacios) devuelve {status:'error'} sin tocar la base.

Notas

Contrato compartido por todo el grupo eda (mantener estable):

TableProfile = {
  table, source, profiled_at, n_rows, n_cols, size_bytes, duplicate_rows,
  duplicate_pct, constant_cols:[str], all_null_cols:[str], null_cell_pct,
  type_breakdown:{numeric, categorical, datetime, text, boolean},
  columns:[ColumnProfile], correlations, key_candidates:[str], quality_score,
  llm, models
}
ColumnProfile = {
  name, physical_type, inferred_type, semantic_type, count, n_rows, null_count,
  null_pct, empty_count, empty_pct, distinct_count, unique_pct, flags:[str],
  quality_score, numeric:<sub>|None, categorical:<sub>|None, datetime:<sub>|None
}
numeric_sub = {
  min, max, mean, median, mode, std, variance, cv, p1, p5, p25, p50, p75, p95,
  p99, iqr, skew, kurtosis, n_outliers, outlier_pct, zero_pct, negative_pct,
  distribution_type, histogram
}

Mapeo de column_type fisico DuckDB a inferred_type: enteros/decimales/float -> numeric; date/time/timestamp -> datetime; boolean -> boolean; varchar/text -> categorical si approx_unique <= 50 o approx_unique/n_rows < 0.5, si no text.

Flags por columna: constant (distinct_count<=1), possible_id (unique_pct>=0.99 y null_pct==0), high_cardinality (categorical con unique_pct>=high_card_ratio), mostly_null (null_pct>0.5).