Files
fn_registry/dev/issues/0174-eda-series-periodo-estacional-niveles.md
T
Egutierrez 7ac69ab4fb feat(eda): series temporales + rigor anti-data-mining + PDF movil + /eda + benchmark issues
Bloque del grupo eda (sesion ausente EDA-benchmark):
- 8 funciones nuevas: adf_kpss_stationarity, acf_pacf, stl_decompose, to_returns,
  fdr_correction, suggest_reexpression, exploratory_caveats, render_eda_pdf
- integracion: profile_table (run_series, emit_pdf), association_matrix (FDR Benjamini-Hochberg),
  render_eda_markdown (secciones series/reexpresion/caveats)
- slash commands /eda y /capitulos
- issues 0173-0177: mejoras del /eda derivadas del benchmark sobre 12 datasets reales
  (outlier_pct x100, periodo estacional, FK inference, render models, tipos id-like)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 03:34:01 +02:00

5.5 KiB
Raw Blame History

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0174 EDA series temporales: período estacional roto + correlación de niveles + to_returns ciego pendiente bugfix
registry-quality
registry-only alta
0173
0175
0176
0177
2026-06-29 2026-06-29
eda
datascience
stl_decompose
profile_table
to_returns
series
benchmark

0174 — EDA series temporales: período estacional + correlación de niveles

Contexto

El benchmark /eda (29/06/2026, temp/eda_benchmark/EVALUATION.md) confirmó que la estacionariedad (ADF+KPSS), la autocorrelación (Ljung-Box) y el aviso de espuriedad Granger-Newbold están bien (verificados a mano con statsmodels). Pero el detector de período estacional está roto, lo que produce falsos negativos de estacionalidad, y la correlación de precios se calcula sobre niveles (espuria para uso financiero).

Hallazgos cubiertos:

Hallazgo Severidad Evidencia del benchmark
H2 — período estacional sale 2 casi siempre → seasonal_strength=0 crítico seattle temp_max reporta "sin estacionalidad" (period=2); STL real con period=365 da fuerza estacional 0.843. UNRATE (mensual) debería usar 12, no 2
H8 — correlación de precios sobre niveles marcada sig=sí medio-alto aapl/btc CloseOpen=0.998 sig=sí: espuria por construcción (niveles autocorrelados no estacionarios)
H13 — to_returns sugerido ciegamente a temperatura (sin sentido físico) bajo seattle temp_max: "convertir a retornos"; debería ser "diferencias"

Causa raíz H2 (verificada en código, READ-ONLY)

python/functions/datascience/stl_decompose.py:34-58 (_infer_period) busca el lag entre 2 y max_period que maximiza la autocorrelación cruda de la serie. En cualquier serie con tendencia (precios, temperatura), la autocorrelación decae monótonamente desde el lag mínimo, así que el lag 2 casi siempre ganaperiod=2 espurio y un STL con componente estacional que es ruido (seasonal_strength≈0). Además, python/functions/pipelines/profile_table.py:175 (_build_series_block) llama stl_decompose(series_vals) sin pasar el período, pese a que el pipeline ya conoce la columna de orden temporal (order_col) y podría derivar la frecuencia.

Tareas

  1. H2 — arreglar la inferencia de período en stl_decompose.py:34-58. Opciones (preferir la robusta): (a) detrend antes de autocorrelar; (b) buscar picos en el periodograma/FFT en vez del primer lag; (c) derivar el período de la frecuencia del índice datetime (mensual→12, diario→7 y/o 365) — la señal más fiable.
  2. H2 — pasar el período desde el pipeline: en profile_table.py:_build_series_block, cuando exista order_col datetime, inferir la frecuencia del índice y pasar period= explícito a stl_decompose. Si no se puede determinar un período fiable, que stl_decompose no reporte seasonal_strength=0 como conclusión: devolver note "período no determinado" (ya hay una rama así en :139-145; extenderla a los casos que hoy caen en period=2).
  3. H8 — correlación sobre retornos para series no estacionarias: en la sección de correlaciones de profile_table.py:346-384, cuando una columna sea una serie no estacionaria de niveles (verdict non_stationary/inconclusive, ya detectado), correlacionar sobre retornos/diferencias (to_returns, ya importado) o marcar esos pares de niveles como "posible espuria" junto a la tabla. El aviso global existe pero está lejos de los números.
  4. H13 — retornos vs diferencias por semántica: en profile_table.py:189 / to_returns.py, elegir "retornos" (financiero, estrictamente positivo multiplicativo) vs "diferencias" (físico, aditivo) según la naturaleza, o usar "diferencias" por defecto cuando no haya señal financiera.
  5. Tests: stl_decompose_test.py (serie sintética mensual con estacionalidad anual → período correcto y seasonal_strength alta; serie con tendencia sin estacionalidad → nota, no period=2); cobertura de _build_series_block con order_col datetime.

Definition of Done

Escenario Tipo Comando / evidencia Resultado esperado
Golden: estacionalidad anual e2e re-correr profile_table con run_series=True sobre seattle temp_max seasonal_strength ≈ 0.84 con período ≈ 365 (NO "sin estacionalidad", NO period=2)
Edge: serie mensual unit stl_decompose_test.py serie mensual sintética con ciclo 12 período inferido 12 y fuerza estacional alta
Edge: sin estacionalidad unit stl_decompose_test.py serie con solo tendencia note "período no determinado", NO seasonal_strength=0 como conclusión
Error: serie corta unit stl_decompose([...]<2*period) nota "serie corta", sin crash (contrato actual)
H8 e2e re-correr profile_table sobre aapl/btc pares de niveles no estacionarios marcados como posible espuria o correlación sobre retornos
Mecánica ./fn run stl_decompose_py_datascience; fn index tests verdes; índice limpio

Re-correr el benchmark sobre seattle, fred-unrate, aapl y btc y confirmar que la estacionalidad se detecta donde existe y no se inventa donde no.

Notas

Issue derivado de temp/eda_benchmark/EDA_ISSUES.md. H2 es el segundo bloqueante de fiabilidad: un "sin estacionalidad" donde la hay es un falso negativo que un decisor creería. La estacionariedad ya funciona — no tocarla. Hermanos: 0173, 0175, 0176, 0177.