Bhargav Adepu

NO. 01MACHINE LEARNING · ACTIVENOVEMBER 2025 – PRESENT

AquaSafe

Five models for waterborne disease risk, and what each one is worth

Waterborne disease in India is not an unsolved science problem. It is a timing problem: the data that would predict an outbreak exists, but it sits in separate registries and arrives after the fact. AquaSafe is an attempt to close that gap and an honest account of which parts of the problem yielded and which did not.

Water quality99.95%binary accuracy
Severity grading92.73%4-class ordinal
Disease prediction73.79%top-3 of 8 classes
Outbreak riskR² 0.9496regression, RMSE 0.0746

Flutter · FastAPI · XGBoost · LightGBM · scikit-learn · Python · joblib

AquaSafe analyses water chemistry, sanitation infrastructure and regional health data to answer four questions: is this water safe, what disease is this presentation most likely to be, how severe is this case, and how likely is an outbreak in this district. Each question is a separate model, because they are separate problems with separate error costs.

The dataset was the project

There is no public dataset joining water chemistry to disease incidence at district resolution in India. The training set is therefore synthetic — 500,000 records generated against real Indian epidemiological distributions, with 26 features spanning water chemistry, sanitation, climate, demographics and clinical symptoms. Total training time across all five models was 36 minutes.


Water quality · binary99.95%
Severity · 4-class ordinal92.73%
Disease, top-3 · 8 classes73.79%
Disease, top-1 · 8 classes42.46%
0100%

FIG. 1The five heads, ranked by how well they actually worked. Water quality is nearly solved; single-label disease attribution is not. Both are printed at the same size on purpose.

What worked

The water quality classifier reached 99.95% accuracy with an F1 of 0.9997, driven — unsurprisingly, and reassuringly — by pH, total coliform count, turbidity, TDS and E. coli. When a model's top features are exactly the ones a sanitary engineer would name, that is evidence the pipeline is wiring the right signal through rather than memorising an artefact of the generator.

Severity assessment, treated as an ordinal problem across Low/Medium/High/Critical, reached 92.73% exact accuracy and 98.16% adjacent accuracy — meaning it is almost never wrong by more than one grade, which is the error profile that matters for triage. Outbreak risk is a regression over a 0–1 range, scoring R² 0.9496 with an RMSE of 0.0746.

What did not

Single-label disease attribution across eight classes reached 42.46% top-1 accuracy, with a macro F1 of 0.2020. Top-3 accuracy was 73.79%. This is the weakest model in the set and the honest reading is that environmental features alone do not separate cholera from typhoid from giardiasis — the clinical presentations overlap, and the synthetic generator cannot invent a signal that the underlying epidemiology does not contain.

It also took by far the longest to train — 1,806 seconds against 17 for severity — which is the usual signature of a model straining against a problem rather than learning it. Presented as a top-3 shortlist for a health worker to narrow by symptom, 74% is useful. Presented as a diagnosis, 42% is not, and the application surfaces it as the former.

The interesting output of this project is not the 99.95%. It is knowing precisely which of the five questions the data can answer and which it cannot.

Shipping it

All five models are exported to joblib and served behind a FastAPI service, with StandardScaler normalisation and median imputation applied identically at training and inference time. The client is a Flutter application targeting iOS, Android and web from one codebase. Inference has to feel instant on a mid-range Android phone over an unreliable connection, which is the requirement that made gradient-boosted trees the right answer over anything deeper.