Metadata-Version: 2.5
Name: estadistica-ambiental
Version: 1.4.0
Summary: Plantilla Python para estadística aplicada al medio ambiente
Author: Dan Méndez
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: hydroeval>=0.1
Requires-Dist: matplotlib>=3.8
Requires-Dist: numpy>=1.26
Requires-Dist: openpyxl>=3.1
Requires-Dist: optuna>=3.5
Requires-Dist: pandas>=2.0
Requires-Dist: pyarrow>=14.0
Requires-Dist: pymannkendall>=1.4
Requires-Dist: requests>=2.31
Requires-Dist: scikit-learn>=1.4
Requires-Dist: scipy>=1.11
Requires-Dist: seaborn>=0.13
Requires-Dist: statsmodels>=0.14
Provides-Extra: bayes
Requires-Dist: arviz<1,>=0.18; extra == 'bayes'
Requires-Dist: pymc<6,>=5.9; extra == 'bayes'
Provides-Extra: deep
Requires-Dist: torch>=2.1; extra == 'deep'
Provides-Extra: dev
Requires-Dist: ipykernel>=6.29; extra == 'dev'
Requires-Dist: jupyterlab>=4.1; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.3; extra == 'dev'
Provides-Extra: docs
Requires-Dist: jupyter-server>=2.10; extra == 'docs'
Requires-Dist: jupyterlite-core>=0.3; extra == 'docs'
Requires-Dist: jupyterlite-pyodide-kernel>=0.3; extra == 'docs'
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
Provides-Extra: fast
Requires-Dist: polars>=0.20; extra == 'fast'
Provides-Extra: ml
Requires-Dist: lightgbm>=4.2; extra == 'ml'
Requires-Dist: xgboost>=2.0; extra == 'ml'
Provides-Extra: netcdf
Requires-Dist: h5netcdf>=1.3; extra == 'netcdf'
Requires-Dist: netcdf4>=1.6; extra == 'netcdf'
Provides-Extra: profile
Requires-Dist: missingno>=0.5; extra == 'profile'
Requires-Dist: plotly>=5.18; extra == 'profile'
Requires-Dist: sweetviz>=2.3; extra == 'profile'
Requires-Dist: ydata-profiling>=4.6; extra == 'profile'
Provides-Extra: prophet
Requires-Dist: prophet>=1.1; extra == 'prophet'
Provides-Extra: spatial
Requires-Dist: branca>=0.7; extra == 'spatial'
Requires-Dist: contextily>=1.5; extra == 'spatial'
Requires-Dist: esda>=2.5; extra == 'spatial'
Requires-Dist: folium>=0.15; extra == 'spatial'
Requires-Dist: geopandas>=0.14; extra == 'spatial'
Requires-Dist: pykrige>=1.7; extra == 'spatial'
Requires-Dist: pyproj>=3.6; extra == 'spatial'
Requires-Dist: pysal>=23.7; extra == 'spatial'
Requires-Dist: rasterio>=1.3; extra == 'spatial'
Requires-Dist: rioxarray>=0.15; extra == 'spatial'
Requires-Dist: shapely>=2.0; extra == 'spatial'
Requires-Dist: xarray>=2024.1; extra == 'spatial'
Description-Content-Type: text/markdown

<div align="center">

# 🌎 Estadística Ambiental

**Base de conocimiento Python para el ciclo estadístico completo aplicado a datos ambientales colombianos**

EDA · estadística descriptiva e inferencial · modelos predictivos · reportes de cumplimiento normativo.
Metodología de estándares internacionales (ISO, WMO, literatura peer-reviewed) con implementación de referencia para Colombia.

