"They told me the ECG was a rhythm strip. Then I learned to read a person's heart size, their potassium, and their age off twelve squiggles a cardiologist calls normal."
An Over-Read AI Agent
Why this section matters
Everything else in this chapter teaches the machine to do what a human already does: name a rhythm, flag a beat, measure an interval. This section is different. It teaches the machine to read things off the ECG that no cardiologist can see. A standard twelve-lead trace turns out to encode the size and squeeze of the heart muscle, the concentration of potassium in the blood, and the biological age of the person, none of which the human eye can extract from the same waveform. These "hidden diagnoses" convert a cheap, painless, ubiquitous test into a screening instrument for conditions that normally need an echocardiogram, a blood draw, or a birth certificate. That is a genuinely new capability, and it is the clearest demonstration in the book that a deep model can recover latent physical state from a sensor signal that experts had declared uninformative.
This section builds on the ECG morphology and lead geometry of Section 29.1 and treats the twelve-lead trace as the measurement \(x = h(s) + \eta\) of a hidden physiological state \(s\), the framing from Chapter 2. The estimation and base-rate reasoning we lean on comes from Chapter 4, and the convolutional backbones that do the reading are the ones from Chapter 13. We stay off the deep-model architecture details, which are the topic of Section 29.5, and off record-versus-beat labeling, which is Section 29.4.
What "hidden diagnosis" actually means
A conventional ECG interpretation is a decoding of features a clinician was taught to name: the width of the QRS complex, the slope of the ST segment, the shape of the T wave. A hidden-diagnosis model does not predict any of those. It predicts a target that lives in a different measurement entirely, an echocardiogram, a serum chemistry panel, or a demographic field, and it learns whatever subtle, distributed pattern in the waveform happens to correlate with that target. The signal was always there; the human reader simply lacked the sensitivity to combine hundreds of sub-threshold amplitude and timing cues across twelve leads into one number. The model does exactly that combination. The result is not magic and not a rhythm classifier with a new label. It is a regression or classification head trained against a paired ground truth that came from a completely different instrument.
The ECG is a wider aperture than the human reader ever used
Two claims that sound contradictory are both true: the standard ECG is fully characterized (we digitize every microvolt of it) and yet cardiologists extract only a fraction of its information. The gap is not in the sensor, it is in the decoder. Deep models widen the decoder, not the sensor. Any structural, metabolic, or demographic variable that leaves a reproducible fingerprint on ventricular depolarization and repolarization is, in principle, recoverable, which is why the list of "hidden diagnoses" keeps growing (low ejection fraction, hyperkalemia, age, sex, anemia, aortic stenosis, and more).
Three canonical targets: LVEF, age and sex, hyperkalemia
Left-ventricular ejection fraction (LVEF). LVEF is the fraction of blood the left ventricle ejects per beat; below roughly \(35\%\) it defines the asymptomatic left-ventricular dysfunction that precedes heart failure and is normally caught only by echocardiography. The landmark result (Attia and colleagues, Nature Medicine 2019) trained a convolutional network on paired ECG and echo LVEF and screened for \(\text{LVEF} \le 35\%\) at an area under the ROC curve near \(0.93\). Why does it work? A weakened, remodeled ventricle subtly alters conduction timing and repolarization in ways that spread across many leads below the threshold a human notices. When and where it matters: opportunistic screening of large asymptomatic populations, where an echo for everyone is unaffordable but an ECG is already being recorded.
Age and sex. The same architecture, retargeted at demographic labels, estimates biological sex with roughly \(90\%\) accuracy and chronological age with a mean absolute error near \(7\) years (Attia and colleagues, Circulation: Arrhythmia and Electrophysiology 2019). The scientifically interesting part is the error itself: when the ECG-predicted age runs well ahead of the true age, that gap associates with cardiovascular comorbidity and mortality, so the "wrong" prediction behaves like an aging biomarker. This is the cleanest illustration that the model reads physiological state, not a label lookup, because there is no clinical feature a human uses to guess age from a normal ECG.
Hyperkalemia. Elevated serum potassium slows and distorts cardiac repolarization; the textbook sign is a tall, peaked T wave, but by the time a human sees it the potassium is already dangerous, and the early, subtle changes are unreadable by eye. A deep model trained on ECGs paired with contemporaneous blood-draw potassium detects hyperkalemia at an AUC around \(0.85\) (Galloway and colleagues, JAMA Cardiology 2019). The payoff is a bloodless potassium estimate, which matters enormously for dialysis and chronic-kidney-disease patients who otherwise need frequent venous draws.
A dialysis clinic that watches potassium without a needle
Consider a nephrology group monitoring hemodialysis patients whose potassium swings dangerously between sessions. Venous draws are painful, slow to result, and cannot run continuously at home. The group deploys a single-lead ECG, the kind captured by a two-electrode patch or a smartwatch pad, feeding a hyperkalemia model derived from the twelve-lead work but retrained on the reduced-lead signal these patients can actually record at home. A rising predicted-potassium trend between clinic visits triggers an earlier appointment or a medication adjustment, catching a subset of hyperkalemic episodes days before the next scheduled draw would have. The model does not replace the lab; it decides when the lab is worth ordering, which is the honest role of a screening signal.
The label, not the network, is where the science lives
Every hidden-diagnosis model is a join between two instruments: the ECG and the ground-truth source (echo, lab, or registry). Two mistakes in that join silently inflate performance to the point of fiction. The first is temporal misalignment. Potassium changes over hours, LVEF over weeks, so an ECG must be paired only with a ground-truth value measured inside a physiologically valid window; pairing a normal-potassium ECG with a blood draw taken two days later teaches the model nothing real. The second, and worse, is patient-level leakage. Many patients contribute several ECGs; if the same person appears in both training and test sets, the model can recognize the individual and their stable anatomy rather than the target condition, and the reported AUC becomes a measurement of memorization. The fix is the leakage-safe discipline of Chapter 5: split by patient before anything else, then align labels within a defined window.
import numpy as np, pandas as pd
# ecgs: one row per recording; labs: one row per blood draw
ecgs = pd.DataFrame({"patient": [1,1,2,3], "ecg_id": [10,11,20,30],
"t_hours": [0.0, 50.0, 2.0, 5.0]})
labs = pd.DataFrame({"patient": [1,1,2,3], "potassium": [4.1, 6.3, 5.9, 4.4],
"t_hours": [1.0, 49.0, 3.5, 40.0]})
WINDOW_H = 4.0 # potassium is only valid within 4 h
pairs = ecgs.merge(labs, on="patient", suffixes=("_ecg", "_lab"))
pairs = pairs[(pairs.t_hours_ecg - pairs.t_hours_lab).abs() <= WINDOW_H]
# patient-level split BEFORE modelling: no patient in both folds
rng = np.random.default_rng(0)
patients = pairs.patient.unique()
test_ids = set(rng.choice(patients, size=max(1, len(patients)//5), replace=False))
pairs["fold"] = np.where(pairs.patient.isin(test_ids), "test", "train")
print(pairs[["patient", "ecg_id", "potassium", "fold"]].to_string(index=False))
patient so no individual leaks across folds. The ECG at t=50 h for patient 1 correctly pairs with the K=6.3 draw, not the earlier normal one.Both filters in that snippet are prerequisites, not refinements. Skip the window and you attach stale labels; skip the patient split and your test AUC measures how well the network re-identifies people. Real reported numbers use both, which is why they generalize to new hospitals.
Grouped, leakage-safe splitting in one line
Hand-rolling a patient-disjoint train/test split (tracking which identifiers landed where, guarding against overlap) is a dozen error-prone lines. scikit-learn packages it:
from sklearn.model_selection import GroupShuffleSplit
gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=0)
train_idx, test_idx = next(gss.split(pairs, groups=pairs["patient"]))
GroupShuffleSplit guarantees no patient spans both folds, replacing roughly 15 lines of manual identifier bookkeeping and the off-by-one bugs that cause silent leakage. The groups argument is the entire contract.The library enforces the disjointness; your remaining judgment is choosing the grouping key (patient, not recording, not visit) and the alignment window. Those two choices, not the split code, are where the domain expertise sits.
From a good AUC to a trustworthy screen
A high AUC is necessary and not sufficient, because these conditions are rare. Screening operates at low prevalence, where positive predictive value is governed by Bayes' rule from Chapter 4:
$$ \mathrm{PPV} = \frac{\mathrm{sens}\cdot p}{\mathrm{sens}\cdot p + (1-\mathrm{spec})(1-p)} $$At a prevalence \(p\) of a few percent, even a model with \(0.90\) sensitivity and \(0.90\) specificity yields a PPV well under \(50\%\), so most positive flags are false and the output must be treated as "order the confirmatory test," never as a diagnosis. This makes calibration, not just ranking, the deployment-critical property: the predicted probability has to mean what it says so a clinician can weigh it, which is exactly the calibration and conformal machinery of Chapter 18. And because a screening flag changes patient care, the value is proven only in a prospective trial, not a retrospective AUC, which connects forward to the clinical-validation design of Section 29.7 and the regulatory frame of Chapter 34.
Where the field is now
The LVEF screener is past the retrospective stage: the EAGLE pragmatic randomized trial (Yao and colleagues, Nature Medicine 2021) cluster-randomized primary-care clinics and showed that surfacing the AI-ECG low-EF flag to physicians increased the diagnosis of low ejection fraction in routine practice, one of the first randomized demonstrations that a hidden-diagnosis ECG changes care, not just a metric. The frontier is moving in two directions: pushing these targets onto single-lead and wearable ECG (Chapter 30) so screening leaves the clinic, and replacing task-specific CNNs with ECG foundation-model embeddings (Section 29.5) that expose many hidden diagnoses from one shared representation. The open problems are honest external validation across hospitals and demographic subgroups, and defending against dataset shift when the deployment population differs from the training cohort.
A shortcut label is a landmine
Because the model reads demographics off the ECG, it can quietly solve the wrong problem. If sicker patients in your dataset happen to be recorded on a particular machine, or if lead placement correlates with the care setting, the network may latch onto an acquisition artifact that predicts the label without any physiology. The age-and-sex result is the canary: a model that infers demographics can also infer, and exploit, the confounders bound to demographics. Audit for it by testing on a hospital whose acquisition hardware and case mix differ from training, and by checking that performance survives when obvious shortcuts (device metadata, timestamps, site) are stripped.
Exercise: size the screen before you build it
You are asked to deploy a hyperkalemia ECG screen in an outpatient nephrology clinic where the prevalence of \(\text{K}^+ > 5.5\) at any given visit is \(4\%\). Your model reports sensitivity \(0.88\) and specificity \(0.88\). (1) Compute the positive predictive value with the Bayes formula above. (2) Given that PPV, write the one-sentence instruction that should appear next to every positive flag in the clinician's interface. (3) The clinic proposes validating the model on the same database it was trained on, splitting by recording. Name the two things wrong with that plan and the corrected protocol. (4) Which of the three canonical targets (LVEF, age, potassium) demands the tightest ECG-to-label time window, and why?
Self-check
- In what precise sense is a hidden-diagnosis model not "reading the ECG better" but "reading it for a different target"? Contrast it with an arrhythmia classifier.
- Why does splitting a hidden-diagnosis dataset by recording instead of by patient inflate the reported AUC, and what is the model actually learning when you do?
- A vendor advertises AUC \(0.94\) for low-LVEF screening. Using the PPV relationship and the notion of prospective validation, list two questions you must ask before trusting it to change patient care.
What's Next
In Section 29.4, we step back to a labeling distinction that underlies every model in this chapter, including the hidden-diagnosis ones: whether the prediction belongs to a single beat or to the whole record. LVEF and potassium are record-level targets by nature, while arrhythmia often lives at the beat, and getting that granularity wrong quietly corrupts both training labels and evaluation. We formalize the choice and its consequences.