Skip to main content

🌎 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 Descargas PyPI Release Python License: MIT

pandas scikit-learn statsmodels Optuna XGBoost LightGBM GeoPandas mkdocs

CI Release workflow Docs Pages Scheduled checks codecov

pip install estadistica-ambiental

📚 Documentación: https://danmendezzz.github.io/Estadistica_Ambiental/ · 📓 Notebooks sin instalar (Pyodide): JupyterLite live

Qué hay · Metodología · Resultados · Estructura · Instalación · Quick Start · Modelos · 17 Líneas temáticas · Normativa · Roadmap

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.


📑 Tabla de contenido (click para expandir)
  1. ¿Qué encontrás en este repo?
  2. ¿Para quién es este repo?
  3. Motivación
  4. Metodología
  5. Resultados y validación
  6. Estructura del proyecto
  7. Arquitectura base ↔ satélite
  8. Instalación
  9. Consumir desde otro proyecto (este repo es base de conocimiento)
  10. Probá sin instalar nada (JupyterLite)
  11. Datos reales (uso opcional, sin duplicar)
  12. Quick Start
  13. Catálogo de modelos
  14. 17 Líneas temáticas
  15. Normativa colombiana integrada
  16. Reportes automáticos
  17. Flujo por línea temática
  18. Compatibilidad y extras
  19. Trabajo futuro
  20. Atribución

¿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) 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/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) 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 → 17 Líneas temáticas → notebooks en notebooks/lineas_tematicas/
Estudiante de estadística ambiental JupyterLite live (sin instalar nada) → Resultados y validación → docs/decisiones.md
Docente o investigador docs/decisiones.md (20 ADRs) → docs/fuentes/ (fichas de dominio) → Catálogo de modelos
Desarrollador de un satélite Consumir desde otro proyecto → patrón documentado en ADR-018

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).

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:

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:

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):

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):

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

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

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/ (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.

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
eda Perfilado automático, calidad de datos (faltantes, duplicados, congelamiento de sensor) run_eda() docs/metodologia.md
preprocessing Imputación (lineal · rolling · KNN · MICE) y outliers opt-in (ADR-002) impute() ADR-002
descriptive Estadística univariada, bivariada y temporal (STL, ACF/PACF) univariate_summary() docs/metodologia.md
inference ADF+KPSS obligatorios, tendencia (Mann-Kendall), excedencias normativas exceedance_report() ADR-004 · ADR-008
spatial Kriging, GWR, I de Moran, autocorrelación espacial moran_i() docs/modelos.md
features Lags, encoding cíclico, ENSO/ONI con lag por línea temática enso_lagged() ADR-007
predictive Catálogo uniforme de 10 modelos (ARIMA a LSTM) get_model() docs/modelos.md
optimization Optimización bayesiana de hiperparámetros con Optuna TPE optimize() docs/metodologia.md
evaluation Backtesting walk-forward con gap=, ranking multi-criterio, métricas NSE/KGE walk_forward() · rank_models() docs/metodologia.md
reporting Reportes HTML autocontenidos (cumplimiento, pronóstico, descriptiva) compliance_report() ADR-008
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"]
🗂️ Árbol completo del repositorio (click para expandir)
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

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).

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)

pip install estadistica-ambiental

Con extras opcionales:

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:

import estadistica_ambiental as ea
print(ea.__version__)

Para desarrollar el repo (clone)

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

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 arriba).

Instalación desde PyPI (preferida)

# Ú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)

# 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:

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

Imports típicos en un repo satélite

# 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. Los breaking changes en API pública se marcan con bump MAJOR y se documentan en 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

# Windows (PowerShell, persistente)
setx SISAIRE_LOCAL_DIR "D:\ruta\a\Datos SISAIRE\00_Datos_Originales"
# Linux/macOS (en .bashrc / .zshrc)
export SISAIRE_LOCAL_DIR="/ruta/a/Datos SISAIRE/00_Datos_Originales"

2. Cargar datos sin copiarlos al repo

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

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

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

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):

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)

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


17 Líneas temáticas

📋 Ver las 17 líneas por bloque (click para expandir)

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

Normativa colombiana integrada

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

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):

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 para cita formal.


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

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

GitHub @DanMendezZz · LinkedIn

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

Metadata

Release files for estadistica-ambiental 1.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for estadistica-ambiental 1.4.0
File Size Uploaded
estadistica_ambiental-1.4.0.tar.gz 753.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for estadistica-ambiental 1.4.0
File Interpreter ABI Platform
estadistica_ambiental-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 909.5 kB

Release files / estadistica_ambiental-1.4.0.tar.gz

Download URL estadistica_ambiental-1.4.0.tar.gz
Size 753.8 kB
Tags Source
SHA-256 checksum
How to use checksums
191870239ec841686318fea37d4a9940bd8f0baa6f33f7297b47f475eca229f0
BLAKE2b-256 checksum
How to use checksums
e9bc6342c7eb263cba58862daa4368bdf372b3a6e85dc9b547e4fe12758b3a9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / estadistica_ambiental-1.4.0-py3-none-any.whl

Download URL estadistica_ambiental-1.4.0-py3-none-any.whl
Size 155.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
75c4fd9c24b90a6373ac5bc67f171a894109b128cca8a18b367f9b63d3613e98
BLAKE2b-256 checksum
How to use checksums
3ca7ffd4b328ce3bb21493eb84e93ad8ee395412c98288afb0fa2bfd212d53c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.4.0 This release

2 release files

1.3.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page