Files
fn_registry/python/functions/datascience/extract_timeseries_raw.md
T
egutierrez a69d14d38e feat(eda): capítulo TIMESERIES del AutomaticEDA (evolución + análisis de serie)
Capítulo nuevo build_timeseries(profile, ctx) -> Chapter|None del motor
AutomaticEDA. Cuando la tabla tiene columna de fecha/datetime, grafica la
evolución de cada columna numérica por periodo (valor agregado + conteo de filas)
y los paneles de descomposición STL y autocorrelación (ACF), con el análisis de
la serie: estacionariedad (ADF+KPSS), autocorrelación (Ljung-Box), fuerzas de
tendencia/estacionalidad (Hyndman) y la transformación sugerida (retornos o
diferencias) para evitar correlaciones espurias. Sin columna temporal devuelve
None. Consolida series OHLC casi idénticas en un único gráfico conservando el
análisis de cada columna.

La serie cruda llega por ctx['timeseries_raw'] (mismo patrón que modelos con
raw_numeric); las figuras son perezosas (Figure.make) y el paginador del núcleo
garantiza no-corte en PDF y PPTX. CHAPTER_VERSION 1.0.0.

Cubre los MUST del diseño (report 2043): MUST-9.1 (línea valor-vs-tiempo + conteo
por periodo), MUST-9.2 (paneles STL + ACF), MUST-9.3 (perfil datetime +
consolidación OHLC).

Funciones nuevas del registry (grupo eda), delegadas a fn-constructor, no inline:
- detect_time_column (pure): detecta la columna temporal y las numéricas
- profile_datetime (pure): rango/frecuencia/regularidad/huecos de la fecha
- resample_timeseries (pure): agrega la serie por periodo + conteo
- extract_timeseries_raw (impure): lee la serie cruda ordenada de DuckDB/PG

Verificación: 69 tests verdes (capítulo 9 + funciones 28 + núcleo/renderers);
golden real sobre seattle-weather (estacional) y aapl (OHLC) con PDF+PPTX sin
cortar nada (cols_cortadas=[]).

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

5.6 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
extract_timeseries_raw function py datascience 1.0.0 impure def extract_timeseries_raw(query_fn, table: str, time_col: str, value_cols: list, max_rows: int = 5000) -> dict Extrae la serie temporal CRUDA (fechas + una o varias columnas numericas) de una tabla, ordenada cronologicamente, para alimentar el render del capitulo TIMESERIES de AutomaticEDA (linea valor-vs-tiempo + conteo por periodo). Recibe un lector read-only inyectado `query_fn(sql) -> dict` (mismo contrato que duckdb_query_readonly / pg_query / el `_q` de profile_table) y NO abre ninguna conexion por su cuenta. Construye UNA sola query con identificadores escapados, ORDER BY por la columna temporal y LIMIT. Devuelve dict dict-no-throw: t (fechas ISO string), series (lista paralela float|None por columna) y n. El capitulo no toca la BD: recibe esto en ctx['timeseries_raw']. Reutilizable tambien por profile_table en una fase futura.
eda
timeseries
datascience
automatic-eda
extraction
read-only
duckdb
postgres
python
false error_go_core
datetime
name desc
query_fn callable lector read-only del backend activo. Recibe un string SQL y devuelve un dict {'status':'ok','rows':[{col:val,...},...]} (mismo contrato que duckdb_query_readonly o el `_q` de profile_table). NO se abre ninguna conexion dentro de la funcion: toda la lectura pasa por query_fn. Si es None -> error.
name desc
table nombre de la tabla de la que extraer la serie. Se escapa con comillas dobles en la query.
name desc
time_col nombre de la columna de orden temporal. Se usa en ORDER BY (cronologico ascendente) y se filtra IS NOT NULL. Sus valores se devuelven en `t` como string ISO.
name desc
value_cols lista de nombres de columnas numericas a extraer. Cada una produce una entrada en `series` con una lista paralela a `t`. Vacia o None -> status error.
name desc
max_rows limite de filas a leer (clausula LIMIT). Default 5000. Protege el render frente a tablas enormes.
dict (nunca lanza). En exito: {'status':'ok','time_col':str,'t':[str,...] (fechas ISO en orden),'series':{col:[float|None,...],...} (paralela a t por value_col, None si el valor no es convertible a float),'n':int}. En error (sin lanzar): {'status':'error','error':str,'time_col':str,'t':[],'series':{},'n':0}. Errores: query_fn None, value_cols vacia, table/time_col vacios, o query_fn devuelve status!='ok' (se propaga su error). true
test_golden_t_y_series_alineadas
test_valor_no_convertible_da_none
test_value_cols_vacia_status_error
test_query_fn_status_error_propaga
test_query_fn_none_da_error_sin_reventar
test_sql_contiene_order_by_y_limit
python/functions/datascience/extract_timeseries_raw_test.py python/functions/datascience/extract_timeseries_raw.py

Ejemplo

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

# El lector read-only se inyecta como closure (igual que el `_q` de profile_table).
db = "data/ventas.duckdb"
def _q(sql):
    return duckdb_query_readonly(db, sql)

res = extract_timeseries_raw(_q, "ventas_diarias", "fecha", ["importe", "unidades"])
# res == {
#   "status": "ok",
#   "time_col": "fecha",
#   "t": ["2024-01-01", "2024-01-02", ...],
#   "series": {"importe": [1234.5, 980.0, ...], "unidades": [12.0, 9.0, ...]},
#   "n": 365,
# }

# Se entrega al capitulo TIMESERIES sin que este toque la BD:
ctx = {"timeseries_raw": res}

Cuando usarla

Cuando el capitulo TIMESERIES de AutomaticEDA necesita pintar una serie valor-vs-tiempo (o conteo por periodo) y NO debe abrir la base de datos por su cuenta: extraes aqui las fechas + columnas numericas ordenadas y se las pasas en ctx['timeseries_raw']. Usala tambien siempre que quieras la secuencia cruda ordenada cronologicamente de una o varias columnas para alimentar otros contrastes de serie (ADF/KPSS, ACF/PACF, STL) reutilizando un unico lector read-only inyectado, en vez de hacer N muestreos a mano.

Gotchas

  • Impura: lee de la base de datos a traves de query_fn. No abre conexiones por su cuenta — depende por completo del lector inyectado. Sigue el estilo dict-no-throw del grupo eda: nunca lanza; ante cualquier fallo devuelve {"status":"error","error":...} con t=[], series={}, n=0.
  • error_type en el frontmatter es error_go_core por convencion del registry (toda funcion impura debe declararlo y el indexer lo exige), pero el codigo NO lanza esa excepcion: degrada al dict de error. Es metadata, no comportamiento.
  • No loguear los datos crudos: t/series pueden contener datos sensibles (igual que un HAR). No volcar el dict completo a logs ni a telemetria; en trazas usa solo n y los nombres de columna.
  • Alineacion por fila: series[col][i] corresponde a t[i]. Un valor no convertible a float se guarda como None (no se descarta la fila) para no romper la alineacion temporal.
  • Orden: el orden cronologico depende del ORDER BY "time_col" del backend. Si time_col esta guardada como texto con formato no lexicograficamente ordenable (p.ej. DD/MM/YYYY), el orden no sera el real — normaliza la columna a date/timestamp antes, o pasa una columna ya ordenable.
  • max_rows: con LIMIT, si la tabla supera max_rows obtienes solo el primer tramo cronologico, no un muestreo uniforme. Sube max_rows si necesitas el rango completo.