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_RUIDOcon los estándares máximos permisibles de la Tabla 2 (Art. 17, Res. 627/2006) por sector y horario, y su entrada enNORMA_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, connatural_noise=Truecomo 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 exponen_medicionespor 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.pygana rangos físicos pararuido/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ámetroweight_typey usaba siempre pesos Queen (issue #42). Cambia el resultado para cualquier llamada conweight_type="rook"o"kN", que hasta ahora recibía pesos Queen en silencio.ci.yml(jobtest-spatial) — la lista manual de dependencias había divergido del extra[spatial]real depyproject.toml(faltabanrioxarray,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 derasterio: no aislaba nada --rioxarray/contextily(ypysalvíatobler) 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(jobtest-ml) — no subía su reporte de cobertura a Codecov pese a generarlo (--cov-report=xml), igual que pasaba contest-bayes/test-spatialantes del PR #40 -- las ramas deml.py/registry.py/optimization/bayes_opt.pyque 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-deepno lo necesita:predictive/deep.pyestá en elomitde[tool.coverage.run], así que su reporte no mide nada distinto del de JOB 2.pyproject.toml— extra[spatial]no declarababranca, importado directo porspatial/viz.py(branca.colormap) y no solo transitivo defolium. Encontrado sincronizando la lista de CI con este extra.io/connectors.py—load_openaq()aceptabalocation_name/countrysin usarlos realmente (countries_idquedaba hardcodeado a Colombia sin importar lo que se pasara). Ahora levantaValueErrorexplícito cuando se pasalocation_namesinlocation_id(la API v3 de OpenAQ no tiene búsqueda de estaciones por nombre) ocountry != 'CO'sinlocation_id(la consulta sinlocation_idestá 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; pasarlocation_idsigue funcionando con cualquiercountry/location_name.io/connectors.py—load_siata_aire()mapeabalat/londesde el CSV pero los descartaba antes delreturnfinal, 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()yHierarchicalModel.predict()capabann_samplesal 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: pedirn_samplesmayor 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()yposterior_predictive_interval()usan 500 muestras internas, así que un modelo ajustado conchains * draws < 500devuelve valores distintos aunque no se pasen_samplesexplícito.predictive/bayesian.py— guard redundantetheta is not None and eps_lags is not NoneenBayesianARIMA.fit()simplificado atheta is not None(eps_lagssolo se calcula en el mismo bloque que creatheta, 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 enICA_BREAKPOINTS(antes la tabla AQI de la EPA en ppm mal etiquetada como mg/m³). Cambia el resultado decompliance_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_FUENTESdocumenta la procedencia legal (código, artículo, URL oficial, fecha de verificación, estado) de cada constante normativa, validado portests/test_config_normas.pyy revisado semanalmente por el jobnormativa-audit. - Extra
[bayes]— pinneadospymc<6yarviz<1para evitar que una instalación fresca resuelva arviz 1.x (refactor mayor que renombrahdi_probaci_prob/ci_kindy cambia sus defaults), lo que rompía 4 tests detests/test_bayesian.pyen CI conTypeError: summary() got an unexpected keyword argument 'hdi_prob'.
[1.3.2] — 2026-05-07¶
Agregado¶
release.yml— JOB 6publish-pypiactivado con Trusted Publishing (OIDC) contra PyPI real. Pending publisher registrado enpypi.org/manage/account/publishing/paraestadistica-ambiental. A partir de esta versión, cada tagv*.*.*publica automáticamente en PyPI real (además de TestPyPI).
Corregido¶
src/estadistica_ambiental/__init__.py—__version__desincronizado conpyproject.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 jobpublish-testpypiahora usa Trusted Publishing (OIDC) en lugar de un token API que nunca estuvo configurado. Requiere registrar el publisher una vez entest.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 consumeload_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 paradatos.gov.co/resource/<id>.jsoncon paginación$offset/$limity soporte deX-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+mkdocstringscon: mkdocs.yml(theme Material en español, paleta light/dark, search multilingüe, snippets para inyectarCHANGELOG.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.ymlpara deploy automático agh-pages. - Extra opcional
[docs]enpyproject.toml. - Empaquetado para PyPI —
python -m buildproduce sdist + wheel limpios (dist/estadistica_ambiental-1.3.0*).twine checkPASSED. Comando de upload manual:python -m twine upload dist/estadistica_ambiental-1.3.0*(requiere token PyPI configurado en~/.pypirco variable de entornoTWINE_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 derequests.gety archivos sintéticos entmp_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 entornoSISAIRE_LOCAL_DIR. El repo nunca asume una ruta fija.NOMBRES_CORRECTOSextendido conFECHA INICIALyFECHA 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_ambientalcomo 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.pysi 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 yselect_best().reporting/forecast_report.py: HTML con Chart.js real vs. pronósticos.docs/metodologia.mdydocs/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.pycon 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).