The puzzle
The data are the matched case-control cohort from Usala et al. (2015), rebuilt from the underlying EHR records. The cohort is exactly 50/50 cases and controls by construction. Even so, every model recalls controls far better than cases at the default 0.5 cutoff.
Out-of-fold predictions, 10-fold cross-validation split by matched pair, full-record lab columns excluded.
For screening, a strong ranking score does not mean a model catches most patients with the disease. Where the threshold sits, and who falls just below it, decides that.
The evidence
All four models separate cases from controls well above chance.
But cases are bimodal, and one of their peaks overlaps the controls just under the 0.5 cutoff.
The same distributions, viewed through their medians: controls sit tightly below the cutoff, while the typical case sits barely above it.
Validation
Before any modeling, I rebuilt the source study (Usala et al., 2015) and reproduced its hyponatremia–osteoporosis association with conditional logistic regression stratified on the matched pairs, pooling five BMI imputations by Rubin's rules.
- Imputation check
- BMI was missing for about 68% of patients, far more often among cases, yet adjusting for it barely moved the association, so the reproduction is not driven by the imputation.
Safeguards
Matched observational EHR data breaks assumptions that standard ML pipelines take for granted.
- Temporal leakage
- Full-record lab summaries include post-diagnosis measurements (sodium is recorded for 99.6% of patients across the full record vs. 67.4% before the index date), so all full-record features were excluded.
- Pair-grouped cross-validation
- Folds are assigned by matched stratum, so a case and its matched control never fall on opposite sides of a split.
Finding
- Not class imbalance
- Exact 50/50 balance rules it out by design.
- Not a single algorithm
- The gap persists from linear models to gradient boosting. Moving from logistic regression to XGBoost lifts AUC from 0.749 to 0.790 but only narrows the gap from 0.29 to 0.24.
- Ranking is not the problem
- Tree ensembles rank a case above its matched control about 79% of the time, well above chance.
- Case heterogeneity
- The evidence so far points to a high-signal case subgroup the models catch, alongside a second group that overlaps heavily with controls.
Stage 3 is in progress: separating missingness flags from lab deciles and computing SHAP values for the two confidence groups.
Tech Stack
- LanguagePython
- Modelingscikit-learn · XGBoost
- Statisticsstatsmodels
- MethodsConditional logit · Rubin's rules
Code, notebooks, and full documentation are in the repository. Patient data is institutional and not redistributed.