Files
fn_registry/python/functions/datascience/resample_timeseries.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

6.6 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
resample_timeseries function py datascience 1.0.0 pure def resample_timeseries(t: list, v: list, freq: str = "auto", agg: str = "mean", max_points: int = 400) -> dict Agrega una serie temporal por periodo para graficar su evolucion y el CONTEO de observaciones por bucket. Nucleo del capitulo TIMESERIES de AutomaticEDA (grupo eda): recibe las fechas y los valores YA leidos (pura, sin tocar ninguna base de datos), empareja t[i] con v[i] por indice, parsea fechas defensivamente, trunca cada fecha al inicio de su bucket (daily/weekly/monthly/quarterly/yearly), y agrega los valores numericos validos por bucket mientras cuenta TODAS las observaciones con fecha valida (densidad temporal, incluida la fila cuyo valor es None). freq='auto' infiere del delta mediano entre fechas. Si hay mas buckets que max_points hace downsampling uniforme conservando primero y ultimo. Estilo dict-no-throw: NUNCA lanza; entrada vacia o longitudes incompatibles devuelve listas vacias + note='datos insuficientes'.
eda
timeseries
resample
aggregate
profiling
datascience
time
name desc
t Lista de fechas paralela a v. Acepta strings ISO ('YYYY-MM-DD' o 'YYYY-MM-DDTHH:MM:SS', con 'Z' opcional), datetime.date o datetime.datetime. Se parsea defensivamente; los pares cuya fecha no parsea se descartan junto con su valor.
name desc
v Lista de valores numericos (float/int) paralela a t. Puede contener None o valores no numericos: se ignoran en la agregacion pero la fila sigue contando en 'count' si su fecha es valida. bool, NaN e Inf se tratan como no numericos.
name desc
freq Granularidad del bucket: 'auto' (infiere del delta mediano en dias entre fechas: <=3 daily, <=16 weekly, <=75 monthly, <=200 quarterly, mayor yearly) o explicita en {daily, weekly, monthly, quarterly, yearly}. Una frecuencia desconocida cae a 'auto'.
name desc
agg Agregacion por bucket sobre los valores numericos validos: 'mean' | 'sum' | 'median' | 'last' (valor de la observacion cronologicamente mas reciente del bucket) | 'min' | 'max'. Una agregacion desconocida cae a 'mean'.
name desc
max_points Tope de buckets en la salida. Si n_buckets > max_points hace downsampling uniforme (1 de cada k buckets equiespaciados, conservando el primero y el ultimo) para no saturar el grafico del PDF/PPTX. max_points<=0 desactiva el limite.
Dict siempre con las mismas claves: t (lista de etiquetas ISO 'YYYY-MM-DD' por bucket, orden cronologico), v (lista paralela del valor agregado por bucket segun agg; None si el bucket no tiene ningun valor numerico valido), count (lista paralela del nº de observaciones con fecha valida por bucket), freq (frecuencia efectivamente usada), agg (agregacion usada), n_in (nº de pares (t,v) con fecha valida que entraron), n_buckets (nº de buckets antes del downsample), downsampled (bool, True si se aplico downsampling), note ('' o 'datos insuficientes' cuando no hay pares validos / longitudes incompatibles / listas vacias). Numericos de v en float, count en int.
false
true
test_daily_a_mensual_mean
test_agg_sum_y_last
test_count_cuenta_observacion_con_valor_none
test_downsampling_respeta_max_points_y_extremos
test_freq_auto_infiere_mensual
test_edge_listas_vacias_o_desiguales
python/functions/datascience/resample_timeseries_test.py python/functions/datascience/resample_timeseries.py

Ejemplo

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

# Serie diaria agregada a buckets mensuales: media del valor + conteo de filas.
t = ["2020-01-01", "2020-01-15", "2020-02-01", "2020-02-10", "2020-02-20"]
v = [10.0, 20.0, 30.0, 40.0, 50.0]

r = resample_timeseries(t, v, freq="monthly", agg="mean")
print(r["t"])      # ['2020-01-01', '2020-02-01']
print(r["v"])      # [15.0, 40.0]
print(r["count"])  # [2, 3]   <- densidad: nº de observaciones por mes
print(r["freq"], r["downsampled"])  # monthly False

# freq='auto' infiere la granularidad del delta mediano entre fechas.
mensual = [f"2022-{m:02d}-01" for m in range(1, 13)]
print(resample_timeseries(mensual, list(range(1, 13)))["freq"])  # monthly

Cuando usarla

  • Usala en el capitulo TIMESERIES de AutomaticEDA para construir, a partir de una columna temporal (detect_time_column) y una columna numerica, la doble serie que el renderer dibuja: la EVOLUCION del valor agregado por periodo y el CONTEO de observaciones por periodo.
  • Cuando ya tengas las fechas y los valores leidos en memoria (de DuckDB, polars, CSV, etc.) y solo necesites agregarlos por dia/semana/mes/trimestre/año sin volver a tocar la base de datos — esta funcion es pura y recibe los datos por parametro.
  • Cuando quieras un downsampling controlado para que una serie muy larga (miles de fechas) quepa en un grafico de un PDF/PPTX sin saturarlo, conservando el primer y el ultimo punto.
  • Cuando no sepas la cadencia de la serie: pasa freq="auto" y deja que la infiera del delta mediano.

Gotchas

  • Funcion pura, sin I/O y determinista. NUNCA lanza: ante entrada invalida (listas vacias, longitudes distintas o todas las fechas no parseables) devuelve listas vacias + note="datos insuficientes".
  • count cuenta OBSERVACIONES con fecha valida en el bucket (densidad temporal), aunque su valor numerico sea None/no numerico. v agrega SOLO los valores numericos validos del bucket; si no hay ninguno, v del bucket es None mientras count sigue reflejando las filas. No confundas count (filas) con el nº de valores agregados.
  • bool, NaN e Inf se tratan como NO numericos (se ignoran en v). Un string que no parsea a numero tambien se ignora en v pero su fila cuenta si la fecha es valida.
  • El truncado de bucket usa el inicio del periodo: semana = lunes ISO (weekday()==0), mes = dia 1, trimestre = primer dia del trimestre (ene/abr/jul/oct), año = 1 de enero. La etiqueta de cada bucket es esa fecha de inicio en ISO YYYY-MM-DD, no un rango.
  • El downsampling (n_buckets > max_points) reduce la salida a <= max_points puntos equiespaciados conservando primero y ultimo, pero n_buckets SIEMPRE reporta el conteo real previo al recorte. Si necesitas todos los buckets, sube max_points o ponlo <=0.
  • Las fechas con hora se truncan a su date() antes de agrupar: la granularidad minima es el dia (no hay buckets horarios).
  • freq desconocida o no-string cae a "auto"; agg desconocida cae a "mean". El campo devuelto refleja la opcion efectivamente usada.