Saltar a contenido

Changelog

El changelog completo se mantiene en la raíz del repositorio. Esta página lo replica para que sea navegable desde el sitio.

Changelog

Formato basado en Keep a Changelog. Versiones: Semver.

Nota sobre versiones iniciales: Las versiones v0.1.0 → v1.0.0 corresponden a las Fases 0-8 del plan de desarrollo, construidas durante un sprint intensivo interno el 2026-04-22. No representan releases incrementales independientes sino una consolidación retrospectiva. A partir de v1.1.0 las fechas son incrementales reales.


[Unreleased]

[1.4.0] — 2026-09-22

Agregado

  • Línea temática 17 — Ruido Ambiental (issues #14/#33): config.NORMA_RUIDO con los estándares máximos permisibles de la Tabla 2 (Art. 17, Res. 627/2006) por sector y horario, y su entrada en NORMA_FUENTES; inference/intervals.py → ruido_exceedance_report() calcula L_Aeq,T por día/horario/sector (promedio energético, no aritmético) y compara contra el estándar del sector, con natural_noise=True como escape explícito del analista para la excepción de fuente natural (Art. 17, Parágrafo Segundo) -- nunca una detección algorítmica; el reporte expone n_mediciones por fila para que sea auditable cuándo una ventana horaria (14h diurna/10h nocturna, Art. 15) está cubierta por una sola lectura en vez de datos continuos; io/validators.py gana rangos físicos para ruido/nivel_ruido/laeq (0-140 dB(A)); notebook plantilla (notebooks/lineas_tematicas/bloque_b_transversales/ruido_ambiental.ipynb) y ficha técnica (docs/fuentes/ruido_ambiental.md) documentan el alcance real de esta línea (sin conector de datos ni benchmark propio todavía).

Corregido

  • inference/intervals.py — ruido_exceedance_report() usaba un .join() por índice para juntar cada medición con su ventana horaria; con timestamps repetidos en el índice eso produce un producto cartesiano que duplica valores antes de calcular L_Aeq, inflando artificialmente el resultado sin avisar (issue #33, encontrado en revisión antes de mergear -- nunca llegó a un release). Reemplazado por asignación posicional, que no depende de que el índice sea único.
  • spatial/autocorrelation.py — local_morans_i() ignoraba su parámetro weight_type y usaba siempre pesos Queen (issue #42). Cambia el resultado para cualquier llamada con weight_type="rook" o "kN", que hasta ahora recibía pesos Queen en silencio.
  • ci.yml (job test-spatial) — la lista manual de dependencias había divergido del extra [spatial] real de pyproject.toml (faltaban rioxarray, contextily, pyproj); ahora instala el extra publicado directamente (pip install -e ".[spatial]") en vez de mantener una lista paralela (issue #41). De paso se eliminó el step separado de rasterio: no aislaba nada -- rioxarray/contextily (y pysal vía tobler) ya lo traen como dependencia dura, así que entraba igual en el mismo batch de instalación sin que el step separado lo evitara.
  • ci.yml (job test-ml) — no subía su reporte de cobertura a Codecov pese a generarlo (--cov-report=xml), igual que pasaba con test-bayes/test-spatial antes del PR #40 -- las ramas de ml.py/registry.py/optimization/bayes_opt.py que solo corren con xgboost/lightgbm instalados eran invisibles para el % reportado. Agregado el mismo step de upload que ya tienen los otros 3 jobs (issue #41). test-deep no lo necesita: predictive/deep.py está en el omit de [tool.coverage.run], así que su reporte no mide nada distinto del de JOB 2.
  • pyproject.toml — extra [spatial] no declaraba branca, importado directo por spatial/viz.py (branca.colormap) y no solo transitivo de folium. Encontrado sincronizando la lista de CI con este extra.
  • io/connectors.py — load_openaq() aceptaba location_name/country sin usarlos realmente (countries_id quedaba hardcodeado a Colombia sin importar lo que se pasara). Ahora levanta ValueError explícito cuando se pasa location_name sin location_id (la API v3 de OpenAQ no tiene búsqueda de estaciones por nombre) o country != 'CO' sin location_id (la consulta sin location_id está cableada a Colombia) -- en vez de ignorarlos en silencio (issue #35). Cambia el resultado: esas llamadas, que antes devolvían datos de Colombia sin filtrar, ahora levantan error; pasar location_id sigue funcionando con cualquier country/location_name.
  • io/connectors.py — load_siata_aire() mapeaba lat/lon desde el CSV pero los descartaba antes del return final, contradiciendo su propio docstring. Ahora las incluye (issue #35). Cambia el resultado: el DataFrame devuelto tiene 2 columnas más.
  • predictive/bayesian.py — BayesianARIMA.predict()/_simulate_paths() y HierarchicalModel.predict() capaban n_samples al tamaño del posterior (n_draw = min(n_samples, n_total)), devolviendo silenciosamente menos filas que las pedidas en vez de re-muestrear con reemplazo (issue #38). Cambia el resultado: pedir n_samples mayor al posterior disponible ahora sí devuelve exactamente esa forma, vía bootstrap con reemplazo, en vez de una forma más chica sin avisar. Alcanza también al camino por defecto: predict() (media), predict_interval() y posterior_predictive_interval() usan 500 muestras internas, así que un modelo ajustado con chains * draws < 500 devuelve valores distintos aunque no se pase n_samples explícito.
  • predictive/bayesian.py — guard redundante theta is not None and eps_lags is not None en BayesianARIMA.fit() simplificado a theta is not None (eps_lags solo se calcula en el mismo bloque que crea theta, el segundo operando nunca aportaba nada). Sin cambio de comportamiento.
  • config.py — 6 valores normativos hardcodeados no coincidían con la norma colombiana vigente (auditoría artículo por artículo, ver ADR-020): NORMA_CO.pm10_annual, NORMA_CO.no2_annual, NORMA_CO.co_8h, NORMA_AGUA_POTABLE.nitratos_max, NORMA_VERTIMIENTOS.dqo_max, y los breakpoints de CO en ICA_BREAKPOINTS (antes la tabla AQI de la EPA en ppm mal etiquetada como mg/m³). Cambia el resultado de compliance_report() / exceedance_report() para esas variables y la clasificación ICA de CO — cualquier reporte generado con una versión anterior queda desactualizado para esos umbrales.
  • Nuevo diccionario NORMA_FUENTES documenta la procedencia legal (código, artículo, URL oficial, fecha de verificación, estado) de cada constante normativa, validado por tests/test_config_normas.py y revisado semanalmente por el job normativa-audit.
  • Extra [bayes] — pinneados pymc<6 y arviz<1 para evitar que una instalación fresca resuelva arviz 1.x (refactor mayor que renombra hdi_prob a ci_prob/ci_kind y cambia sus defaults), lo que rompía 4 tests de tests/test_bayesian.py en CI con TypeError: summary() got an unexpected keyword argument 'hdi_prob'.

[1.3.2] — 2026-05-07

Agregado

  • release.yml — JOB 6 publish-pypi activado con Trusted Publishing (OIDC) contra PyPI real. Pending publisher registrado en pypi.org/manage/account/publishing/ para estadistica-ambiental. A partir de esta versión, cada tag v*.*.* publica automáticamente en PyPI real (además de TestPyPI).

Corregido

  • src/estadistica_ambiental/__init__.py — __version__ desincronizado con pyproject.toml (estaba hardcodeado en "1.0.0" desde v1.0.0). Ahora refleja la versión real del paquete.

[1.3.1] — 2026-05-07

Corregido

  • release.yml — el job publish-testpypi ahora usa Trusted Publishing (OIDC) en lugar de un token API que nunca estuvo configurado. Requiere registrar el publisher una vez en test.pypi.org/manage/account/publishing/ (ver comentarios en el workflow).
  • Sin cambios funcionales en el paquete — wheel/sdist idénticos a v1.3.0. Esta versión existe únicamente para validar el flujo de publicación automatizada con la corrección del workflow.

[1.3.0] — 2026-05-07

Agregado

  • examples/ — 6 scripts runnables y autocontenidos (con fallback a datos sintéticos): 00_quickstart, 01_calidad_aire_pm25, 02_oferta_hidrica_caudal, 03_paramos_iuh, 04_cambio_climatico_co2, 05_eda_generico. Pensados para onboarding rápido sin abrir un notebook completo.
  • notebooks/showcases/calidad_aire_sisaire_real.ipynb — notebook end-to-end que consume load_sisaire_local() real (con fallback sintético) y recorre carga → validación → calidad → resampling → descriptiva → excedencias → Mann-Kendall → métricas → reporte HTML de cumplimiento.
  • Conectores genéricos adicionales en io/connectors.py:
  • load_datos_gov_co_dataset(dataset_id, where, select, limit, app_token) — cliente SODA para datos.gov.co/resource/<id>.json con paginación $offset/$limit y soporte de X-App-Token.
  • load_ideam_dhime_csv(path, parametro, fecha_col_candidates) — lector robusto para exports CSV de DHIME (auto-skip de líneas de metadata, detección de columnas fecha/valor, fallback utf-8/latin-1, sniff de delimitador).
  • Documentación navegable — sitio mkdocs-material + mkdocstrings con:
  • mkdocs.yml (theme Material en español, paleta light/dark, search multilingüe, snippets para inyectar CHANGELOG.md).
  • docs/index.md, docs/getting-started.md, docs/api.md (API reference auto-generada para 21 sub-módulos), docs/changelog.md.
  • Workflow .github/workflows/docs.yml para deploy automático a gh-pages.
  • Extra opcional [docs] en pyproject.toml.
  • Empaquetado para PyPI — python -m build produce sdist + wheel limpios (dist/estadistica_ambiental-1.3.0*). twine check PASSED. Comando de upload manual: python -m twine upload dist/estadistica_ambiental-1.3.0* (requiere token PyPI configurado en ~/.pypirc o variable de entorno TWINE_PASSWORD).
  • README: nuevas secciones "Snippets cortos por línea temática", "Notebook end-to-end con datos reales" y "Documentación navegable".

Tests

  • 8 tests nuevos: TestLoadDatosGovCoDataset (4) + TestLoadIdeamDhimeCsv (4) con mocks de requests.get y archivos sintéticos en tmp_path.
  • Suite total: 592 passed, 19 skipped, 4 xfailed (sin regresiones).

Notas

  • Esta versión consolida el patrón base ↔ satélite: el repo expone más conectores y onboarding pero mantiene su rol de base de conocimiento. Productos finales siguen viviendo en repos satélite que pinean a este tag.

[1.2.0] — 2026-05-07

Agregado

  • io.connectors.load_sisaire_local(anios, parametro, estaciones, path): lee descargas locales del portal SISAIRE/CAR (CAR_<año>.csv) sin duplicar archivos al repo. Normaliza encabezados (Estacion→estacion, Fecha inicial→fecha, PM2.5→pm25), fallback de encoding utf-8/latin-1, errores claros si la ruta no está configurada.
  • config.SISAIRE_LOCAL_DIR (Path | None) leído de la variable de entorno SISAIRE_LOCAL_DIR. El repo nunca asume una ruta fija.
  • NOMBRES_CORRECTOS extendido con FECHA INICIAL y FECHA FINAL.
  • README: nueva sección "Datos reales (uso opcional, sin duplicar)" y nueva sección "Consumir desde otro proyecto" (instalación pip+git, pinning a tag, patrón base ↔ repo satélite).

Tests

  • TestLoadSisaireLocal (8 nuevos): single year, multi-year concat, glob, filtro por estación, FileNotFoundError sin env, parámetro inexistente.
  • Smoke test contra datos reales: 219.108 registros / 31 estaciones / 2024.

Notas de arquitectura

  • Se ratifica que este repo es base de conocimiento + librería — productos finales (dashboards Streamlit, pipelines productivos, reportes ejecutivos) van en repos satélite que importan estadistica_ambiental como dependencia.

[1.0.0] — 2026-04-22 (primer release público — consolidación Fases 0-8)

Agregado

  • API pública completa: from estadistica_ambiental import * expone 20 símbolos.
  • predictive/deep.py: LSTMModel y GRUModel con ventana deslizante y graceful ImportError.
  • predictive/spatial_models.py: KrigingInterpolator y SpatioTemporalKriging.
  • predictive/bayesian.py: stub BayesianARIMA y HierarchicalModel (Fase 10).
  • reporting/stats_report.py: reporte HTML con descriptiva + ADF/KPSS + Mann-Kendall.
  • LSTM y GRU registrados automáticamente en predictive/registry.py si PyTorch está disponible.
  • docs/fuentes/calidad_aire.md: ficha completa extraída del NotebookLM (2026-04-22).
  • notebooks/00_plantilla_ciclo_completo.ipynb: plantilla maestra reusable.
  • 15 notebooks adicionales para Bloques A, B, C (líneas temáticas restantes).
  • CHANGELOG.md: este archivo.

Corregido

  • evaluation/comparison.py: normalización invertida para métricas higher-is-better (R², NSE, KGE).

Tests

  • 199 tests en verde + 1 skip (geopandas opcional).

[0.8.0] — 2026-04-22

Agregado

  • Fase 7 — Capa espacial completa: spatial/io.py, projections.py, interpolation.py (IDW + Kriging), autocorrelation.py (Moran, LISA), viz.py.
  • config.py: normas colombianas y OMS para calidad del aire (Res. 2254/2017).
  • features/exogenous.py: alineación de exógenas y features meteorológicos.
  • features/climate.py: ONI/ENSO desde NOAA, clasificación niño/niña/neutro, dummies.
  • evaluation/comparison.py: ranking multi-criterio y select_best().
  • reporting/forecast_report.py: HTML con Chart.js real vs. pronósticos.
  • docs/metodologia.md y docs/modelos.md.
  • Tags v0.1.0, v0.5.0, v0.8.0, v1.0.0 en GitHub.

[0.5.0] — 2026-04-22

Agregado

  • Fase 5-6 — Catálogo de modelos y evaluación:
  • predictive/ml.py: XGBoostModel, RandomForestModel, LightGBMModel.
  • predictive/prophet_model.py: Prophet con exógenas.
  • predictive/registry.py: get_model(), list_models(), register().
  • evaluation/backtesting.py: walk-forward expanding/sliding.
  • features/lags.py, features/calendar.py con codificación cíclica.

[0.1.0] — 2026-04-22

Agregado

  • Fase 0 — Estructura completa del repositorio.
  • Fase 1 — io/loaders.py, io/validators.py, eda/variables.py, eda/quality.py, eda/profiling.py, eda/viz.py.
  • Fase 2 — descriptive/univariate.py, bivariate.py, temporal.py; inference/distributions.py, hypothesis.py, stationarity.py, trend.py, intervals.py.
  • Fase 3 — preprocessing/imputation.py, outliers.py, resampling.py; predictive/base.py, classical.py (ARIMA/SARIMA/SARIMAX/ETS); optimization/bayes_opt.py; evaluation/metrics.py.
  • Fase 4 — Notebook MVP calidad del aire PM2.5 RMCAB Bogotá.
  • 16 notebooks (1 MVP + 15 plantillas por línea temática).
  • 4 ADRs en docs/decisiones.md.
  • Atribución a boa-sarima-forecaster (TomCardeLo).