Downloads · 30 days
0
ethanchrstian/siaga-pantura-hazard-models
siaga-pantura-hazard-models is a tabular classification model from ethanchrstian. Use it for the tabular classification task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
Two calibrated XGBoost classifiers that drive SIAGA, a Pusdalops decision board for coastal north Java. They answer two questions for each of 324 kecamatan:
Downloads · 30 days
0
Access
Public
Updated Aug 8, 2026
Repo size
4.1 KB
Likes
0
Public
Click a slice to open those files.
.json2 MB · 99%
From the Hugging Face model README
Two calibrated XGBoost classifiers that drive SIAGA, a Pusdalops decision board for coastal north Java. They answer two questions for each of 324 kecamatan:
The point of the pair is that both hazards draw on one water balance and one fleet of trucks, pumps and crews. The probabilities feed a two-stage stochastic CVaR program that pre-positions that shared fleet, so the two numbers have to be comparable and honestly calibrated, not just individually accurate.
Built for RISTEK Fasilkom UI Datathon 2026.
| File | What it is |
|---|---|
flood_model.json | XGBoost booster, flood in t+1..t+3 |
drought_model.json | XGBoost booster, water stress at month m+1 |
flood_calibrator.pkl | Isotonic calibrator, fitted out-of-fold |
drought_calibrator.pkl | Isotonic calibrator, fitted out-of-fold |
model_meta.json | Feature order for each model |
metrics.json | Full test metrics, feature importance, calibrator selection |
climatology.json | Per-district discharge threshold and SPI gamma parameters |
reliability.json, reliability.csv | Reliability curve on the held-out years |
climatology.json is needed to rebuild features from raw rainfall and
discharge, so it ships with the models rather than the data.
Flood is river discharge exceeding that district's own 95th percentile at some point in the next 72 hours, which is the return-period rule GloFAS uses for its alerts. Discharge is independent of the rainfall features because it integrates upstream routing.
Water stress is SPI-3 for the following month at or below -1.0, McKee's moderate-drought threshold. SPI is the index BMKG uses operationally.
Neither label comes from disaster event records. BNPB's DIBI sits behind a locked Superset instance, its open ArcGIS layers return HTTP 500, and the Dartmouth Flood Observatory archive is decommissioned. Labelling from open physical reanalysis is arguably more rigorous than a news-derived event list, but it is a different thing and should be read as such: these models predict a physical exceedance, not a declared disaster.
Trained on 2015 to 2022, tested on 2023 to 2024. No district or period appears in both.
| Flood | Water stress | |
|---|---|---|
| Test rows | 232,458 | 7,452 |
| Base rate | 5.2% | 18.6% |
| AUC | 0.931 | 0.959 |
| Average precision | 0.444 | 0.858 |
| Brier | 0.0364 | 0.0650 |
| Brier, uncalibrated | 0.0566 | 0.0693 |
| Reliability | 0.00051 | 0.00348 |
| Operating threshold | 0.227 | 0.500 |
| Precision at threshold | 0.353 | 0.770 |
| Recall at threshold | 0.686 | 0.792 |
Calibration matters more here than discrimination, because the downstream optimizer multiplies these probabilities by exposed population and allocates on the result. A miscalibrated 90% sends trucks to the wrong kecamatan. Calibrators were selected on reliability rather than Brier score, since Brier rewards sharpness and would have picked a better-separating but less honest model.
Read the flood precision before you trust an alert. At the operating threshold, precision is 0.353. About two in three flood warnings are not followed by a threshold exceedance. That is the cost of 0.686 recall on a 5.2% base rate, and the product states it on the printed dispatch order rather than hiding it.
The worst calibration gap above 0.5 is 0.079 for flood and 0.190 for water stress. The water stress figure is the weaker one and is worth knowing before acting on a high drought probability.
Flood, per district-day: rain_1d, rain_3d, rain_7d, rain_30d,
disc_now, disc_7d_mean, disc_change_3d, month, coastal.
Water stress, per district-month: spi1, spi3, spi6, p1, dry_run,
month, coastal.
Order matters. Read it from model_meta.json rather than from this table.
Most of the flood signal is accumulated rainfall: rain_30d alone carries 0.358
of the importance, with rain_7d and rain_3d next. For water stress, spi1
carries 0.552.
import json, pickle
import numpy as np
import xgboost as xgb
from huggingface_hub import hf_hub_download
REPO = "ethanchrstian/siaga-pantura-hazard-models"
meta = json.load(open(hf_hub_download(REPO, "model_meta.json")))
cols = meta["flood_feats"]
booster = xgb.Booster()
booster.load_model(hf_hub_download(REPO, "flood_model.json"))
with open(hf_hub_download(REPO, "flood_calibrator.pkl"), "rb") as f:
cal = pickle.load(f)
# Column order must match meta["flood_feats"].
X = np.array([[12.0, 40.0, 88.0, 310.0, 220.0, 190.0, 35.0, 2, 1]])
raw = booster.predict(xgb.DMatrix(X, feature_names=cols))
if cal["type"] == "isotonic":
prob = np.clip(cal["model"].predict(raw), 1e-3, 1 - 1e-3)
elif cal["type"] == "platt":
prob = cal["model"].predict_proba(raw.reshape(-1, 1))[:, 1]
else:
prob = raw
prob = np.clip(prob, 0.0, 1.0)
# raw 0.714 -> calibrated 0.386
The calibration step is not optional, and the comment on the last line is why:
the booster's raw output on that row is 0.714, and the honest probability is
0.386. Skip the calibrator and every downstream allocation is computed from a
number roughly twice too large. metrics.json records brier_uncalibrated
alongside brier so the aggregate effect is visible too.
cal is a dict with keys type, model and op_threshold. Both models
currently use isotonic, but branch on type rather than assuming it. The
reference implementation is _apply_cal in backend/app/services/hazard.py in
the GitHub repo.
ethanchrstian/siaga-pantura-hazard-data,
which carries the feature tables, the labels, the boundaries, the population
raster extract and the precomputed probability history.
Sources: ERA5 rainfall and GloFAS v4 discharge, both via Open-Meteo; GADM v4.1 level 3 boundaries; WorldPop 2020 UN-adjusted population.
@misc{siaga2026,
title = {SIAGA: Sistem AI untuk Peringatan Dini Banjir-Kekeringan Terkopel
dan Optimasi Prapenempatan Sumber Daya Bencana},
year = {2026},
note = {RISTEK Fasilkom UI Datathon 2026},
url = {https://github.com/ethannchrstian/Siaga}
}
License MIT. The underlying data keeps its own terms: ERA5 and GloFAS under Copernicus, GADM non-commercial, WorldPop CC BY 4.0.