Algorithmic Fairness, Missingness Topologies, and Structural Feature Interactions in a Sub-Saharan Hypertensive Risk Prediction Cohort
Principal Investigator: Paul Sentongo
Affiliation: Independent Research Portfolio (Resource-Constrained Clinical AI Initiatives)
Data Infrastructure: Electronic Health Records from Nakaseke Hospital, Uganda
Live Screener Application: https://nakaseke-hypertension-screener.onrender.com/
Non-communicable diseases (NCDs) are the fastest-growing source of mortality in Sub-Saharan Africa. Hypertension is the primary upstream cause of stroke, ischemic heart disease, and renal failure across the region. Unlike the dense, highly curated registries used to build published clinical risk models in high-income countries, community-based screening data from resource-constrained environments like Nakaseke District, Uganda, contains severe structural missingness, small-sample subgroup fragility, and no confirmatory laboratory biomarkers.
This repository evaluates whether a hypertension risk classifier trained on low-resource screening data can achieve high statistical reliability, demographic equity, and physiological interpretability. We replace standard median/mode imputation with multivariate iterative missing-data resolution, comparing Bayesian Ridge MICE against an Extra-Trees MissForest implementation.
We then run an algorithmic fairness audit that decomposes model performance across sex and age strata using Disparate Impact Ratio (DIR), Demographic Parity Difference (DPD), Equal Opportunity Difference (EOD), and Expected Calibration Error (ECE). Finally, we calculate the second-order SHAP interaction tensor to isolate non-linear physiological feature interactions learned by the ensemble.
+-------------------------------------------------------+
| Nakaseke Hospital EHR Cohort |
| (N = 3,471 Patients) |
+-------------------------------------------------------+
|
v
+-------------------------------------------------------+
| Missingness Topology Engine |
| (MICE / MissForest Iterative Imputation) |
+-------------------------------------------------------+
|
v
+-------------------------------------------------------+
| Model Selection & Tuning |
| (Scikit-Learn / Optuna / MLflow) |
+-------------------------------------------------------+
|
+----------------------+----------------------+
| |
v v
+---------------------------------------+ +---------------------------------------+
| Algorithmic Fairness Audit | | Second-Order Explainability |
| (Demographic Slices: DIR, DPD, EOD) | | (Full SHAP Interaction Tensor Matrix) |
+---------------------------------------+ +---------------------------------------+
Tabular machine learning algorithms assume missing data points are negligible or randomly distributed. This assumption breaks down in Community Health Worker (CHW) field operations.
In the Nakaseke research dataset, the age field is missing for 49.3% of the 3,471 recorded patients. This missingness is non-random. It stems from interview fatigue, respondent absence during follow-up visits, equipment shortages, and field transcription gaps.
For example, if a CHW misplaces a measuring tape mid-day, waist circumference data collection stops for all subsequent patients until replacement equipment arrives. If a patient grows tired during a long survey, later items (such as dietary frequency) are skipped, while early demographic items remain complete.
This creates Missing At Random (MAR) or Missing Not At Random (MNAR) data patterns. Filling these gaps with a column median or mode destroys the underlying correlation structure. It collapses conditional distributions onto marginal averages, artificially squeezes variance, and shifts the estimated risk boundary. Aggregate AUROC scores calculated on naively imputed data conceal these systemic errors.
UNCONDITIONAL IMPUTATION (Median/Mode) MULTIVARIATE ITERATIVE IMPUTATION (MICE)
Variable Y Variable Y
^ ^
| o o | o o
| o o o | o o o
Imputed -> |===== X ===== (Collapses Variance) | o X o (Preserves Joint
| o o | o o Distribution)
| o o | o o
+-------------------> +------------------->
Variable X Variable X
Catchment-area screening cohorts reflect patterns of health-seeking behavior, local transport access, and demographic self-selection. A risk model trained on this data can show strong overall performance while failing on key sub-populations.
If a screening model under-flags older women or younger adults, those patients miss out on follow-up care. Evaluating a clinical tool purely on aggregate population metrics creates systemic performance gaps for under-represented groups.
The pipeline resolves missing data using Multivariate Imputation by Chained Equations (MICE) through scikit-learn's IterativeImputer. Each incomplete feature
The algorithm cycles through missing fields iteratively until predictions stabilize. Two conditional models are evaluated:
- MICE (Bayesian Ridge): A fast, linear-Gaussian model executed inside cross-validation loops to prevent data leakage across train and validation splits.
- MissForest (Extra-Trees Regressor): A non-parametric model that captures non-linear relationships and feature interactions among physical measurements (such as waist circumference, hip circumference, and BMI).
The imputer is embedded directly inside the pipeline (src/data/imputation.py). It fits only on training folds and applies .transform() to validation and test folds.
Let src/fairness/audit.py) measures three primary fairness metrics:
- Demographic Parity Difference (DPD): Measures the absolute difference in positive prediction rates between demographic groups:
- Disparate Impact Ratio (DIR): Evaluates selection rates as a ratio between groups:
- Equal Opportunity Difference (EOD): Measures the gap in true positive rates (sensitivity). This serves as our core clinical metric, tracking whether hypertensive individuals in one group are missed more often than those in another:
Each sub-population is also evaluated for Expected Calibration Error (ECE) to verify that predicted probabilities match observed outcome rates.
Individual feature contributions are calculated using Shapley Additive Explanations (SHAP). For a model
To evaluate non-linear feature interactions, we calculate the second-order SHAP interaction tensor (Lundberg et al., 2020):
This tensor matrix is computed in polynomial time via Tree SHAP (src/explainability/interactions.py), exposing structural feature couplings across the learned decision boundary.
- Hospital-Seeking Selection Bias: The dataset consists of individuals presenting at Nakaseke Hospital. Asymptomatic individuals or those living far from health facilities are under-represented. Predictions are conditional on health-system contact.
- Unmeasured Confounders: The dataset lacks laboratory biomarkers, exact dietary sodium excretion measurements, physical activity tracking, and genetic profiles. This puts a ceiling on achievable predictive performance.
- Cross-Sectional Data: Predictions rely on a single clinical interaction. The pipeline does not track longitudinal risk trajectories over time.
- Geographic Coverage Gaps: Demographic auditing is limited to age and sex. Sub-county geographic location data is absent from the current modeling pipeline.
- Age-Stratified Missingness Constraints: Because 49.3% of patient age records were missing in the raw survey, age-based fairness metrics are evaluated exclusively on the observed age sub-cohort to avoid confounding fairness measurements with imputation noise.
All statistics are calculated using research.py on an independent, stratified 20% test partition (
| Baseline & Imputation Model | Imputation Strategy | Test AUROC | F1 Score | Recall (Sensitivity) | Precision |
|---|---|---|---|---|---|
| Logistic Regression Baseline | Column Median / Mode Substitution | 0.639 | 0.447 | 0.571 | 0.367 |
| Audited Random Forest Model | MissForest Extra-Trees (IterativeImputer) |
0.649 | 0.343 | 0.262 | 0.495 |
Note: Precision is derived algebraically from reported F1 and Recall ($P = rac{F1 \cdot R}{2R - F1}$). The Random Forest trades raw sensitivity for higher precision and a statistically rigorous imputation pipeline.
| Sex | n | Disease Prevalence | AUROC | Recall (TPR) | Precision | F1 Score | ECE |
|---|---|---|---|---|---|---|---|
| Male | 333 | 25.8% | 0.602 | 14.0% | 0.444 | 0.212 | 0.119 |
| Female | 362 | 29.0% | 0.682 | 36.2% | 0.514 | 0.425 | 0.121 |
- Disparate Impact Ratio (DIR): 0.397 (below the 0.80 benchmark threshold).
- Equal Opportunity Difference (EOD): -0.222 (male patients experience lower sensitivity).
| Age Band | n | Disease Prevalence | AUROC | Recall (TPR) | Precision | F1 Score | ECE |
|---|---|---|---|---|---|---|---|
| < 30 | 65 | 13.8% | 0.611 | 0.0% | — | 0.000 | 0.095 |
| 30–44 | 111 | 20.7% | 0.659 | 13.0% | 0.333 | 0.188 | 0.138 |
| 45–59 | 112 | 30.4% | 0.634 | 20.6% | 0.500 | 0.292 | 0.109 |
| ≥ 60 | 72 | 47.2% | 0.674 | 58.8% | 0.645 | 0.615 | 0.153 |
- Disparate Impact Ratio (DIR): 0.000
- Equal Opportunity Difference (EOD): -0.588
At the default decision threshold, the model fails to flag hypertensive patients under age 30. This highlights why demographic auditing is essential before deploying clinical screening models.
The full interaction tensor matrix
| Rank | Feature Pair Coupling | Mean Absolute Interaction (adds_salt × lifestyle_score | 0.00180 |
| 2 | married × employed | 0.00176 |
| 3 | adds_salt × biomass_exposure | 0.00158 |
| 4 | veg_servings_week × adds_salt | 0.00144 |
| 5 | biomass_exposure × height_cm | 0.00143 |
| 8 | age × adds_salt | 0.00125 |
| 10 | age × married | 0.00115 |
| 14 | household_size × age_group | 0.00111 |
- Feature Engineering Artefact: The top interaction pair (
adds_salt×lifestyle_score) reflects how the synthetic feature was constructed, aslifestyle_scoreincorporatesadds_salt. The model detects mathematical overlap rather than a novel physiological mechanism. - Attenuated Physical Interactions: The expected interaction between age and BMI did not rank within the top 15 pairs. In this cohort fit, age interactions manifest primarily through household structure (
age_group×household_size) and lifestyle indicators (age×adds_salt).
Outputs are saved to models/research/top_shap_interactions.csv, models/figures/shap_interaction_heatmap.png, and models/figures/shap_interaction_age_bmi.png.
To bypass the predictive ceiling of survey-only screening, future iterations will integrate non-invasive fundus imaging. Hypertensive retinopathy causes microvascular changes—such as arteriovenous nicking and arteriolar narrowing—visible via smartphone-attached ophthalmoscopes.
+------------------------------------+ +------------------------------------+
| Tabular Survey Vector | | Retinal Fundus Image |
| (Demographics, Measurements, etc) | | (Smartphone Ophthalmoscopy) |
+------------------------------------+ +------------------------------------+
| |
v v
+------------------------------------+ +------------------------------------+
| Dense Tabular Encoder | | Vision Transformer / ResNet |
+------------------------------------+ +------------------------------------+
| |
+--------------------+----------------------+
|
v
+-----------------------------+
| Cross-Attention Fusion |
| Token Gating |
+-----------------------------+
|
v
+-----------------------------+
| Hypertension Risk Logit |
+-----------------------------+
- Data Collection: Collect paired questionnaire data and fundus photographs across clinical field sites.
- Pre-training: Pre-train image backbones on public eye-disease datasets before fine-tuning on local clinical data.
- Cross-Attention Fusion: Use cross-attention token gating so tabular risk indicators dynamically highlight spatial vascular features in image embeddings.
- Fairness Re-Audit: Run subgroup performance audits on the multimodal model to prevent new sources of demographic disparity.
src/
├── data/
│ ├── loader.py # Reads raw Stata (.dta) files
│ ├── cleaner.py # Data cleaning and target variable construction
│ ├── features.py # Feature engineering and transformation rules
│ └── imputation.py # Imputation modules (MICE and MissForest)
├── models/
│ └── trainer.py # Model training, hyperparameter tuning, and logging
├── fairness/
│ └── audit.py # Demographic parity and fairness audit framework
├── explainability/
│ └── interactions.py # Second-order SHAP interaction computation
├── pipeline.py # Production training pipeline (train.py)
└── research_pipeline.py # Research audit entry point (research.py)
pip install -r requirements.txt
python train.pypython research.pyAll configurations, split ratios, random seeds (42), and imputation options are governed by config/config.yaml.
The web application (app/) runs inside a Docker container (Dockerfile) configured for automated deployment via Render (render.yaml).
- The production Random Forest model (
models/best_model.pkl) processes inference requests entirely in memory. - Free-tier hosting instances enter sleep mode after inactivity and require 30 to 60 seconds to boot up on request.
- The application is an auxiliary clinical screening aid and does not replace diagnostic blood pressure measurements.
- Patient records are fully anonymized. No personal identifiers (names, addresses, contact numbers) are stored or passed to inference pipelines.
- The web tool processes incoming feature vectors in memory without writing responses to disk.
- Model output probabilities are displayed alongside risk tier classifications and recommended follow-up actions.
- The low sensitivity observed in young demographic groups mandates that model predictions should not be used as an exclusive decision maker for patient discharge or triage.
@misc{sentongo2026hypertension,
author = {Sentongo, Paul},
title = {Algorithmic Fairness, Missingness Topologies, and Structural Feature Interactions in a Sub-Saharan Hypertensive Risk Prediction Cohort},
year = {2026},
publisher = {GitHub},
journal = {GitHub Repository},
howpublished = {\url{https://github.com/sentongo-web/Hypertension-Detection-Complete-MLOPs}}
}Distributed under the MIT License. Raw clinical records remain the private property of Nakaseke Hospital Research Unit and are excluded from public redistribution.