Files
fn_registry/python/functions/datascience/pivot_table_duckdb.md
T
egutierrez 96da9e3015 feat(eda): funciones de agregación/OLAP para AutomaticEDA (groupby/pivot push-down + selección LLM)
Cuatro funciones nuevas del grupo eda que nutren el capítulo AGREGACION:
- select_groupby_keys (pure): elige categóricas agrupables + numéricas medida desde el TableProfile.
- groupby_stats_duckdb (impure): GROUP BY push-down en DuckDB (count/mean/median/std/min/max por grupo).
- pivot_table_duckdb (impure): pivot A×B push-down, limitado a top filas/cols para no cortar.
- suggest_aggregations_llm (impure): el LLM elige las agregaciones interesantes con fallback determinista.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:33:55 +02:00

5.3 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
pivot_table_duckdb function py datascience 1.0.0 impure def pivot_table_duckdb(db_path: str, table: str, index: str, columns: str, value: str, agg: str = 'mean', top_rows: int = 10, top_cols: int = 8) -> dict Pivot table (index x columns -> agg(value)) calculada con push-down SQL en DuckDB (GROUP BY en el motor, sin traer filas a RAM) y recortada a las top_rows filas y top_cols columnas con mas observaciones para que quepa entera en un PDF movil / slide PPTX sin cortarse. Version push-down para tablas grandes de la funcion pura `pivot` (que pivota list[dict] en memoria).
eda
pivot
duckdb
aggregate
datascience
push-down
report
duckdb_query_readonly_py_infra
false error_go_core
name desc
db_path Ruta al archivo DuckDB. Debe existir; el modo read_only NO crea la base.
name desc
table Nombre de la tabla a pivotar. Se interpola citado con dobles comillas (DuckDB no admite parametros para identificadores).
name desc
index Columna cuyos valores forman las filas de la pivot (eje vertical).
name desc
columns Columna cuyos valores forman las columnas de la pivot (eje horizontal).
name desc
value Columna numerica a agregar en cada celda. Ignorada cuando agg='count'.
name desc
agg Funcion de agregacion: mean, sum, count, min, max, median. mean->avg(), count->COUNT(*). Otro valor devuelve {status:'error'}.
name desc
top_rows Numero maximo de filas a conservar, elegidas por mayor numero de observaciones (suma de COUNT(*) por valor de index). Default 10.
name desc
top_cols Numero maximo de columnas a conservar, elegidas por mayor numero de observaciones (suma de COUNT(*) por valor de columns). Default 8.
dict. En exito {status:'ok', index, columns, value, agg, row_labels:[...], col_labels:[...], matrix:..., truncated_rows:bool, truncated_cols:bool, note:str}. matrix tiene len(row_labels) filas y cada fila len(col_labels) celdas (valor agregado o None si la combinacion no existe). truncated_* indica si hubo mas filas/columnas que el top. En error {status:'error', error:str} (no lanza). true
pivot mean labels y celda conocida
pivot trunca a top rows y top cols
pivot count no necesita value real
pivot db inexistente devuelve error sin lanzar
pivot agg invalido devuelve error
python/functions/datascience/pivot_table_duckdb_test.py python/functions/datascience/pivot_table_duckdb.py

Ejemplo

import duckdb
from datascience import pivot_table_duckdb

# Tabla DuckDB de prueba estilo titanic: sex x pclass -> mean(fare).
db = "/tmp/pivot_demo.duckdb"
con = duckdb.connect(db)
con.execute(
    "CREATE TABLE titanic AS SELECT * FROM (VALUES "
    "('male',1,211.3),('female',1,151.5),('male',3,7.9),"
    "('female',3,16.7),('male',1,52.0),('female',2,41.6)"
    ") t(sex, pclass, fare)"
)
con.close()

res = pivot_table_duckdb(db, "titanic", index="sex", columns="pclass", value="fare", agg="mean")
print(res["status"])        # ok
print(res["row_labels"])    # ['female', 'male']  (orden por nº de observaciones desc; empate -> etiqueta)
print(res["col_labels"])    # [1, 3, 2]  (pclass=1 tiene 3 obs, pclass=3 -> 2, pclass=2 -> 1)
print(res["matrix"])        # [[151.5, 16.7, 41.6], [131.65, 7.9, None]]  (male/pclass=2 no existe -> None)

Cuando usarla

Cuando quieres una pivot table (index x columns -> agg(value)) de una tabla DuckDB con MUCHAS filas y necesitas que el resultado quepa entero en un informe: un PDF abierto en el movil o un slide PPTX, donde una matriz de 50x30 se cortaria. La agregacion se hace push-down en el motor (no traes las filas a RAM) y el resultado se limita a las top_rows x top_cols combinaciones con mas observaciones. Encaja en el flujo eda para resumir el cruce de dos categoricas (sexo x clase, region x producto) contra una metrica. Para pivotar un list[dict] ya cargado en memoria usa la funcion pura pivot_py_datascience; esta es la version push-down sobre disco.

Gotchas

  • Funcion impura: lee un archivo DuckDB del disco (read_only, nunca lo modifica).
  • Recorta a top_rows x top_cols por numero de observaciones (suma de COUNT(*)), NO por magnitud del valor agregado. Si habia mas filas/columnas, truncated_rows / truncated_cols quedan en True y esas combinaciones NO aparecen en la matriz.
  • Las celdas sin datos (combinacion index x columns que no existe en la tabla) se rellenan con None, no con 0: distinguir "cero medido" de "sin observaciones".
  • agg='count' cuenta filas por celda con COUNT(*) e ignora value (puedes pasar cualquier nombre de columna). Para el resto de aggs, value debe ser una columna numerica real o la query fallara con {status:'error'}.
  • agg solo admite mean, sum, count, min, max, median; cualquier otro valor devuelve {status:'error'} sin tocar la base.
  • Orden de row_labels / col_labels: por numero de observaciones descendente, con desempate estable por etiqueta. No es orden alfabetico ni el de aparicion.
  • La query se ejecuta con sandbox=False en duckdb_query_readonly (uso interno confiable: el SQL lo construye esta funcion, no un cliente externo).