---
name: stl_decompose
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: pure
signature: "def stl_decompose(values: list, period: int = None, robust: bool = True) -> dict"
description: "Descomposicion STL (Seasonal-Trend using Loess, statsmodels) de una serie temporal en tendencia, estacional y resto. Si period es None lo infiere por autocorrelacion. Devuelve las 3 componentes (o estadisticos si son largas), mas la fuerza de tendencia y de estacionalidad de Hyndman (1 - Var(resto)/Var(resto+componente)). Descarta None/NaN; serie corta (<2*period) -> nota."
tags: [statistics, timeseries, decomposition, stl, seasonality, trend, eda, forecasting, python]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [math, numpy, statsmodels]
params:
  - name: values
    desc: "serie temporal de valores numericos en orden cronologico. None/NaN/infinitos/no-numericos se descartan antes de descomponer."
  - name: period
    desc: "periodo estacional (observaciones por ciclo, p.ej. 12 para mensual con estacionalidad anual). Si None se infiere por autocorrelacion; si no hay periodo claro devuelve nota."
  - name: robust
    desc: "si True (default) usa el ajuste robusto de STL, que reduce el efecto de outliers sobre tendencia y estacionalidad."
output: "dict con 'period' usado, 'period_inferred' (bool), 'trend'/'seasonal'/'resid' (cada uno min/max/mean/std + values si la serie es corta, si no None), 'trend_strength' y 'seasonal_strength' (medidas de Hyndman en [0,1]). Serie insuficiente o sin periodo inferible: dict con 'note' y strengths en None. Nunca lanza excepcion."
tested: true
tests: ["test_serie_con_tendencia_y_estacionalidad", "test_fuerza_estacional_alta_con_estacionalidad_fuerte", "test_infiere_periodo_si_none", "test_serie_corta_devuelve_nota", "test_muestra_insuficiente_devuelve_nota", "test_descarta_none_y_nan", "test_serie_larga_resume_sin_values"]
test_file_path: "python/functions/datascience/stl_decompose_test.py"
file_path: "python/functions/datascience/stl_decompose.py"
---

## Ejemplo

```python
from datascience import stl_decompose
import numpy as np

# Serie mensual = tendencia lineal + ciclo estacional anual (periodo 12) + ruido
rng = np.random.default_rng(0)
n = 120
serie = [0.3 * i + 10 * np.sin(2 * np.pi * i / 12) + rng.normal(0, 1) for i in range(n)]

res = stl_decompose(serie, period=12)
res["trend_strength"]       # -> ~0.99 (tendencia clara)
res["seasonal_strength"]    # -> ~0.98 (estacionalidad clara)
res["seasonal"]["values"][:3]   # primeras 3 muestras de la componente estacional

# Sin pasar periodo: lo infiere por autocorrelacion
stl_decompose(serie)["period_inferred"]   # -> True
```

## Cuando usarla

Cuando quieres separar una serie temporal en sus partes para entenderla o
prepararla para modelar: cuanta de su variacion es tendencia de fondo, cuanta es
ciclo estacional repetitivo y cuanta es ruido. Util en EDA para decidir si merece
la pena desestacionalizar antes de comparar periodos, para detectar un cambio de
tendencia, o para extraer features (las fuerzas de tendencia/estacionalidad de
Hyndman resumen la serie en dos numeros comparables entre series).

## Gotchas

- Es pura pero importa `statsmodels.tsa.seasonal.STL` y `numpy` (en `python/.venv`).
- STL exige al menos **dos ciclos completos**: con `n < 2*period` devuelve una
  nota en vez de descomponer. Para datos mensuales con estacionalidad anual
  (period=12) necesitas >= 24 meses.
- La inferencia automatica de `period` busca el pico de autocorrelacion; es
  heuristica. Si conoces el periodo real (12 mensual, 7 diario-semanal, 24
  horario-diario), pasalo explicito: es mas fiable.
- Las componentes largas (> 200 puntos) se resumen en estadisticos y `values`
  queda en `None` para no inflar el payload; las cortas vienen completas.
- Las fuerzas estan en `[0,1]` por construccion (se recortan a 0 si la varianza
  del resto supera la de resto+componente, lo que indica componente inexistente).