[![PyPI](https://img.shields.io/pypi/v/estadistica-ambiental.svg?label=PyPI&style=for-the-badge)](https://pypi.org/project/estadistica-ambiental/)
[![Descargas PyPI](https://img.shields.io/pypi/dm/estadistica-ambiental.svg?label=descargas%2Fmes&style=for-the-badge)](https://pypi.org/project/estadistica-ambiental/)
[![Release](https://img.shields.io/github/v/release/DanMendezZz/Estadistica_Ambiental?style=for-the-badge&label=release)](https://github.com/DanMendezZz/Estadistica_Ambiental/releases)
[![Python](https://img.shields.io/pypi/pyversions/estadistica-ambiental.svg?style=for-the-badge&logo=python&logoColor=white)](https://pypi.org/project/estadistica-ambiental/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](LICENSE)

[![pandas](https://img.shields.io/badge/pandas-150458?style=for-the-badge&logo=pandas&logoColor=white)](https://pandas.pydata.org/)
[![scikit-learn](https://img.shields.io/badge/scikit--learn-F7931E?style=for-the-badge&logo=scikitlearn&logoColor=white)](https://scikit-learn.org/)
[![statsmodels](https://img.shields.io/badge/statsmodels-3776AB?style=for-the-badge)](https://www.statsmodels.org/)
[![Optuna](https://img.shields.io/badge/Optuna-0078D4?style=for-the-badge)](https://optuna.org/)
[![XGBoost](https://img.shields.io/badge/XGBoost-EB0028?style=for-the-badge)](https://xgboost.readthedocs.io/)
[![LightGBM](https://img.shields.io/badge/LightGBM-02569B?style=for-the-badge)](https://lightgbm.readthedocs.io/)
[![GeoPandas](https://img.shields.io/badge/GeoPandas-139C5A?style=for-the-badge)](https://geopandas.org/)
[![mkdocs](https://img.shields.io/badge/docs-mkdocs--material-blue.svg?style=for-the-badge)](https://danmendezzz.github.io/Estadistica_Ambiental/)

[![CI](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/ci.yml/badge.svg)](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/ci.yml)
[![Release workflow](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/release.yml/badge.svg)](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/release.yml)
[![Docs](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/docs.yml/badge.svg)](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/docs.yml)
[![Pages](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/pages.yml/badge.svg)](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/pages.yml)
[![Scheduled checks](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/scheduled.yml/badge.svg)](https://github.com/DanMendezZz/Estadistica_Ambiental/actions/workflows/scheduled.yml)
[![codecov](https://codecov.io/gh/DanMendezZz/Estadistica_Ambiental/branch/main/graph/badge.svg)](https://codecov.io/gh/DanMendezZz/Estadistica_Ambiental)

```bash
pip install estadistica-ambiental
```

📚 **Documentación:** <https://danmendezzz.github.io/Estadistica_Ambiental/>  ·  📓 **Notebooks sin instalar (Pyodide):** [JupyterLite live](https://danmendezzz.github.io/Estadistica_Ambiental/lite/)

<p>
<a href="#qué-encontrás-en-este-repo">Qué hay</a> ·
<a href="#metodología">Metodología</a> ·
<a href="#resultados-y-validación">Resultados</a> ·
<a href="#estructura-del-proyecto">Estructura</a> ·
<a href="#instalación">Instalación</a> ·
<a href="#quick-start">Quick Start</a> ·
<a href="#catálogo-de-modelos">Modelos</a> ·
<a href="#17-líneas-temáticas">17 Líneas temáticas</a> ·
<a href="#normativa-colombiana-integrada">Normativa</a> ·
<a href="#trabajo-futuro">Roadmap</a>
</p>

> **Nota:** el repositorio cubre 17 líneas temáticas (páramos, humedales, calidad del aire, oferta hídrica,
> áreas protegidas y más). Cada línea tiene su propia ficha de dominio, notebook plantilla y normas
> colombianas integradas en el código.

</div>

---

<details>
<summary><b>📑 Tabla de contenido</b> (click para expandir)</summary>

1. [¿Qué encontrás en este repo?](#qué-encontrás-en-este-repo)
2. [¿Para quién es este repo?](#para-quién-es-este-repo)
3. [Motivación](#motivación)
4. [Metodología](#metodología)
5. [Resultados y validación](#resultados-y-validación)
6. [Estructura del proyecto](#estructura-del-proyecto)
7. [Arquitectura base ↔ satélite](#arquitectura-base--satélite)
8. [Instalación](#instalación)
9. [Consumir desde otro proyecto (este repo es base de conocimiento)](#consumir-desde-otro-proyecto-este-repo-es-base-de-conocimiento)
10. [Probá sin instalar nada (JupyterLite)](#probá-sin-instalar-nada--jupyterlite)
11. [Datos reales (uso opcional, sin duplicar)](#datos-reales-uso-opcional-sin-duplicar)
12. [Quick Start](#quick-start)
13. [Catálogo de modelos](#catálogo-de-modelos)
14. [17 Líneas temáticas](#17-líneas-temáticas)
15. [Normativa colombiana integrada](#normativa-colombiana-integrada)
16. [Reportes automáticos](#reportes-automáticos)
17. [Flujo por línea temática](#flujo-por-línea-temática)
18. [Compatibilidad y extras](#compatibilidad-y-extras)
19. [Trabajo futuro](#trabajo-futuro)
20. [Atribución](#atribución)

</details>

---

## ¿Qué encontrás en este repo?

Este repo es **base de conocimiento + librería reutilizable**, no un producto final. Concretamente:

- **11 módulos del pipeline estadístico** (ver [tabla de módulos](#estructura-del-proyecto)) instalables con `pip install estadistica-ambiental`.
- **16 notebooks plantilla** por línea temática (calidad del aire, oferta hídrica, páramos, humedales, …) que recorren el ciclo completo end-to-end con datos sintéticos o reales.
- **20 ADRs** ([`docs/decisiones.md`](docs/decisiones.md) + [`docs/adr/`](docs/adr/)) con el porqué de cada decisión metodológica: outliers como señal real, RMSLE en variables negativas, ENSO con lag por ecosistema, normas centralizadas, base↔satélite, OIDC para PyPI.
- **16 fichas de dominio** ([`docs/fuentes/<linea>.md`](docs/fuentes/)) con normas regulatorias, fuentes públicas, umbrales y buenas prácticas por línea temática.
- **Normas colombianas centralizadas** en `config.py` (Res. 2254/2017, 2115/2007, 631/2015, IUA, IRH, ICA, ENSO).
- **Más de 700 tests · CI verde · cobertura ~84 %** sobre Linux + Windows; sitio mkdocs auto-publicado a GitHub Pages tras cada push a `main`.

---

## ¿Para quién es este repo?

| Sos... | Empezá por |
| --- | --- |
| **Analista en CAR / IDEAM / MADS / alcaldía** | [Quick Start](#quick-start) → [17 Líneas temáticas](#17-líneas-temáticas) → notebooks en `notebooks/lineas_tematicas/` |
| **Estudiante de estadística ambiental** | [JupyterLite live](https://danmendezzz.github.io/Estadistica_Ambiental/lite/) (sin instalar nada) → [Resultados y validación](#resultados-y-validación) → [`docs/decisiones.md`](docs/decisiones.md) |
| **Docente o investigador** | [`docs/decisiones.md`](docs/decisiones.md) (20 ADRs) → [`docs/fuentes/`](docs/fuentes/) (fichas de dominio) → [Catálogo de modelos](#catálogo-de-modelos) |
| **Desarrollador de un satélite** | [Consumir desde otro proyecto](#consumir-desde-otro-proyecto-este-repo-es-base-de-conocimiento) → patrón documentado en [ADR-018](docs/adr/ADR-018-base-satelite-governance.md) |

> **Nota didáctica:** las decisiones difíciles (cuándo usar SARIMA vs ML, por qué obligamos ADF+KPSS, cuándo
> validar contra OMS y cuándo contra Res. 2254) están **documentadas como ADR**, no escondidas en el código.
> Si vas a defender una metodología, los ADRs son el insumo principal.

---

## Motivación

Los analistas de entidades ambientales colombianas (CAR, IDEAM, MADS, alcaldías) enfrentan un problema
recurrente: **cada proyecto estadístico parte de cero**. Los datos cambian, la variable también, pero el
ciclo analítico es siempre el mismo: cargar, validar, describir, inferir, modelar, reportar.

Este repositorio resuelve eso con una **base de conocimiento reutilizable** que combina tres cosas
que raramente aparecen juntas en un solo lugar:

- **Metodología documentada**: decisiones de diseño (ADR-001 a ADR-020), buenas prácticas calibradas
  sobre datos reales y fichas de dominio por línea temática.
- **Normas colombianas en el código**: Res. 2254/2017 (calidad del aire), 2115/2007 (agua potable),
  631/2015 (vertimientos) e índices IDEAM listos para usarse con un solo import, sin hardcodear umbrales.
- **Código validado sobre datos reales**: el pipeline de calidad del aire fue ejecutado sobre series
  horarias de PM2.5 de una red de monitoreo en Cundinamarca (fuente: SISAIRE / IDEAM). Los resultados
  son reproducibles con los datos públicos de la plataforma.

El repo no reemplaza el juicio del analista; **documenta el camino** para que no tenga que redescubrirlo
cada vez.

> **Alcance metodológico:** los métodos estadísticos implementados (SARIMA, Kriging, GWR, I de Moran,
> XGBoost, Prophet, etc.) son estándares internacionales aplicables a cualquier contexto ambiental.
> La capa de dominio (normas regulatorias, fuentes de datos, umbrales, índices) está calibrada para
> Colombia y el Sistema Nacional Ambiental (SINA). Adaptar el repo a otro país implica únicamente
> reemplazar las constantes de `config.py` con la normativa local.

---

## Metodología

El ciclo estadístico está implementado como **módulos independientes y encadenables**. Cada línea
temática recorre el ciclo completo o solo las etapas que aplican.

### 1 — Ingesta y validación

`io/loaders.py` lee CSV, Excel, Parquet, NetCDF y Shapefile. `io/validators.py` aplica **74 rangos
físicos calibrados** (temperatura, caudal, pH, PM2.5, OD, NDVI, etc.) con sobrescrituras por línea
temática (`linea_tematica="paramos"` ajusta temperatura máx a 16 °C en lugar de 45 °C).

```python
from estadistica_ambiental.io.loaders import load_csv
from estadistica_ambiental.io.validators import validate

df  = load_csv("data/raw/pm25_sisaire.csv", date_col="fecha")
val = validate(df, date_col="fecha", linea_tematica="calidad_aire")
```

### 2 — Análisis Exploratorio (EDA)

`eda/quality.py` detecta faltantes (patrón MCAR/MAR/MNAR), duplicados, inconsistencias temporales y
congelamiento de sensor. `eda/profiling.py` genera un reporte HTML con `ydata-profiling` o con la
plantilla propia del repo cuando el extra `[profile]` no está instalado.

### 3 — Estadística descriptiva

`descriptive/` cubre univariada (media, mediana, IQR, asimetría, curtosis), bivariada (Pearson,
Spearman, Kendall, tablas de contingencia) y temporal (descomposición STL, ACF/PACF, rolling stats).

### 4 — Estadística inferencial

`inference/stationarity.py` implementa **ADF + KPSS de forma obligatoria** antes de cualquier modelo
ARIMA (ADR-004). `inference/trend.py` expone Mann-Kendall, Sen's slope y Pettitt. `inference/intervals.py`
calcula excedencias contra normas colombianas y guías OMS 2021:

```python
from estadistica_ambiental.inference.stationarity import stationarity_report
from estadistica_ambiental.inference.trend import mann_kendall
from estadistica_ambiental.inference.intervals import exceedance_report

stationarity_report(ts)           # ADF + KPSS combinados
mk = mann_kendall(ts)
print(f"Tendencia: {mk['trend']} | slope={mk['slope']:.4f}")

print(exceedance_report(ts, variable="pm25"))
# → tabla vs. Res. 2254/2017 (37 µg/m³ 24h) y OMS 2021 (15 µg/m³)
```

### 5 — Covariables climáticas (ENSO/ONI)

`features/climate.py` descarga el Índice Oceánico El Niño (ONI) desde NOAA CPC y aplica el **lag
hidrológico específico por línea temática** (páramos: 2 meses, oferta hídrica: 4 meses, calidad del
aire: 2 meses). El lag viene de `config.ENSO_LAG_MESES` y es sobrescribible:

```python
from estadistica_ambiental.features.climate import load_oni, enso_lagged

oni = load_oni()
df  = enso_lagged(df, oni, date_col="fecha", linea_tematica="oferta_hidrica")
```

### 6 — Modelado predictivo con optimización bayesiana

`predictive/registry.py` expone un catálogo uniforme de 10 modelos. `optimization/bayes_opt.py`
usa **Optuna TPE con `multivariate=True`** para ajustar hiperparámetros. `evaluation/backtesting.py`
implementa walk-forward expanding/sliding con parámetro `gap=` para evitar leakage en series con
autocorrelación alta (crítico en PM2.5 horario con ACF ≈ 0.97):

```python
from estadistica_ambiental.predictive.registry import get_model
from estadistica_ambiental.evaluation.backtesting import walk_forward
from estadistica_ambiental.evaluation.comparison import rank_models

models = {
    "XGBoost":     get_model("xgboost", lags=[1, 2, 3, 6, 12, 24]),
    "SARIMA":      get_model("sarima", order=(1,1,1), seasonal_order=(1,1,1,24)),
    "RandomForest": get_model("random_forest", lags=[1, 2, 3, 6, 12, 24]),
}
results = {
    name: walk_forward(model, ts, horizon=24, n_splits=5,
                       gap=24, domain="air_quality")
    for name, model in models.items()
}
rank_models(results)[["rmse", "nrmse", "hit_rate_ica", "rank"]]
```

### 7 — Cumplimiento normativo y reporte HTML

`reporting/compliance_report.py` genera un HTML independiente con semáforo por variable,
tabla de excedencias con cada norma colombiana aplicable y período de retorno. La lógica de
cálculo vive en `inference/intervals.py` (testeable de forma aislada, ADR-008):

```python
from estadistica_ambiental.reporting.compliance_report import compliance_report

compliance_report(df, variables=["pm25", "pm10"],
                  linea_tematica="calidad_aire",
                  output="data/output/reports/cumplimiento.html")
```

---

## Resultados y validación

### Comparación de modelos — PM2.5 horario

Backtesting walk-forward (`gap=24h`, 5 folds) sobre series horarias de PM2.5.
Fuente de datos: SISAIRE / IDEAM, red de monitoreo calidad del aire, Cundinamarca.

| Modelo | RMSE (µg/m³) | NRMSE | HitRate ICA | Recall >55 µg/m³ | Rol |
|---|---|---|---|---|---|
| **XGBoost** | **3.717** | **0.426** | 88.61% | **15.50%** | Producción |
| LightGBM | 3.724 | 0.427 | 88.62% | 13.69% | Producción |
| Random Forest | 3.716 | 0.426 | **88.67%** | 13.15% | Producción |
| SARIMAX | ~4.5 | – | ~75% | – | Con meteo disponible |
| SARIMA | 5.916 | 0.872 | 69.39% | 0% | Benchmark estadístico |
| LSTM | 10.178 | 1.211 | 63.44% | 0.82% | Referencia deep |

> Score combinado = 30% RMSE normalizado + 10% NRMSE + 25% HitRate ICA + 20% F1 ponderado + 15% Recall >55 µg/m³

![Comparación de modelos](docs/img/model_comparison.png)

*Comparación de RMSE, NRMSE y HitRate ICA entre los 6 modelos evaluados en backtesting walk-forward sobre PM2.5 horario (fuente: SISAIRE / IDEAM, Cundinamarca).*

**Hallazgo clave:** para series horarias con ACF alta (≈ 0.97 en lag-1h), los modelos ML con
lag features superan ampliamente a SARIMA. El gap de 24h en walk-forward redujo el learning
curve gap de 0.38 a 0.048; sin gap, el R² está inflado por leakage de autocorrelación.

### Pronóstico con bandas de incertidumbre

La arquitectura **AR(1) doble-escala** genera pronósticos probabilísticos (P10/P50/P90) sin
reentrenar el modelo base:

```
ŷ(t) = base_RF(t)                         ← componente estacional/tendencia
      + Δ_nivel × exp(−t / τ)             ← corrección nivel sinóptica (τ ≈ 48–185 h)
      + e_AR(t), donde e_AR(t) = φ·e_AR(t−1) + σ·ε(t)   ← AR(1) horario (φ ≈ 0.63–0.93)
```

![Pronóstico PM2.5 con incertidumbre](docs/img/forecast_ar1.png)

*Pronóstico PM2.5 con bandas P10/P50/P90 generadas por el componente AR(1) horario sobre la corrección de nivel sinóptica del modelo base RF.*

### Showcase: cumplimiento normativo PM2.5/PM10 (estación Kennedy)

El sitio auto-publicado [`/showcase/`](https://danmendezzz.github.io/Estadistica_Ambiental/showcase/) (workflow `pages.yml`,
regenerado cada lunes vía `scripts/generate_showcase.py`) muestra el semáforo de cumplimiento normativo
para PM2.5 y PM10 sobre la estación Kennedy (red RMCAB Bogotá, 2022–2024): excedencias contra Res.
2254/2017 y OMS 2021, con tabla detallada por norma y gráficos Chart.js interactivos.

<!-- TODO: falta generar una captura real (screenshot) de docs/showcase/index.html para embeber aquí.
     No se genera una imagen inventada: el HTML vive en docs/showcase/index.html y también se
     publica en vivo vía GitHub Pages (workflow pages.yml). -->

### Caso de uso productivo: pipeline CAR (Cundinamarca)

El proyecto hermano **"Calidad de aire CAR"** (red SISAIRE / IDEAM, 34 estaciones, 2016–2026)
es la primera validación operacional del repo en datos reales. Confirma de forma independiente
varias decisiones del repo:

- `walk_forward(gap=24)`: el gap de 24 h fue redescubierto en CAR por leakage de autocorrelación PM2.5 (r ≈ 0.97 lag-1h).
- `exceedance_report()` con Res. 2254/2017 y OMS 2021: utilizado en backtesting 2025 y reporte ejecutivo.
- `enso_lagged(lag_meses=2)` para calidad del aire: coincidencia con la literatura colombiana.

Métricas en producción: **RMSE = 3.717 µg/m³**, **HitRate ICA = 88.61 %**, **27/31 estaciones AR(1) PASS**
(tests T1–T4 + KS + Ljung-Box + Jarque-Bera). El feedback recíproco está documentado en el proyecto hermano de pronóstico.

---

## Estructura del proyecto

### Los 11 módulos del pipeline

| Módulo | Qué hace | Función clave | Doc |
|---|---|---|---|
| `io` | Carga (CSV · Excel · Parquet · NetCDF · Shapefile) y validación con 74 rangos físicos calibrados | `load_csv()` · `validate()` | [`docs/metodologia.md`](docs/metodologia.md) |
| `eda` | Perfilado automático, calidad de datos (faltantes, duplicados, congelamiento de sensor) | `run_eda()` | [`docs/metodologia.md`](docs/metodologia.md) |
| `preprocessing` | Imputación (lineal · rolling · KNN · MICE) y outliers opt-in (ADR-002) | `impute()` | [ADR-002](docs/decisiones.md) |
| `descriptive` | Estadística univariada, bivariada y temporal (STL, ACF/PACF) | `univariate_summary()` | [`docs/metodologia.md`](docs/metodologia.md) |
| `inference` | ADF+KPSS obligatorios, tendencia (Mann-Kendall), excedencias normativas | `exceedance_report()` | [ADR-004](docs/decisiones.md) · [ADR-008](docs/decisiones.md) |
| `spatial` | Kriging, GWR, I de Moran, autocorrelación espacial | `moran_i()` | [`docs/modelos.md`](docs/modelos.md) |
| `features` | Lags, encoding cíclico, ENSO/ONI con lag por línea temática | `enso_lagged()` | [ADR-007](docs/decisiones.md) |
| `predictive` | Catálogo uniforme de 10 modelos (ARIMA a LSTM) | `get_model()` | [`docs/modelos.md`](docs/modelos.md) |
| `optimization` | Optimización bayesiana de hiperparámetros con Optuna TPE | `optimize()` | [`docs/metodologia.md`](docs/metodologia.md) |
| `evaluation` | Backtesting walk-forward con `gap=`, ranking multi-criterio, métricas NSE/KGE | `walk_forward()` · `rank_models()` | [`docs/metodologia.md`](docs/metodologia.md) |
| `reporting` | Reportes HTML autocontenidos (cumplimiento, pronóstico, descriptiva) | `compliance_report()` | [ADR-008](docs/decisiones.md) |

```mermaid
flowchart TD
    IO["io<br/>loaders · validators · connectors"] --> EDA["eda<br/>quality · profiling · viz"]
    EDA --> PRE["preprocessing<br/>imputation · outliers"]
    PRE --> DESC["descriptive<br/>univariate · bivariate · temporal"]
    DESC --> INF["inference<br/>stationarity · trend · intervals"]
    INF --> FEAT["features<br/>lags · calendar · climate(ENSO)"]
    FEAT --> SPA["spatial<br/>kriging · GWR · Moran's I"]
    SPA --> PRED["predictive<br/>registry · classical · ml · deep"]
    PRED --> OPT["optimization<br/>bayes_opt (Optuna TPE)"]
    OPT --> EVAL["evaluation<br/>backtesting · comparison · anomaly"]
    EVAL --> REP["reporting<br/>compliance · forecast · stats"]
```

<details>
<summary><b>🗂️ Árbol completo del repositorio</b> (click para expandir)</summary>

```
Estadistica_Ambiental/
│
├── src/estadistica_ambiental/
│   ├── config.py                  ← normas colombianas, ENSO lags, rutas
│   │
│   ├── io/
│   │   ├── loaders.py             ← CSV · Excel · Parquet · NetCDF · Shapefile
│   │   ├── validators.py          ← 74 rangos físicos + sobrescrituras por línea
│   │   └── connectors.py          ← OpenAQ · RMCAB · SIATA · IDEAM DHIME · SMByC
│   │
│   ├── eda/
│   │   ├── profiling.py           ← reporte HTML automático (ydata-profiling / propio)
│   │   ├── quality.py             ← faltantes · duplicados · congelamiento de sensor
│   │   ├── variables.py           ← tipificación automática de columnas
│   │   └── viz.py                 ← series · boxplots · heatmaps · missingno
│   │
│   ├── preprocessing/
│   │   ├── imputation.py          ← lineal · rolling · KNN · MICE
│   │   ├── outliers.py            ← IQR opt-in (ADR-002: picos ambientales = señal real)
│   │   └── air_quality.py         ← flag_spatial_episodes · categorize_ica · correct_seasonal_bias
│   │
│   ├── descriptive/
│   │   ├── univariate.py          ← media · mediana · IQR · asimetría · curtosis
│   │   ├── bivariate.py           ← Pearson · Spearman · Kendall · contingencia
│   │   └── temporal.py            ← STL · ACF · PACF · rolling stats
│   │
│   ├── inference/
│   │   ├── stationarity.py        ← ADF + KPSS obligatorios (ADR-004)
│   │   ├── trend.py               ← Mann-Kendall · Sen's slope · Pettitt
│   │   ├── hypothesis.py          ← t-test · Mann-Whitney · ANOVA · Kruskal-Wallis
│   │   ├── distributions.py       ← Shapiro-Wilk · lognormal · gamma · Weibull · Gumbel
│   │   └── intervals.py           ← exceedance_report() vs. normas CO + OMS
│   │
│   ├── features/
│   │   ├── lags.py                ← lag features configurables
│   │   ├── calendar.py            ← encoding cíclico (hora · día · semana)
│   │   ├── climate.py             ← enso_lagged() · load_oni() — lag por línea (ADR-007)
│   │   └── exogenous.py           ← alineación de covariables meteorológicas
│   │
│   ├── predictive/
│   │   ├── registry.py            ← get_model() · list_models() · register()
│   │   ├── classical.py           ← ARIMA · SARIMA · SARIMAX · ETS
│   │   ├── prophet_model.py       ← Prophet con exógenas
│   │   ├── ml.py                  ← XGBoost · RandomForest · LightGBM
│   │   ├── deep.py                ← LSTM · GRU (requiere [deep])
│   │   ├── spatial_models.py      ← Kriging · GP espacio-temporal
│   │   └── base.py                ← BaseModel · OptimizationResult · ModelSpec
│   │
│   ├── optimization/
│   │   └── bayes_opt.py           ← Optuna TPE multivariate · warm starts · MedianPruner
│   │
│   ├── evaluation/
│   │   ├── metrics.py             ← MAE · RMSE · NSE · KGE · hit_rate_ica por contaminante
│   │   ├── backtesting.py         ← walk_forward(gap=) · expanding · sliding
│   │   ├── comparison.py          ← rank_models() · select_best()
│   │   └── anomaly.py             ← detect_anomalies() · anomaly_summary()
│   │
│   └── reporting/
│       ├── compliance_report.py   ← HTML semáforo normativo (ADR-008)
│       ├── forecast_report.py     ← HTML forecast interactivo con Chart.js
│       └── stats_report.py        ← HTML descriptiva + ADF/KPSS + Mann-Kendall
│
├── docs/
│   ├── fuentes/                   ← 16 fichas técnicas de dominio
│   │   └── calidad_aire.md        ← variables · ICA µg/m³ · buenas prácticas BP-1 a BP-7
│   ├── decisiones.md              ← ADR-001 a ADR-013
│   ├── adr/                       ← ADR-014 a ADR-020
│   ├── showcase/                  ← index.html – cumplimiento normativo estación Kennedy (RMCAB)
│   ├── img/                       ← model_comparison.png · forecast_ar1.png
│   ├── metodologia.md             ← ciclo estadístico detallado
│   ├── modelos.md                 ← catálogo de modelos y cuándo usar cada uno
│   └── intake_lider.md            ← cuestionario onboarding líderes de área (18 preguntas)
│
├── notebooks/lineas_tematicas/
│   ├── bloque_a_gestion/          ← 13 notebooks (uno por línea temática)
│   ├── bloque_b_transversales/    ← calidad_aire · cambio_climatico
│   └── bloque_c_tecnicas/         ← geoespacial
│
├── scripts/
│   ├── run_linea_tematica.py      ← CLI unificado: --linea · --modelos · --list
│   ├── fase8_calidad_aire.py      ← showcase con datos reales PM2.5 SISAIRE
│   ├── generate_showcase.py       ← genera docs/showcase/index.html (workflow pages.yml)
│   └── build_notebooks.py         ← regenera los 16 notebooks desde plantilla
│
└── tests/                         ← más de 700 tests · ~84% cobertura · CI ubuntu + windows
```

</details>

---

## Arquitectura base ↔ satélite

Este repo es la **base**: librería + metodología + notebooks plantilla, publicada en PyPI y sin
dependencias de producto concreto. Los dashboards, ETLs y reportes ejecutivos para una entidad
específica viven en **repos satélite** que importan `estadistica-ambiental` con versión pineada
(patrón formalizado en [ADR-018](docs/adr/ADR-018-base-satelite-governance.md)).

```mermaid
flowchart LR
    subgraph BASE["Estadistica_Ambiental (este repo - base)"]
        direction TB
        M["11 módulos del pipeline"]
        N["16 notebooks plantilla"]
        F["16 fichas de dominio"]
        A["ADR-001 a ADR-020"]
    end

    BASE -->|"pip install<br/>estadistica-ambiental==X.Y.Z<br/>(pin exacto)"| S1["calidad-aire-CAR<br/>(dashboard CAR-específico)"]
    BASE -->|pin exacto| S2["paramos-rabanal<br/>(satélite previsto)"]
    BASE -->|pin exacto| S3["pomca-magdalena<br/>(satélite previsto)"]

    S1 -.->|"nunca al revés:<br/>la base no depende<br/>de ningún satélite"| BASE
```

**Reglas clave del ADR:** la base nunca depende de un satélite (coupling unidireccional); cada
satélite pinea la versión exacta de la base (`estadistica-ambiental==1.4.0`, no rangos abiertos);
apps Streamlit/Dash, pipelines ETL nocturnos, configuraciones de deploy productivo y datos crudos
de cliente **no** viven en este repo. El primer satélite materializado (`Estadistica_Ambiental_Dashboard`)
validó el patrón y fue retirado el 2026-07-24 una vez cumplido su propósito de referencia; la
estructura queda documentada en el ADR para el próximo satélite que se instancie.

---

## Instalación

### Desde PyPI (recomendado para uso normal)

```bash
pip install estadistica-ambiental
```

Con extras opcionales:

```bash
pip install "estadistica-ambiental[ml]"           # XGBoost, LightGBM
pip install "estadistica-ambiental[spatial]"      # geopandas, pykrige, pysal, folium
pip install "estadistica-ambiental[prophet]"      # Meta Prophet
pip install "estadistica-ambiental[deep]"         # PyTorch (LSTM/GRU)
pip install "estadistica-ambiental[ml,spatial]"   # combinaciones
```

Verificar la instalación:

```python
import estadistica_ambiental as ea
print(ea.__version__)
```

### Para desarrollar el repo (clone)

```bash
git clone https://github.com/DanMendezZz/Estadistica_Ambiental.git
cd Estadistica_Ambiental
pip install -e ".[dev,docs]"
```

### Dependencias core

Python 3.10+ con: `pandas`, `numpy`, `scipy`, `statsmodels`, `scikit-learn`, `optuna`,
`hydroeval`, `pymannkendall`, `matplotlib`, `seaborn`, `requests`.
Ver `pyproject.toml` para la lista completa.

### Verificar

```bash
python -m pytest tests/ -q
# más de 700 tests — ~84% de cobertura en Linux + Windows
```

---

## Consumir desde otro proyecto (este repo es base de conocimiento)

Este repositorio es **base de conocimiento + librería reutilizable**, no un
producto final. Los dashboards, apps Streamlit, reportes ejecutivos y pipelines
productivos viven en **repos satélite** que importan `estadistica_ambiental`
como dependencia (ver [arquitectura base ↔ satélite](#arquitectura-base--satélite) arriba).

### Instalación desde PyPI (preferida)

```bash
# Última estable
pip install estadistica-ambiental

# Pinear a versión exacta (recomendado en producción)
pip install "estadistica-ambiental==1.4.0"

# Con extras
pip install "estadistica-ambiental[ml,spatial]==1.4.0"
```

### Alternativa — desde GitHub (commits sin tag, ramas, forks)

```bash
# Pin a tag concreto
pip install "git+https://github.com/DanMendezZz/Estadistica_Ambiental@v1.4.0"

# Rama main (sin garantías de estabilidad)
pip install "git+https://github.com/DanMendezZz/Estadistica_Ambiental@main"
```

> **Pin a versión siempre** en repos satélite. Evita que un commit en `main` rompa
> producción sin aviso. Cuando salga `v1.5.0` actualizás conscientemente.

### Documentación navegable

Sitio mkdocs-material con API reference auto-generada, ADRs, fichas de dominio
y changelog: **<https://danmendezzz.github.io/Estadistica_Ambiental/>**.

Para construir el sitio localmente:

```bash
pip install -e ".[docs]"
mkdocs serve
```

### Imports típicos en un repo satélite

```python
# Conectores y validación
from estadistica_ambiental.io.connectors import load_sisaire_local, load_openaq
from estadistica_ambiental.io.validators import validate

# Reglas de dominio (normas colombianas, ENSO, ICA)
from estadistica_ambiental.config import NORMA_CO, NORMA_OMS, ENSO_LAG_MESES
from estadistica_ambiental.features.climate import enso_lagged, load_oni

# Análisis y reportes
from estadistica_ambiental.inference.intervals import exceedance_report
from estadistica_ambiental.inference.stationarity import stationarity_report
from estadistica_ambiental.evaluation.backtesting import walk_forward
from estadistica_ambiental.reporting.compliance_report import compliance_report
```

### Qué SÍ vive en este repo (base)

- Módulos reusables del ciclo estadístico (`src/estadistica_ambiental/`).
- Conectores genéricos a fuentes públicas (OpenAQ, SISAIRE, RMCAB, IDEAM…).
- Notebooks plantilla por línea temática (`notebooks/lineas_tematicas/`).
- Fichas de dominio (`docs/fuentes/`) y ADRs (`docs/decisiones.md`).
- Tests, CI, documentación metodológica.

### Qué NO vive aquí (va en repos satélite)

- Apps Streamlit / dashboards de cliente concreto.
- Pipelines ETL nocturnos con configuración de deploy.
- Reportes ejecutivos automatizados con identidad visual de una entidad.
- Datos crudos (sin importar tamaño; usar `SISAIRE_LOCAL_DIR` u otro).
- Credenciales, tokens API, URLs internas.

### Compatibilidad de versiones

Sigue [SemVer](https://semver.org). Los breaking changes en API pública se
marcan con bump MAJOR y se documentan en [`CHANGELOG.md`](CHANGELOG.md). Hasta
v1.x los símbolos exportados desde `from estadistica_ambiental import *` son
estables.

---

## Probá sin instalar nada — JupyterLite

Tres notebooks didácticos corren **directo en el navegador** vía Pyodide (sin Python local, sin pip,
sin descargas), pensado para estudiantes y demos rápidas:

🔗 **<https://danmendezzz.github.io/Estadistica_Ambiental/lite/>**

| Notebook | Qué muestra |
| --- | --- |
| `01_calidad_demo.ipynb` | Carga, validación con rangos físicos, EDA mínimo sobre PM2.5. |
| `02_tendencia_mann_kendall.ipynb` | Detección de tendencia con Mann-Kendall + Sen's slope sobre serie ambiental. |
| `03_excedencias_normativas.ipynb` | `exceedance_report()` contra Res. 2254/2017 y guías OMS 2021. |

> **Limitaciones de Pyodide (ADR-017):** las librerías nativas pesadas (geopandas, rasterio, XGBoost,
> Prophet, PyTorch, PyMC) **no corren en el browser**. Para esos módulos hay que instalar el paquete
> normalmente. Los notebooks de JupyterLite usan únicamente la capa puramente Python del repo.

---

## Datos reales (uso opcional, sin duplicar)

El repo no incluye datos crudos. Para trabajar con descargas locales del portal
**SISAIRE / IDEAM** (CSV anuales `CAR_<año>.csv`) se referencia la carpeta
externa con una **variable de entorno**; el repo nunca asume una ruta fija.

### 1. Configurar la variable de entorno

```powershell
# Windows (PowerShell, persistente)
setx SISAIRE_LOCAL_DIR "D:\ruta\a\Datos SISAIRE\00_Datos_Originales"
```

```bash
# Linux/macOS (en .bashrc / .zshrc)
export SISAIRE_LOCAL_DIR="/ruta/a/Datos SISAIRE/00_Datos_Originales"
```

### 2. Cargar datos sin copiarlos al repo

```python
from estadistica_ambiental.io.connectors import load_sisaire_local

# Todos los años disponibles, una estación
df = load_sisaire_local(parametro="pm25", estaciones=["BOGOTA RURAL - MOCHUELO"])

# Año específico, todas las estaciones
df = load_sisaire_local(anios=2024, parametro="pm25")

# Multi-año
df = load_sisaire_local(anios=[2023, 2024, 2025], parametro="pm25")
```

`load_sisaire_local()` lee los CSV `CAR_<año>.csv` directamente desde la carpeta
externa, normaliza encabezados (`Estacion` → `estacion`, `Fecha inicial` →
`fecha`, `PM2.5` → `pm25`) y entrega un DataFrame listo para el pipeline
(`validate()`, `exceedance_report()`, `walk_forward()`, `compliance_report()`).

Si la variable no está configurada o se pasa una ruta inexistente, se levanta
`FileNotFoundError` con instrucciones claras. Tests con archivos sintéticos en
`tests/test_connectors.py::TestLoadSisaireLocal`.

---

## Quick Start

### Análisis completo de una serie ambiental

```python
from estadistica_ambiental.io.loaders import load_csv
from estadistica_ambiental.io.validators import validate
from estadistica_ambiental.eda.profiling import run_eda
from estadistica_ambiental.inference.stationarity import stationarity_report
from estadistica_ambiental.inference.trend import mann_kendall
from estadistica_ambiental.inference.intervals import exceedance_report

df  = load_csv("data/raw/pm25_sisaire.csv", date_col="fecha")
validate(df, date_col="fecha", linea_tematica="calidad_aire")
run_eda(df, output="data/output/reports/eda.html", date_col="fecha")

ts = df.set_index("fecha")["pm25"]
stationarity_report(ts)
mk = mann_kendall(ts)
print(f"Tendencia: {mk['trend']} | slope={mk['slope']:.4f} µg/m³/año")
print(exceedance_report(ts, variable="pm25"))
```

### Backtesting multi-modelo con ranking

```python
from estadistica_ambiental.predictive.registry import get_model
from estadistica_ambiental.evaluation.backtesting import walk_forward
from estadistica_ambiental.evaluation.comparison import rank_models

models = {
    "XGBoost":     get_model("xgboost", lags=[1, 2, 3, 6, 12, 24]),
    "Prophet":     get_model("prophet"),
    "SARIMA":      get_model("sarima", order=(1,1,1), seasonal_order=(1,1,1,24)),
}
results = {
    name: walk_forward(model, ts, horizon=24, n_splits=5, gap=24, domain="air_quality")
    for name, model in models.items()
}
rank_models(results)[["rmse", "hit_rate_ica", "rank"]]
```

### Ejecutar el ciclo completo desde la línea de comandos

```bash
python scripts/run_linea_tematica.py --list                          # ver las líneas
python scripts/run_linea_tematica.py --linea oferta_hidrica          # datos sintéticos
python scripts/run_linea_tematica.py --linea paramos --modelos sarima,xgboost
python scripts/fase8_calidad_aire.py                                 # datos reales SISAIRE
```

### Snippets cortos por línea temática (`examples/`)

Para ver el patrón sin abrir un notebook completo, `examples/` contiene scripts
runnables (autocontenidos: caen a datos sintéticos si no hay descarga local):

```bash
python examples/00_quickstart.py             # ciclo mínimo: cargar → validar → describir
python examples/01_calidad_aire_pm25.py      # exceedance_report contra Res. 2254 + OMS 2021
python examples/02_oferta_hidrica_caudal.py  # NSE/KGE + ADF
python examples/03_paramos_iuh.py            # IRH + gradiente Caldas-Lang
python examples/04_cambio_climatico_co2.py   # Mann-Kendall + Sen slope
python examples/05_eda_generico.py           # run_eda + reporte HTML
```

### Notebook end-to-end con datos reales

`notebooks/showcases/calidad_aire_sisaire_real.ipynb` ejecuta el ciclo completo
sobre datos SISAIRE/CAR reales (vía `load_sisaire_local()`) o sintéticos
(fallback automático si `SISAIRE_LOCAL_DIR` no está configurada).

---

## Catálogo de modelos

| Modelo | Extra | Cuándo usarlo |
|---|---|---|
| ARIMA / SARIMA | – | Baseline; series mensuales o diarias con estacionalidad clara |
| SARIMAX | – | SARIMA + covariables meteorológicas disponibles |
| ETS / Holt-Winters | – | Baseline rápido sin exógenas |
| Prophet | `[prophet]` | Estacionalidades múltiples, eventos especiales, gaps tolerables |
| XGBoost | `[ml]` | **Producción**: PM2.5 horario · caudal diario · series con muchas exógenas |
| LightGBM | `[ml]` | Igual que XGBoost, más rápido en datasets grandes |
| Random Forest | – | Robusto sin tuning agresivo; buena línea base ML |
| LSTM / GRU | `[deep]` | Series largas (>5 años), cuando hay GPU disponible |
| Kriging / GP | `[spatial]` | Interpolación espacio-temporal entre estaciones |
| PyMC / Bayesian | `[bayes]` | Incertidumbre jerárquica multi-estación (Fase 10, ver [ADR-016](docs/adr/ADR-016-pymc-bayesiano-fase10.md)) |

Todos los modelos comparten la misma interfaz y son comparables con `walk_forward` + `rank_models`.

---

## 17 Líneas temáticas

<details>
<summary><b>📋 Ver las 17 líneas por bloque</b> (click para expandir)</summary>

### Bloque A — Gestión ambiental (13 líneas)

| Línea | Variable principal | Norma clave | ENSO lag |
|---|---|---|---|
| Áreas protegidas | cobertura (ha) · NDVI | SMByC deforestación | – |
| Humedales | nivel agua (m) | Protocolo IDEAM | 3m |
| Páramos | temperatura (°C) · precipitación | Política Páramos | 2m |
| Gestión de riesgo | precipitación (mm) | Ley 1523/2012 | 3m |
| Oferta hídrica | caudal (m³/s) | IUA · IRH (IDEAM/ENA) | 4m |
| POMCA | caudal (m³/s) | Decreto 1640/2012 | 4m |
| PUEEA | consumo agua (m³) | Res. 2115/2007 | 3m |
| Recurso hídrico | OD · pH · DBO5 | Res. 2115/2007 (pH) / referencia técnica (OD, DBO5) | 3m |
| Rondas hídricas | caudal (m³/s) · vegetación | Decreto 2811/1974 | 3m |
| Sistemas de información | n_registros · cobertura | MIPG | – |
| Predios conservación | NDVI · cobertura (ha) | SMByC | – |
| Ordenamiento territorial | superficie (km²) | POT · POMCA | – |
| Dirección directiva | indicadores PAI/MIPG | MIPG | – |

### Bloque B — Transversales temáticas (3 líneas)

| Línea | Variable principal | Norma clave |
|---|---|---|
| Calidad del aire | PM2.5 · PM10 · O3 · NO2 (µg/m³) | Res. 2254/2017 |
| Cambio climático | temperatura · ONI · escenarios RCP | IPCC · IDEAM |
| Ruido ambiental | L_Aeq,T (dB(A)) | Res. 627/2006 |

### Bloque C — Capa técnica transversal (1 línea)

| Línea | Alcance |
|---|---|
| Geoespacial | Kriging · IDW · I de Moran · GWR · folium; transversal a todas las líneas |

</details>

---

## Normativa colombiana integrada

```python
from estadistica_ambiental.config import (
    NORMA_CO,           # Res. 2254/2017 — calidad del aire
    NORMA_OMS,          # Guías OMS 2021
    NORMA_AGUA_POTABLE, # Res. 2115/2007
    NORMA_VERTIMIENTOS, # Res. 631/2015
    NORMA_RUIDO,        # Res. 627/2006 — ruido ambiental
    IUA_THRESHOLDS,     # IDEAM / ENA
    ENSO_LAG_MESES,     # lag por línea temática
)
```

| Constante | Norma | Variables |
|---|---|---|
| `NORMA_CO` | Res. 2254/2017 | PM2.5 · PM10 · O3 · NO2 · SO2 · CO |
| `NORMA_OMS` | Guías OMS 2021 | PM2.5 · PM10 · O3 · NO2 |
| `NORMA_AGUA_POTABLE` | Res. 2115/2007 (OD/DBO5: referencia técnica sin norma vigente, ver ADR-020) | pH · OD · coliformes · DBO5 · conductividad |
| `NORMA_VERTIMIENTOS` | Res. 631/2015 | DBO5 · DQO · SST · pH · temperatura |
| `NORMA_RUIDO` | Res. 627/2006 | L_Aeq,T por sector y horario (dB(A)) |
| `IUA_THRESHOLDS` | IDEAM / ENA | Índice de Uso del Agua |
| `IRH_THRESHOLDS` | IDEAM / ENA | Índice de Retención Hídrica |
| `ICA_CATEGORIES` | IDEAM | Índice de Calidad del Agua |
| `ENSO_LAG_MESES` | Literatura colombiana | Lag hidrológico por línea |

---

## Reportes automáticos

Cada ejecución del ciclo genera en `data/output/`:

| Archivo | Contenido |
|---|---|
| `eda_<linea>.html` | Reporte EDA completo con ydata-profiling o plantilla propia |
| `descriptiva_<linea>.csv` | Estadísticos por variable y período |
| `inferencial_<linea>.json` | ADF · KPSS · Mann-Kendall · Pettitt · excedencias |
| `backtesting_<linea>.csv` | Métricas por fold y modelo |
| `ranking_modelos_<linea>.csv` | Score multi-criterio y ranking |
| `forecast_<linea>.html` | Pronóstico interactivo (Chart.js) real vs. predicho |
| `cumplimiento_<linea>.html` | Semáforo normativo · excedencias · período de retorno |

---

## Flujo por línea temática

```mermaid
flowchart TD
    A["Datos crudos"] -->|"io/loaders.py + io/validators.py"| B["Carga · validación de rangos físicos"]
    B -->|"eda/"| C["EDA automatizado → reporte HTML"]
    C -->|"preprocessing/"| D["Limpieza · imputación"]
    D -->|"descriptive/"| E["Descriptiva: tablas y gráficos"]
    E -->|"inference/"| F["Inferencial: ADF+KPSS · Mann-Kendall · exceedance_report"]
    F -->|"features/"| G["Feature engineering: lags · calendario · ENSO"]
    G -->|"predictive/ + optimization/"| H["Modelado con optimización bayesiana (Optuna TPE)"]
    H -->|"evaluation/"| I["Backtesting walk-forward · ranking multi-criterio"]
    I -->|"reporting/"| J["Reporte de pronóstico HTML · Reporte de cumplimiento normativo"]
    J --> K["docs/decisiones.md - registro ADR de decisiones metodológicas"]
```

---

## Compatibilidad y extras

| Extra | Dependencias | Cuándo instalarlo |
|---|---|---|
| `[ml]` | xgboost · lightgbm | Modelos ML en cualquier línea |
| `[prophet]` | prophet | Líneas con estacionalidades múltiples |
| `[spatial]` | geopandas · rasterio · pykrige · pysal · folium | Capa geoespacial |
| `[deep]` | torch | LSTM / GRU en series largas |
| `[bayes]` | pymc · arviz | Modelos jerárquicos (Fase 10, experimental) |
| `[profile]` | ydata-profiling · sweetviz · missingno | EDA enriquecido |
| `[fast]` | polars | Series horarias muy largas (>1M registros) |

---

## Trabajo futuro

La base de conocimiento queda documentalmente cerrada en v1.4.0 (todas las decisiones grandes con ADR,
cobertura de API completa en docs, tests verdes). Los siguientes frentes son **mejoras incrementales**,
priorizadas por valor pedagógico, no por features de producto.

### A. Pedagógico (alta prioridad)

- **Glosario de dominio** (`docs/glosario.md`) con términos técnicos colombianos (IUA, IRH, ICA, ENSO, ICA-aire, ENA, MRV, REDD+).
- **Índice "preguntas que el repo responde"**: ~30 preguntas frecuentes linkeando a notebook + función.
- **Casos de estudio reproducibles**: 3-5 mini-casos cortos por bloque temático.

### B. Cobertura (media prioridad)

- Auditoría cruzada `Fuentes.md` ↔ notebooks (gap analysis).
- Fichas operativas para los conectores ya implementados (limitaciones API, latencia, cobertura).
- **Ruido ambiental** (Res. 627/2006): implementado el cumplimiento normativo
  (`ruido_exceedance_report()`) y la ficha técnica; falta un conector de
  datos real y un notebook con mediciones reales una vez se identifique una
  fuente pública (ver `docs/fuentes/ruido_ambiental.md`).

### C. Calidad técnica (baja prioridad)

- Pre-commit hook con `mkdocs build --strict` para detectar warnings griffe antes del push.
- Subir cobertura a ≥ 85 % en `predictive.bayesian` y `spatial.*`.
- Type hints completos con `mypy --strict` en módulos heredados.

### D. Ecosistema satélites (depende del usuario, no del repo base)

- Validador de cumplimiento normativo como webapp (carga CSV → reporte HTML).
- Backtesting interactivo educativo (selección de modelo + serie + horizonte).

---

## Atribución

Construido sobre el trabajo de **Tomás Cárdenas López** ([@TomCardeLo](https://github.com/TomCardeLo)):

> **[boa-forecaster](https://github.com/TomCardeLo/boa-forecaster)**: pipeline multi-modelo con
> optimización bayesiana (Optuna TPE), `ModelSpec` protocol y ensemble ponderado. v2.4.

Los módulos `optimization/bayes_opt.py`, `evaluation/metrics.py`, `predictive/classical.py` y
`config.py` se heredan parcialmente y se adaptan al dominio ambiental colombiano (métricas NSE/KGE,
normas colombianas, rangos físicos ambientales, ENSO con lag por ecosistema).
Ver [`CITATION.cff`](CITATION.cff) para cita formal.

---

<div align="center">

**Dan Méndez** · Científico de Datos Ambiental · Colombia

*Modelado estadístico y machine learning aplicado a datos de monitoreo ambiental colombiano.*

[GitHub @DanMendezZz](https://github.com/DanMendezZz) · [LinkedIn](https://www.linkedin.com/in/daniel-m%C3%A9ndez-44161b1b3/)

*Construido para las entidades del Sistema Nacional Ambiental (SINA) de Colombia.*

</div>
