7ac69ab4fb
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>
87 lines
5.5 KiB
Markdown
87 lines
5.5 KiB
Markdown
---
|
||
id: "0174"
|
||
title: "EDA series temporales: período estacional roto + correlación de niveles + to_returns ciego"
|
||
status: pendiente
|
||
type: bugfix
|
||
domain:
|
||
- registry-quality
|
||
scope: registry-only
|
||
priority: alta
|
||
depends: []
|
||
blocks: []
|
||
related: ["0173", "0175", "0176", "0177"]
|
||
created: 2026-06-29
|
||
updated: 2026-06-29
|
||
tags: [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 `Close–Open=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 gana** → `period=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.
|