763e06c127
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.5 KiB
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). |
|
|
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. |
|
false | error_go_core | true |
|
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 quedescribe_numericy otras funciones del grupo enriquecen luego sobre una muestra. - Cuando quieras perfilar tablas grandes sin traer filas a RAM:
SUMMARIZEhace 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). Eldb_pathdebe existir. distinct_countexacto para tablas <=200k filas, aproximado+capado por encima:SUMMARIZEusa HyperLogLog (approx_unique), que SOBREESTIMA y en tablas pequenas puede reportar mas distintos que filas (inflandounique_pctpor encima de 1.0 y disparando flagspossible_idfalsos). Por eso, paran_rows <= 200000la funcion calculaCOUNT(DISTINCT)EXACTO en una sola query combinada (barata) y usa ese valor. Para tablas mas grandes mantieneapprox_uniquepero lo CAPA an_rows(distinct_count = min(approx_unique, n_rows)). En ambos casosunique_pct = min(distinct_count / n_rows, 1.0), asi quedistinct_countnunca supera las filas niunique_pctpasa de 1.0. Los flagspossible_id/high_cardinalityderivan de esedistinct_countya corregido (exacto y fiable por debajo de 200k filas; aproximado y conservador por encima).SUMMARIZENO da skew, kurtosis ni histograma, ni percentiles finos (p1/p5/p95/p99), moda, outliers, correlaciones, key_candidates ni quality_score. Esas claves quedan enNone/[]a proposito: las rellena otra funcion del grupoedasobre una muestra. El sub-dictnumericsolo trae min, max, mean, std, p25, p50, p75.SUMMARIZE.countes el total de filas, no el no-nulo: la funcion deriva elcountno-nulo del ColumnProfile comon_rows - null_count(connull_countredondeado denull_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
SUMMARIZEvalidadas 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).