urg-forecast-core 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- urg_forecast_core-0.1.0/.gitignore +40 -0
- urg_forecast_core-0.1.0/CHANGELOG.md +48 -0
- urg_forecast_core-0.1.0/CITATION.cff +32 -0
- urg_forecast_core-0.1.0/CONTRIBUTING.md +72 -0
- urg_forecast_core-0.1.0/LICENSE +21 -0
- urg_forecast_core-0.1.0/PKG-INFO +287 -0
- urg_forecast_core-0.1.0/README.es.md +209 -0
- urg_forecast_core-0.1.0/README.md +212 -0
- urg_forecast_core-0.1.0/docs/decisions.md +185 -0
- urg_forecast_core-0.1.0/docs/roadmap.md +52 -0
- urg_forecast_core-0.1.0/pyproject.toml +123 -0
- urg_forecast_core-0.1.0/scripts/demo_deis.py +12 -0
- urg_forecast_core-0.1.0/scripts/demo_synthetic.py +12 -0
- urg_forecast_core-0.1.0/scripts/generate_fixture.py +231 -0
- urg_forecast_core-0.1.0/scripts/harness_smoke.py +86 -0
- urg_forecast_core-0.1.0/src/urgencias_core/__init__.py +1 -0
- urg_forecast_core-0.1.0/src/urgencias_core/_logging.py +32 -0
- urg_forecast_core-0.1.0/src/urgencias_core/_optional.py +26 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/_fixtures/deis_demo_snapshot.README.md +59 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/_fixtures/deis_demo_snapshot.parquet +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/_fixtures/synthetic_ed_visits_demo.parquet +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/deis.py +477 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/fixtures.py +32 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/loader.py +110 -0
- urg_forecast_core-0.1.0/src/urgencias_core/data/timeseries.py +150 -0
- urg_forecast_core-0.1.0/src/urgencias_core/demos/__init__.py +9 -0
- urg_forecast_core-0.1.0/src/urgencias_core/demos/deis.py +369 -0
- urg_forecast_core-0.1.0/src/urgencias_core/demos/server.py +43 -0
- urg_forecast_core-0.1.0/src/urgencias_core/demos/synthetic.py +160 -0
- urg_forecast_core-0.1.0/src/urgencias_core/eval/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/eval/baselines.py +239 -0
- urg_forecast_core-0.1.0/src/urgencias_core/eval/harness.py +171 -0
- urg_forecast_core-0.1.0/src/urgencias_core/features/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/features/calendar.py +169 -0
- urg_forecast_core-0.1.0/src/urgencias_core/features/weather.py +145 -0
- urg_forecast_core-0.1.0/src/urgencias_core/models/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/models/lgb_quantile.py +130 -0
- urg_forecast_core-0.1.0/src/urgencias_core/models/protocol.py +97 -0
- urg_forecast_core-0.1.0/src/urgencias_core/py.typed +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/app.py +231 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/charts.py +99 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/config.py +101 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/static/style.css +115 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/templates/base.html +26 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/templates/baseline.html +22 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/templates/forecast.html +19 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/templates/index.html +35 -0
- urg_forecast_core-0.1.0/src/urgencias_core/server/templates/simulation.html +36 -0
- urg_forecast_core-0.1.0/src/urgencias_core/simulation/__init__.py +0 -0
- urg_forecast_core-0.1.0/src/urgencias_core/simulation/engine.py +156 -0
- urg_forecast_core-0.1.0/src/urgencias_core/simulation/los_empirical.py +111 -0
- urg_forecast_core-0.1.0/tests/__init__.py +0 -0
- urg_forecast_core-0.1.0/tests/conftest.py +33 -0
- urg_forecast_core-0.1.0/tests/fixtures/synthetic_ed_visits.parquet +0 -0
- urg_forecast_core-0.1.0/tests/test_baselines.py +64 -0
- urg_forecast_core-0.1.0/tests/test_calendar.py +91 -0
- urg_forecast_core-0.1.0/tests/test_deis.py +140 -0
- urg_forecast_core-0.1.0/tests/test_demos.py +57 -0
- urg_forecast_core-0.1.0/tests/test_harness.py +91 -0
- urg_forecast_core-0.1.0/tests/test_lgb_quantile.py +41 -0
- urg_forecast_core-0.1.0/tests/test_loader.py +74 -0
- urg_forecast_core-0.1.0/tests/test_los_empirical.py +67 -0
- urg_forecast_core-0.1.0/tests/test_packaging.py +47 -0
- urg_forecast_core-0.1.0/tests/test_protocol.py +38 -0
- urg_forecast_core-0.1.0/tests/test_server.py +72 -0
- urg_forecast_core-0.1.0/tests/test_simulation_engine.py +91 -0
- urg_forecast_core-0.1.0/tests/test_smoke.py +7 -0
- urg_forecast_core-0.1.0/tests/test_timeseries.py +72 -0
- urg_forecast_core-0.1.0/tests/test_weather.py +76 -0
- urg_forecast_core-0.1.0/urg-forecast-core.toml.example +25 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.mypy_cache/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Build
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
|
|
15
|
+
# Data and models (reference repo: no real data committed)
|
|
16
|
+
/data/raw/
|
|
17
|
+
/data/processed/
|
|
18
|
+
/data/external/
|
|
19
|
+
/models/
|
|
20
|
+
/outputs/
|
|
21
|
+
|
|
22
|
+
# Parquet files by default are not committed, except the synthetic fixtures
|
|
23
|
+
# (the test fixture and the compact demo fixture shipped inside the package).
|
|
24
|
+
*.parquet
|
|
25
|
+
!tests/fixtures/*.parquet
|
|
26
|
+
!src/urgencias_core/data/_fixtures/*.parquet
|
|
27
|
+
|
|
28
|
+
# Editor / OS
|
|
29
|
+
.DS_Store
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
|
|
34
|
+
# Agent/harness scratch (git worktrees created by tooling)
|
|
35
|
+
.claude/worktrees/
|
|
36
|
+
|
|
37
|
+
# Env
|
|
38
|
+
.env
|
|
39
|
+
.env.*
|
|
40
|
+
!.env.example
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) (API may
|
|
6
|
+
change between minor versions while on 0.x).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-07-20
|
|
11
|
+
|
|
12
|
+
First public release — the reference pipeline packaged for `pip install`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Core library: visit-level → hourly occupancy time series (event-cumsum),
|
|
17
|
+
Chilean calendar features, empirical LOS sampler, Monte Carlo occupancy
|
|
18
|
+
simulation, `Forecaster` protocol, seasonal-naive / statsforecast / LightGBM
|
|
19
|
+
quantile forecasters, and an evaluation harness.
|
|
20
|
+
- DEIS MINSAL *Atenciones de Urgencia* fetcher with an offline snapshot
|
|
21
|
+
fallback, bundled inside the package.
|
|
22
|
+
- Minimal FastAPI reference server with server-rendered charts.
|
|
23
|
+
- Console entry points: `urgencias-demo-synthetic`, `urgencias-demo-deis`,
|
|
24
|
+
`urgencias-server`.
|
|
25
|
+
- Optional-dependency extras: `models`, `viz`, `server`, `fetch`, `all`. The
|
|
26
|
+
core install ships only pandas/numpy/pyarrow/holidays/pydantic; gated modules
|
|
27
|
+
raise an actionable error naming the extra to install.
|
|
28
|
+
- `py.typed` marker, PyPI classifiers/keywords/URLs, and packaged demo
|
|
29
|
+
datasets so the server and demos run out of the box from an installed wheel.
|
|
30
|
+
- CI: lint gate, Python 3.11/3.12 test matrix, build + `twine check`, and a
|
|
31
|
+
core-only install job.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Default server fixture resolved a repo-relative path (`parents[3]`) that
|
|
36
|
+
escaped `site-packages` in an installed wheel; it now resolves the bundled
|
|
37
|
+
fixture via `importlib.resources`.
|
|
38
|
+
- DEIS weekly aggregation (`demos.deis._to_weekly`) now trims partial weeks at
|
|
39
|
+
both series edges, not only a fully-empty trailing week. A most-recent week
|
|
40
|
+
with a missing day (near-real-time reporting lag) was kept and appeared as a
|
|
41
|
+
spurious end-of-series drop that contaminated the backtest.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Unified formatting on `ruff format` (dropped black).
|
|
46
|
+
|
|
47
|
+
[Unreleased]: https://github.com/nicoveraz/urg-forecast-core/compare/v0.1.0...HEAD
|
|
48
|
+
[0.1.0]: https://github.com/nicoveraz/urg-forecast-core/releases/tag/v0.1.0
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it using these metadata."
|
|
3
|
+
title: "urg-forecast-core"
|
|
4
|
+
abstract: >-
|
|
5
|
+
Open reference pipeline for Chilean emergency department analytics,
|
|
6
|
+
probabilistic forecasting, and Monte Carlo occupancy simulation: a
|
|
7
|
+
visits-to-hourly-occupancy transform, Chilean calendar features, a uniform
|
|
8
|
+
quantile Forecaster interface (seasonal-naive, statsforecast, LightGBM), an
|
|
9
|
+
evaluation harness, an empirical-LOS Monte Carlo engine, a DEIS MINSAL
|
|
10
|
+
open-data client, and a minimal reference dashboard.
|
|
11
|
+
type: software
|
|
12
|
+
authors:
|
|
13
|
+
- given-names: "Nicolás"
|
|
14
|
+
family-names: "Vera Zúñiga"
|
|
15
|
+
orcid: "https://orcid.org/0009-0007-9249-3736"
|
|
16
|
+
affiliation: "Eunosia, Frutillar, Chile"
|
|
17
|
+
version: "0.1.0"
|
|
18
|
+
date-released: "2026-07-20"
|
|
19
|
+
license: MIT
|
|
20
|
+
repository-code: "https://github.com/nicoveraz/urg-forecast-core"
|
|
21
|
+
url: "https://pypi.org/project/urg-forecast-core/"
|
|
22
|
+
keywords:
|
|
23
|
+
- emergency department
|
|
24
|
+
- emergency medicine
|
|
25
|
+
- forecasting
|
|
26
|
+
- time series
|
|
27
|
+
- Monte Carlo simulation
|
|
28
|
+
- capacity planning
|
|
29
|
+
- Chile
|
|
30
|
+
- DEIS
|
|
31
|
+
# After the first Zenodo release, add the concept DOI here, e.g.:
|
|
32
|
+
# doi: "10.5281/zenodo.XXXXXXX"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
`urg-forecast-core` is an open foundation maintained on a best-effort basis. Fork
|
|
4
|
+
freely, adapt it to your hospital, ship it inside your own product. Pull requests
|
|
5
|
+
and issues are welcome; while on 0.x the API may change between minor versions.
|
|
6
|
+
If you need commercial support or bespoke work on top of this foundation, contact
|
|
7
|
+
the author.
|
|
8
|
+
|
|
9
|
+
## Development
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uv sync --all-extras --dev # full toolchain + all optional deps
|
|
13
|
+
uv run pytest -q # tests
|
|
14
|
+
uv run ruff check . # lint
|
|
15
|
+
uv run ruff format . # format (ruff is the single formatter)
|
|
16
|
+
pre-commit install # optional: run lint/format on commit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The package uses a src layout. Heavy dependencies live behind extras
|
|
20
|
+
(`models`, `viz`, `server`, `fetch`, `all`); modules that need them guard the
|
|
21
|
+
import and raise an actionable error. Keep that pattern when adding code that
|
|
22
|
+
depends on an optional library.
|
|
23
|
+
|
|
24
|
+
## Cutting a release
|
|
25
|
+
|
|
26
|
+
Releases publish to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
|
|
27
|
+
(OIDC) from `.github/workflows/publish.yml` — no API tokens as secrets.
|
|
28
|
+
|
|
29
|
+
One-time setup: on PyPI, add this repository and the `pypi` environment as a
|
|
30
|
+
trusted publisher for the `urg-forecast-core` project. Optionally validate metadata
|
|
31
|
+
first by publishing a pre-release (e.g. `0.1.0rc1`) to TestPyPI.
|
|
32
|
+
|
|
33
|
+
Per release:
|
|
34
|
+
|
|
35
|
+
1. Bump `version` in `pyproject.toml` (semver).
|
|
36
|
+
2. Move the `## [Unreleased]` notes in `CHANGELOG.md` under a new
|
|
37
|
+
`## [X.Y.Z] - YYYY-MM-DD` heading and update the compare links.
|
|
38
|
+
3. Commit, then tag and push:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git tag vX.Y.Z
|
|
42
|
+
git push origin main --tags
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The `publish` workflow then runs tests, verifies the tag matches the package
|
|
46
|
+
version, builds, publishes to PyPI, and creates a GitHub Release with the
|
|
47
|
+
changelog section as its notes.
|
|
48
|
+
|
|
49
|
+
## Archiving on Zenodo (citable DOI)
|
|
50
|
+
|
|
51
|
+
Releases are archived on [Zenodo](https://zenodo.org/) for a citable DOI.
|
|
52
|
+
Metadata for the archive comes from `.zenodo.json`; `CITATION.cff` provides the
|
|
53
|
+
citation shown on GitHub.
|
|
54
|
+
|
|
55
|
+
One-time setup:
|
|
56
|
+
|
|
57
|
+
1. Sign in to Zenodo with GitHub and, under *GitHub* settings, flip the switch
|
|
58
|
+
**on** for the `urg-forecast-core` repository.
|
|
59
|
+
2. Cut a release (the tag flow above creates a GitHub Release). Zenodo detects
|
|
60
|
+
the published GitHub Release, archives the source, and mints two DOIs: a
|
|
61
|
+
**concept DOI** (always resolves to the latest version) and a
|
|
62
|
+
**version DOI** (this specific release).
|
|
63
|
+
|
|
64
|
+
After the first release:
|
|
65
|
+
|
|
66
|
+
3. Add the concept DOI to `CITATION.cff` (`doi:` field), the README "Citing"
|
|
67
|
+
section (DOI badge), and `paper/paper.md` if submitting to JOSS.
|
|
68
|
+
|
|
69
|
+
For submitting the software paper (JOSS), the archived Zenodo DOI is required at
|
|
70
|
+
submission; draft papers are under `paper/`. Author ORCID and affiliation are
|
|
71
|
+
set in `paper/paper.md`, `CITATION.cff`, and `.zenodo.json`; keep them in sync
|
|
72
|
+
if authorship changes.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicolás Vera Z.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: urg-forecast-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reference code for Chilean ED analytics, simulation, and forecasting. Open foundation of Eunosia.
|
|
5
|
+
Project-URL: Homepage, https://github.com/nicoveraz/urg-forecast-core
|
|
6
|
+
Project-URL: Repository, https://github.com/nicoveraz/urg-forecast-core
|
|
7
|
+
Project-URL: Issues, https://github.com/nicoveraz/urg-forecast-core/issues
|
|
8
|
+
Author: Nicolás Vera Z.
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Nicolás Vera Z.
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: chile,deis,emergency-department,forecasting,healthcare,monte-carlo,simulation,time-series
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
42
|
+
Classifier: Typing :: Typed
|
|
43
|
+
Requires-Python: <3.13,>=3.11
|
|
44
|
+
Requires-Dist: holidays>=0.50
|
|
45
|
+
Requires-Dist: numpy>=1.26
|
|
46
|
+
Requires-Dist: pandas>=2.2
|
|
47
|
+
Requires-Dist: pyarrow>=16.0
|
|
48
|
+
Requires-Dist: pydantic>=2.6
|
|
49
|
+
Provides-Extra: all
|
|
50
|
+
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
51
|
+
Requires-Dist: httpx>=0.27; extra == 'all'
|
|
52
|
+
Requires-Dist: jinja2>=3.1; extra == 'all'
|
|
53
|
+
Requires-Dist: lightgbm>=4.3; extra == 'all'
|
|
54
|
+
Requires-Dist: matplotlib>=3.8; extra == 'all'
|
|
55
|
+
Requires-Dist: scikit-learn>=1.4; extra == 'all'
|
|
56
|
+
Requires-Dist: statsforecast>=1.7; extra == 'all'
|
|
57
|
+
Requires-Dist: tabulate>=0.9; extra == 'all'
|
|
58
|
+
Requires-Dist: uvicorn>=0.29; extra == 'all'
|
|
59
|
+
Provides-Extra: fetch
|
|
60
|
+
Requires-Dist: httpx>=0.27; extra == 'fetch'
|
|
61
|
+
Provides-Extra: models
|
|
62
|
+
Requires-Dist: lightgbm>=4.3; extra == 'models'
|
|
63
|
+
Requires-Dist: scikit-learn>=1.4; extra == 'models'
|
|
64
|
+
Requires-Dist: statsforecast>=1.7; extra == 'models'
|
|
65
|
+
Provides-Extra: server
|
|
66
|
+
Requires-Dist: fastapi>=0.110; extra == 'server'
|
|
67
|
+
Requires-Dist: jinja2>=3.1; extra == 'server'
|
|
68
|
+
Requires-Dist: matplotlib>=3.8; extra == 'server'
|
|
69
|
+
Requires-Dist: tabulate>=0.9; extra == 'server'
|
|
70
|
+
Requires-Dist: uvicorn>=0.29; extra == 'server'
|
|
71
|
+
Provides-Extra: viz
|
|
72
|
+
Requires-Dist: matplotlib>=3.8; extra == 'viz'
|
|
73
|
+
Requires-Dist: tabulate>=0.9; extra == 'viz'
|
|
74
|
+
Description-Content-Type: text/markdown
|
|
75
|
+
|
|
76
|
+
# urg-forecast-core
|
|
77
|
+
|
|
78
|
+
[](https://github.com/nicoveraz/urg-forecast-core/actions/workflows/ci.yml)
|
|
79
|
+
[](https://pypi.org/project/urg-forecast-core/)
|
|
80
|
+
[](https://pypi.org/project/urg-forecast-core/)
|
|
81
|
+
[](https://github.com/nicoveraz/urg-forecast-core/blob/main/LICENSE)
|
|
82
|
+
|
|
83
|
+
Reference code for Chilean emergency department (ED) analytics, simulation, and
|
|
84
|
+
forecasting. Open foundation of **Eunosia**.
|
|
85
|
+
|
|
86
|
+
*Leer en [español](https://github.com/nicoveraz/urg-forecast-core/blob/main/README.es.md).*
|
|
87
|
+
|
|
88
|
+
It turns visit-level ED data into hourly occupancy series, adds Chilean calendar
|
|
89
|
+
features, forecasts arrivals/occupancy with quantile bands, and runs a Monte
|
|
90
|
+
Carlo census simulator — plus a reader for the public DEIS MINSAL dataset and a
|
|
91
|
+
minimal web dashboard.
|
|
92
|
+
|
|
93
|
+
## Install
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install urg-forecast-core # core library (data, timeseries, features, simulation)
|
|
97
|
+
pip install "urg-forecast-core[all]" # everything: models, viz, server, and data fetchers
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The core install is intentionally light (pandas/numpy/pyarrow/holidays/pydantic).
|
|
101
|
+
Heavier capabilities live behind extras — a module that needs one raises a clear
|
|
102
|
+
"install the extra" error:
|
|
103
|
+
|
|
104
|
+
| Extra | Pulls in | Enables |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `models` | lightgbm, statsforecast, scikit-learn | LightGBM/statsforecast quantile forecasters |
|
|
107
|
+
| `viz` | matplotlib, tabulate | charts and markdown tables (demos, server) |
|
|
108
|
+
| `server` | fastapi, uvicorn, jinja2 (+ `viz`) | the reference dashboard server |
|
|
109
|
+
| `fetch` | httpx | DEIS MINSAL and Open-Meteo network clients |
|
|
110
|
+
| `all` | all of the above | the demos and the full test suite |
|
|
111
|
+
|
|
112
|
+
## Quickstart
|
|
113
|
+
|
|
114
|
+
After `pip install "urg-forecast-core[all]"`, three console commands are available.
|
|
115
|
+
They run on datasets bundled with the package and write to `./outputs`:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
urgencias-demo-synthetic # full pipeline incl. simulation → 3 PNGs
|
|
119
|
+
urgencias-demo-deis --offline # forecasting on real DEIS hospital data
|
|
120
|
+
urgencias-server # reference dashboard at http://127.0.0.1:8000
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
From a source checkout with [uv](https://docs.astral.sh/uv/):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git clone https://github.com/nicoveraz/urg-forecast-core
|
|
127
|
+
cd urg-forecast-core
|
|
128
|
+
uv sync --all-extras
|
|
129
|
+
|
|
130
|
+
uv run urgencias-demo-synthetic
|
|
131
|
+
uv run urgencias-demo-deis --offline
|
|
132
|
+
uv run urgencias-server
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The synthetic demo runs in seconds on a compact one-year synthetic fixture
|
|
136
|
+
(~13,000 visits) bundled with the package. The DEIS demo fetches real public
|
|
137
|
+
data (or falls back to the bundled offline snapshot) and writes backtesting
|
|
138
|
+
tables plus 6-month-ahead forecasts.
|
|
139
|
+
|
|
140
|
+
## What the pipeline produces
|
|
141
|
+
|
|
142
|
+
The figures below are the direct output of running the two demos against the
|
|
143
|
+
bundled data.
|
|
144
|
+
|
|
145
|
+
### 1. From visits to an hourly occupancy series
|
|
146
|
+
|
|
147
|
+
`urgencias_core.data.timeseries` converts the visit-level parquet (one row per
|
|
148
|
+
visit, with arrival and discharge timestamps) into an hourly census series using
|
|
149
|
+
the event-cumsum trick (+1 at arrival, −1 at discharge, cumulative sum reindexed
|
|
150
|
+
to the hourly grid). The figure shows the last week of the synthetic fixture: a
|
|
151
|
+
clear diurnal cycle with overnight troughs and evening peaks.
|
|
152
|
+
|
|
153
|
+

|
|
154
|
+
|
|
155
|
+
### 2. Forecasting layer — 48-hour hourly forecast
|
|
156
|
+
|
|
157
|
+
On that series, `SeasonalNaiveBaseline` produces a 48-hour hourly forecast with
|
|
158
|
+
P50–P80 and P80–P95 quantile bands. The stronger models (`AutoARIMA`,
|
|
159
|
+
`AutoETS`, `LGBQuantile`) are compared in the evaluation harness and live behind
|
|
160
|
+
the same `Forecaster` interface.
|
|
161
|
+
|
|
162
|
+

|
|
163
|
+
|
|
164
|
+
### 3. Monte Carlo simulation engine
|
|
165
|
+
|
|
166
|
+
`urgencias_core.simulation.engine` takes future arrivals (sampled from the
|
|
167
|
+
forecast) and, for each arrival, samples an empirical length-of-stay conditional
|
|
168
|
+
on (acuity, arrival hour). Iterating M replicates yields census uncertainty
|
|
169
|
+
bands 24 hours ahead — the basis for surge decisions and shift tables.
|
|
170
|
+
|
|
171
|
+

|
|
172
|
+
|
|
173
|
+
### 4. Real data — weekly backtest on DEIS
|
|
174
|
+
|
|
175
|
+
The DEIS demo runs the same forecasting layer against real ED attendances from
|
|
176
|
+
Hospital de Puerto Montt. The harness holds out the last 12 complete weeks
|
|
177
|
+
(partial edge weeks are trimmed, since near-real-time DEIS data can under-count
|
|
178
|
+
the latest week) and trains on the prior history; `AutoARIMA` is selected by P80
|
|
179
|
+
pinball loss and tracks the autumn rise — evidence the pipeline isn't overfit to
|
|
180
|
+
the synthetic regime.
|
|
181
|
+
|
|
182
|
+

|
|
183
|
+
|
|
184
|
+
### 5. Operational 6-month forecast
|
|
185
|
+
|
|
186
|
+
With the model validated, the demo retrains on all history and emits a 26-week
|
|
187
|
+
weekly forecast — the useful horizon for staffing, budget, and supplies. The
|
|
188
|
+
P80–P95 band widens with the horizon, as expected.
|
|
189
|
+
|
|
190
|
+

|
|
191
|
+
|
|
192
|
+
### 6. Reference dashboard
|
|
193
|
+
|
|
194
|
+
The FastAPI server (`urgencias-server`) exposes four routes with the same charts
|
|
195
|
+
as the pipeline, live in the browser. It is deliberately minimal — Jinja2 plus
|
|
196
|
+
base64-embedded matplotlib, no JavaScript — a starting point for a hospital to
|
|
197
|
+
clone and adapt.
|
|
198
|
+
|
|
199
|
+
<p align="center">
|
|
200
|
+
<img src="https://raw.githubusercontent.com/nicoveraz/urg-forecast-core/main/docs/img/dashboard_index.png" width="48%" alt="Dashboard - index"/>
|
|
201
|
+
<img src="https://raw.githubusercontent.com/nicoveraz/urg-forecast-core/main/docs/img/dashboard_baseline.png" width="48%" alt="Dashboard - descriptive analytics"/>
|
|
202
|
+
</p>
|
|
203
|
+
<p align="center">
|
|
204
|
+
<img src="https://raw.githubusercontent.com/nicoveraz/urg-forecast-core/main/docs/img/dashboard_forecast.png" width="48%" alt="Dashboard - forecast"/>
|
|
205
|
+
<img src="https://raw.githubusercontent.com/nicoveraz/urg-forecast-core/main/docs/img/dashboard_simulation.png" width="48%" alt="Dashboard - simulation"/>
|
|
206
|
+
</p>
|
|
207
|
+
|
|
208
|
+
## What's inside
|
|
209
|
+
|
|
210
|
+
| Module | Purpose |
|
|
211
|
+
|---|---|
|
|
212
|
+
| `urgencias_core.data.loader` | Read a visit-level parquet and validate the schema. |
|
|
213
|
+
| `urgencias_core.data.timeseries` | Convert visits to an hourly series (arrivals, discharges, occupancy by acuity, mean LOS) via the event-cumsum trick. |
|
|
214
|
+
| `urgencias_core.data.deis` | DEIS MINSAL client (fetch + cache + filter to demo hospitals) with an offline snapshot fallback. |
|
|
215
|
+
| `urgencias_core.features.calendar` | `holidays.CL` holidays, bridge days, school calendar, configurable regional events. |
|
|
216
|
+
| `urgencias_core.features.weather` | Open-Meteo client with on-disk cache, Puerto Montt by default. |
|
|
217
|
+
| `urgencias_core.models.protocol` | `Forecaster` protocol and `HorizonSpec` (grain-agnostic: hourly, daily, weekly, monthly). |
|
|
218
|
+
| `urgencias_core.models.lgb_quantile` | LightGBM quantile regression, one model per quantile, calendar features. |
|
|
219
|
+
| `urgencias_core.eval.baselines` | `SeasonalNaiveBaseline` + `statsforecast` wrappers (AutoARIMA, AutoETS, AutoTheta, MSTL). |
|
|
220
|
+
| `urgencias_core.eval.harness` | Side-by-side evaluation with a ≥5% warning rule (a model that doesn't beat the baselines shouldn't ship). |
|
|
221
|
+
| `urgencias_core.simulation.los_empirical` | Empirical LOS sampler conditional on (acuity, arrival hour). |
|
|
222
|
+
| `urgencias_core.simulation.engine` | Monte Carlo census simulation 24 hours forward. |
|
|
223
|
+
| `urgencias_core.server` | Minimal FastAPI server (4 routes, Jinja2, base64 matplotlib, no JS). |
|
|
224
|
+
|
|
225
|
+
Docstrings are in English; user-facing strings in the server, demo outputs, and
|
|
226
|
+
fixtures are in Spanish.
|
|
227
|
+
|
|
228
|
+
## Public data: DEIS MINSAL
|
|
229
|
+
|
|
230
|
+
The DEIS demo uses open data from Chile's Ministry of Health Department of Health
|
|
231
|
+
Statistics and Information ([deis.minsal.cl](https://deis.minsal.cl/#datosabiertos))
|
|
232
|
+
for two hospitals in the Servicio de Salud Reloncaví network: **Hospital de
|
|
233
|
+
Puerto Montt** (code 24-105, high-complexity, locally "Hospital Base de Puerto
|
|
234
|
+
Montt") and **Hospital de Frutillar** (code 24-115, low-complexity).
|
|
235
|
+
|
|
236
|
+
DEIS publishes this series from 2008 to the present. The current-year file is
|
|
237
|
+
updated weekly during the winter respiratory campaign (March–September) and
|
|
238
|
+
roughly monthly otherwise. The demo uses the latest data available at run time
|
|
239
|
+
and produces a six-month-ahead forecast.
|
|
240
|
+
|
|
241
|
+
**Why these two hospitals.** Regional reference centers in Los Lagos with
|
|
242
|
+
publicly available data. Chosen on geographic and pragmatic grounds, not on any
|
|
243
|
+
evaluation of quality.
|
|
244
|
+
|
|
245
|
+
**Methodological framing only.** This demo uses public DEIS MINSAL data to show
|
|
246
|
+
how the forecasting tools behave on real Chilean hospital data. It is NOT an
|
|
247
|
+
operational, clinical, or quality evaluation of either hospital.
|
|
248
|
+
|
|
249
|
+
**Attribution and license.** Data published by DEIS MINSAL under Chile's open
|
|
250
|
+
data framework. If you use this code or derivatives for research, maintain DEIS
|
|
251
|
+
attribution and, where relevant, cite `urg-forecast-core`. The offline snapshot
|
|
252
|
+
bundled with the package is a filtered extract of the public dataset for
|
|
253
|
+
reproducibility; it does not replace fetching directly from the source for
|
|
254
|
+
operational use.
|
|
255
|
+
|
|
256
|
+
## Project status
|
|
257
|
+
|
|
258
|
+
`urg-forecast-core` is an open foundation, developed and maintained by Nicolás
|
|
259
|
+
Vera Z. as the base of **Eunosia**, a clinical AI platform for emergency
|
|
260
|
+
medicine. It is published on PyPI and maintained on a best-effort basis: while
|
|
261
|
+
on 0.x the API may change between minor versions, and issues and pull requests
|
|
262
|
+
are welcome but not guaranteed a fast response. If you need commercial support
|
|
263
|
+
or bespoke work on top of this foundation, contact the author.
|
|
264
|
+
|
|
265
|
+
See [`CONTRIBUTING.md`](https://github.com/nicoveraz/urg-forecast-core/blob/main/CONTRIBUTING.md)
|
|
266
|
+
for development and release procedures, [`docs/decisions.md`](https://github.com/nicoveraz/urg-forecast-core/blob/main/docs/decisions.md)
|
|
267
|
+
for architecture decisions, and [`docs/roadmap.md`](https://github.com/nicoveraz/urg-forecast-core/blob/main/docs/roadmap.md)
|
|
268
|
+
for deferred items (xlsx/mdb support for DEIS 2017–2019, neuralforecast, EMR
|
|
269
|
+
integration to separate workup from boarding time).
|
|
270
|
+
|
|
271
|
+
## Citing
|
|
272
|
+
|
|
273
|
+
If you use `urg-forecast-core` in research, please cite it. Machine-readable
|
|
274
|
+
metadata lives in [`CITATION.cff`](https://github.com/nicoveraz/urg-forecast-core/blob/main/CITATION.cff)
|
|
275
|
+
(GitHub renders a "Cite this repository" button from it). Each tagged release is
|
|
276
|
+
archived on [Zenodo](https://zenodo.org/) with a DOI.
|
|
277
|
+
|
|
278
|
+
<!-- After the first Zenodo release, add the concept-DOI badge and BibTeX here:
|
|
279
|
+
[](https://doi.org/10.5281/zenodo.XXXXXXX) -->
|
|
280
|
+
|
|
281
|
+
A software paper (JOSS format) and a fuller methods preprint are drafted under
|
|
282
|
+
[`paper/`](https://github.com/nicoveraz/urg-forecast-core/tree/main/paper).
|
|
283
|
+
Please also mention Eunosia and link back to the repository.
|
|
284
|
+
|
|
285
|
+
## License
|
|
286
|
+
|
|
287
|
+
MIT. See [LICENSE](https://github.com/nicoveraz/urg-forecast-core/blob/main/LICENSE).
|