Paper · 2018-07-06 · cs.CV
Automated and Interpretable Patient ECG Profiles for Disease Detection, Tracking, and Discovery
A CNN with an HMM segments 12-lead ECGs into P, PR, QRS, ST, T and TP states. Intervals and resized waveforms form a 725-value patient profile for gradient-boosted models that estimate left ventricular mass, left atrial volume and mitral e' and detect PAH, HCM, cardiac amyloid and MVP. Author-reported: interval deviations 0.6-5.6%; disease AUROC 0.77-0.94.
Hidden Markov modelSequence labelingGradient-boosted decision treesInterpretable machine learningecgmedical-signal-processingsegmentationinterpretabilityclinical-prediction
arXivPDFCodeMarkdown15 min read
AI-compiled by claude-haiku-5-5 on 2026-11-09, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
A standard ECG is a set of wave traces, and doctors read it by looking for specific shapes and timings. Older computer programs did this with hand-written rules. This paper trains a neural network to label every moment of an ECG as belonging to one part of a heartbeat, such as the P wave or the QRS complex. A second, simpler model then cleans up those labels, using the fact that heartbeat parts come in a fixed order.
From the labelled beats, the authors build one fixed-length list of numbers per patient: some timing values and a compact copy of each part of the waveform. They feed that list to a standard tree-based model. Because the inputs are named ECG features and not raw signal, the model's important inputs can be read off and checked against known heart physiology. The same models estimate heart measurements that the paper takes from echocardiograms, and they flag several heart diseases. The authors also track patients whose ECGs were taken over several years.
The work is a single-hospital study, and it only covers ECGs of people whose heart rhythm is regular. The authors present the results as promising, not as ready for clinical use.
TL;DR
Use this card if you need an interpretable ECG feature pipeline: a CNN plus HMM for per-sample wave segmentation, a 725-value profile, and gradient-boosted regression and classification on top. The core is fully specified except for the boosting hyperparameters. The released code covers segmentation and interval estimation only, and it differs from the paper in several places (see Paper vs code). No license file is present, so only the paper's text, not the code, may guide reuse.
Problem
Heuristic ECG rules capture only a few features and miss interactions between leads § Introduction. Deep networks on raw ECG work, but they are opaque § Introduction and § Discussion. The authors want a scalable pipeline that keeps features tied to physiology, so that model outputs can be checked against known ECG correlates § Introduction and § Discussion. The assumption is that the ECG is in normal sinus rhythm: the models are trained only on such ECGs § Methods (Selection of studies for model development).
Method
Sections in the source are unnumbered. This card cites them as
[§ Methods] (subsection), [§ Results] (subsection), [§ Discussion] and
[§ Supplement] (section). Tables with a caption in the supplement are numbered
S1-S12 and figures S1-S3, as the source sets them.
Data. From the UCSF MUSE archive, 2010-2017, 12-lead, 10 s ECGs were selected § Methods (ECG Data). Sampling was 500 Hz for 60% and 250 Hz for 40% § Methods (ECG Data). Each cohort is matched to echocardiograms taken within 30 days, for left ventricular mass index (10,082 ECGs; 8,631 used), left atrial volume index (8,289; 7,053 used) and mitral annulus medial e' (4,205; 3,629 used) § Methods (Selection of studies for model development) tab. S1 tab. S2 tab. S3. Disease cohorts were PAH, HCM, cardiac amyloidosis (CA) and mitral valve prolapse (MVP). Each case was matched to up to five controls by age (10-year bins), sex, study year and race § Methods (Selection of studies for model development) tab. S4-tab. S7.
Segmentation CNN. The network takes 12 leads of 2000 samples and outputs a class for each sample among six: P wave, PR segment, QRS complex, ST segment, T wave and TP segment § Methods (Convolutional Neural Networks for ECG segmentation) § Supplement (CNN for segmentation). It is a U-Net adapted to 1-D input: it first processes each lead on its own, then merges the 12 leads with a 12x1 convolution, then runs a second contracting and expanding path § Supplement (CNN for segmentation). Training used 170 hand-labelled two-second strips, 112 from the PTB database and 58 from UCSF; each millisecond was labelled § Methods (Convolutional Neural Networks for ECG segmentation) fig. 2.
HMM refinement. The HMM has six states, one for each segment class § Methods (Enhancing ECG segmentation with HMMs). Start and transition probabilities were set from the manual labels; emission probabilities were learned from CNN output on the training data § Methods (Enhancing ECG segmentation with HMMs). A final heuristic removes complexes shorter than 10 ms § Methods (Enhancing ECG segmentation with HMMs).
Validation of segmentation. Two checks: intersection over union against manual labels, and interval agreement with the MUSE reference on 35,466 ECGs not used for training § Methods (Validation of ECG segmentation) § Results (Validation of ecgAI Machine Learning-based ECG Segmentation).
Patient profile (725 values). Five scalars: PR interval, P duration, QRS duration, heart rate and QT interval, each averaged over cycles and leads. Then three waveform blocks, each resized to 20 samples per lead by linear interpolation and averaged over cycles: PR, QRS and ST-T. Twelve leads times 20 samples times three blocks gives 720 values, so 725 in total § Methods (Deriving patient-level ECG profiles) fig. 1.
Structure and function models. One gradient-boosted regression model per target estimates left ventricular mass index, left atrial volume index and mitral e' § Methods (ECG-Derived Estimates of Cardiac structure and Function). Only ECGs whose RR, PR, QRS and QT intervals agree with the reference (mean difference below 10%) are used § Methods (ECG-Derived Estimates of Cardiac structure and Function). Binary versions set controls by the median (below it for LV mass index and left atrial volume index, above it for e') and cases by the 10th percentile on the other side § Methods (ECG-Derived Estimates of Cardiac structure and Function). Predictor rankings are in tab. S11 and tab. S12.
Disease models. Each disease has its own gradient-boosted classifier that outputs a probability from the profile § Methods (Disease detection and tracking). For tracking, patients with ECGs in two or more years get a per-year median score § Methods (Disease detection and tracking) fig. 6.
Statistics. Area under the ROC curve, with DeLong confidence intervals, was used for classification; absolute differences and Bland-Altman plots were used for the continuous targets § Methods (Statistical Methods) § Methods (ECG-Derived Estimates of Cardiac structure and Function).
# CNN-HMM segmentation [§ Methods] (Enhancing ECG segmentation with HMMs)
# Input: leads (12, 2000)
# Output: states (2000,), one of six classes per sample
def segment(leads, unet, hmm):
# 1. Score each sample for the six segment classes [§ Supplement]
scores = unet(leads) # (2000, 6)
labels = argmax(scores, axis=-1) # (2000,)
# 2. Find the most likely state path given the labels [§ Methods]
states = viterbi(labels, hmm) # (2000,)
# 3. Remove implausibly short complexes (< 10 ms) [§ Methods]
return remove_short(states, min_ms=10)# Patient-level ECG profile [§ Methods] (Deriving patient-level ECG profiles)
# Input: segmented ECG cycles, all 12 leads
# Output: profile (725,)
def build_profile(cycles):
# 1. Five scalars, averaged over cycles and leads [§ Methods]
scalars = [pr, p_dur, qrs_dur, heart_rate, qt] # 5 values
# 2. Resize each segment's voltage per lead to 20 samples [§ Methods]
pr_block = resize_per_lead(cycles.pr, 20) # (12, 20)
qrs_block = resize_per_lead(cycles.qrs, 20) # (12, 20)
stt_block = resize_per_lead(cycles.st_t, 20) # (12, 20)
# 3. Average each block over cycles, then stack everything [§ Methods]
blocks = [average_cycles(b) for b in (pr_block, qrs_block, stt_block)]
return concat(scalars, flatten(blocks)) # 5 + 720 = 725# Structure and disease models [§ Methods] (ECG-Derived Estimates ...)
# Input: profiles (N, 725); targets; gradient-boosted trees (GBM)
# Output: fitted model and cross-validated accuracy
def fit_gbm(profiles, targets):
# 1. Keep ECGs whose intervals agree within 10% [§ Methods]
keep = interval_mean_difference(profiles) < 0.10
# 2. Tune the GBM settings with 3-fold cross-validation [§ Methods]
settings = tune_gbm(profiles[keep], targets[keep], folds=3)
# 3. Fit and estimate accuracy with 5-fold cross-validation [§ Methods]
model = fit(profiles[keep], targets[keep], settings)
scores = cross_validate(settings, profiles[keep], targets[keep], folds=5)
return model, scoresHyperparameters
| Setting | Value | Source | Notes |
|---|---|---|---|
| Optimizer | Adam | § Supplement (CNN for segmentation) | Code also uses Adam ecgHMM.py |
| Learning rate | 1e-5 | § Supplement (CNN for segmentation) | Same in config.json |
| Mini-batch size | 5 | § Supplement (CNN for segmentation) | Code config: 4 config.json |
| Weight decay | 1e-7 on all network weights | § Supplement (CNN for segmentation) | Code config: 1e-8 config.json; see Paper vs code |
| Dropout | 0.5 on the final convolution block | § Supplement (CNN for segmentation) | Code config: 0.5 config.json; probability vs keep-probability not stated |
| Training length | 500 epochs | § Supplement (CNN for segmentation) | Same in config.json |
| Input | 12 leads x 2000 samples | § Supplement (CNN for segmentation) | Same in config.json |
| Filter sizes | 19, 15, 11, then 9 | § Supplement (CNN for segmentation) | Same in config.json |
| Output classes | 6 | § Methods (Convolutional Neural Networks for ECG segmentation) | Same in config.json |
| Segmentation training set | 170 strips (112 PTB, 58 UCSF) | § Methods (Convolutional Neural Networks for ECG segmentation) | Two-second strips, 1 ms labels |
| Segmentation CV | 5-fold | § Supplement (CNN for segmentation) | Accuracy assessment |
| Training hardware and time | one GTX 1080, about 4 hours | § Supplement (CNN for segmentation) | Not otherwise stated |
| Short-complex filter | below 10 ms removed | § Methods (Enhancing ECG segmentation with HMMs) | Form of the heuristic not stated |
| HMM start and transition probabilities | Set from manual labels | § Methods (Enhancing ECG segmentation with HMMs) | Values not stated in the paper; the code hard-codes a 6x6 matrix ecgHMM.py |
| Interval agreement filter | mean difference below 10% | § Methods (ECG-Derived Estimates of Cardiac structure and Function) | Across RR, PR, QRS and QT |
| Profile resolution | 20 samples per segment per lead | § Methods (Deriving patient-level ECG profiles) | Binned to 5 for interpretation § Methods (ECG-Derived Estimates ...) |
| GBM settings | Not stated | § Methods (ECG-Derived Estimates of Cardiac structure and Function) | Trees, depth, shrinkage and tuning grid not stated; R caret GBM |
| GBM tuning CV | 3-fold | § Methods (ECG-Derived Estimates of Cardiac structure and Function) | Automated; search space not stated |
| Accuracy CV | 5-fold | § Methods (ECG-Derived Estimates of Cardiac structure and Function) | |
| Dichotomy cut points | Median for controls; 10th percentile for cases | § Methods (ECG-Derived Estimates of Cardiac structure and Function) | Direction for each target is only partly spelled out; see Pitfalls |
| PAH tracking threshold | 80% sensitivity, 90% specificity | fig. 6 | The score value at this threshold is not stated |
| Software | R 3.3.2 or python 2.7; TensorFlow for CNN; scikit-image for resizing | § Methods (Statistical Methods) |
Results
Author-reported. Setup: UCSF MUSE ECGs and echocardiogram or diagnosis labels from a single centre. No external baseline is given for the headline numbers. The authors say results are not directly comparable to earlier ECG studies § Discussion.
| Setting | Metric | Baseline | This paper | Source |
|---|---|---|---|---|
| Segmentation, 6 classes | Intersection over union (0-100) | Not reported | P 91, PR 85, QRS 94, ST 88, T 91, TP 92 | § Results (Validation of ecgAI Machine Learning-based ECG Segmentation) |
| Intervals vs MUSE (35,466 ECGs) | Median absolute deviation, % of reference | MUSE itself | Heart rate 0.6, PR 3.0, QRS 5.6, QT 4.4 | tab. 2 |
| Intervals vs MUSE | 75th and 95th percentile of deviation, % | Not reported | Heart rate 1.5 / 9.8, PR 5.9 / 27.4, QRS 9.7 / 18.7, QT 6.3 / 23.6 | tab. 2 |
| Interval correlation | rho (type not stated) | Not reported | 0.77 to 0.98 | § Results (Validation ...) fig. 3 |
| LV mass index (n = 8,631) | Median absolute deviation, % of echo | Echo | 16.5 | tab. 2 |
| Mitral e' (n = 3,629) | Median absolute deviation, % of echo | Echo | 19.1 | tab. 2 |
| Left atrial volume index (n = 7,053) | Median absolute deviation, % of echo | Echo | 22.9 | tab. 2 |
| LV hypertrophy (binary) | AUROC (95% CI) | Not reported | 0.87 (0.86-0.89) | § Results (ecgAI Performance to Quantify Cardiac Structure) fig. 4 |
| Diastolic dysfunction (binary) | AUROC (95% CI) | Not reported | 0.84 (0.82-0.86) | § Results (ecgAI Performance to Quantify Cardiac Structure) fig. 4 |
| Left atrial enlargement (binary) | AUROC (95% CI) | Not reported | 0.62 (0.60-0.64) | § Results (ecgAI Performance to Quantify Cardiac Structure) |
| PAH detection | AUROC (95% CI) | Not reported | 0.94 (0.93-0.95) | § Results (ecgAI Performance for Cardiac Disease Detection) fig. 5 |
| HCM detection | AUROC (95% CI) | Not reported | 0.91 (0.90-0.92) | § Results (ecgAI Performance for Cardiac Disease Detection) fig. 5 |
| Cardiac amyloid detection | AUROC (95% CI) | Not reported | 0.86 (0.82-0.89) | § Results (ecgAI Performance for Cardiac Disease Detection) fig. 5 |
| MVP detection | AUROC (95% CI) | Not reported | 0.77 (0.76-0.78) | § Results (ecgAI Performance for Cardiac Disease Detection) fig. 5 |
| Serial PAH tracking | Qualitative | None | Three patients with score swings, matched to ECG changes | § Results (Serial ECGs Analysis ...) fig. 6 |
Case and control counts for the disease models are in tab. S4-tab. S7. The LVH, diastolic dysfunction and left atrial enlargement models use tab. S8-tab. S10. Top predictors per model are in tab. S11 and tab. S12.
Paper vs code
The official repository is https://bitbucket.org/rahuldeo/ecgai, linked from the paper
§ Methods (Materials and Methods, first paragraph). It is public and its owner is
an author. It has no LICENSE file, so code_license is recorded as none. No code was
copied. The commit above is from the repository listing at the time of compilation.
Method of checking. The repository was read through WebFetch, not cloned, because
the remote is not GitHub. The files read were config.json, ecgHMM.py and the
README. The listing also shows src/run.py, src/run_rcd.py, src/util.py and
load_data.pyc. These were not read. Line numbers from the fetch were not checked
against a local copy, and some lines differ by one between two fetches. The citations
below therefore name the file and function, and give line numbers only where the two
fetches agreed.
Discrepancies found:
- Weight decay: paper 1e-7 § Supplement (CNN for segmentation);
config.jsonsets 1e-8. - Mini-batch size: paper 5 § Supplement (CNN for segmentation);
config.jsonsets 4. - Weight decay scope: paper applies it to all weights. The loss in
ecgHMM.pyadds an L2 term over trainable variables, filtered by a batch-normalisation name test (in the model's loss construction; truncated in the fetch). The paper does not mention batch normalisation. - Emission probabilities: paper says they were learned on the training data
§ Methods (Enhancing ECG segmentation with HMMs). The code builds the emission matrix
from confusion counts over
x_test(module-level code aroundecgNumDict,ecgHMM.py). That is the held-out split, so the emission matrix is fitted on test data. - HMM transition matrix: paper gives no values § Methods (Enhancing ECG segmentation with HMMs).
The code hard-codes a 6x6 matrix that keeps each state most of the time and moves
forward in the order P, PR, QRS, ST, T, TP (
ecgHMM.py,hmm_modelsetup, around lines 480-486). - Undocumented filters: the code smooths each input window with a 20-sample box
filter (
ecgHMM.py,smoothRows) and applies three "bridging" passes to the HMM output, with windows of 10 and 15 samples and fractions 0.6 and 0.9 (bridgeAcross,bridgeUp,bridgeAcrossFinal). The paper describes only the 10 ms rule. - Aggregation: paper says averages over cycles § Methods (Deriving patient-level ECG
profiles). The code takes
np.nanmedianover cycles for both scalars and waveform blocks (ecgHMM.py, around the final vector assembly). - Windowing: the paper does not say how a 10 s ECG is windowed for inference. The code
resamples each lead to 10,000 samples by nearest-neighbour interpolation, then runs
2000-sample windows with a 500-sample step over the first 8,500 samples
(
ecgHMM.py,expandLeadand the main loop). - Waveform blocks: the paper's ST-T block § Methods (Deriving patient-level ECG profiles) matches the code's ST run plus the following T run. The code's P-PR block starts at the P onset, not the PR segment alone.
- The released script processes one hard-coded example file (
ecgHMM.py, thefilenamevariable). It is a demonstration, not a training pipeline. - Model code: the segmentation CNN is in
ecgHMM.py. The gradient-boosted and disease code is not in the files read. The paper's Rcaretmodels are not confirmed to be in the repository. - Model weights: the README links a Dropbox folder for the trained model. That link is not part of the repository, and its licence is unknown. It was not used.
- Framework: the code uses TensorFlow 1.x-style calls (
tf.train.AdamOptimizer,tf.nn.dropoutwith a keep argument), while the paper says only "TensorFlow".
Pitfalls
- Architecture counts are not reconciled. The main text says 32 convolutional layers, 5 max-pool and 3 deconvolutional layers § Methods (Convolutional Neural Networks for ECG segmentation). The supplement describes blocks of three convolutions each, with pooling after the first five blocks § Supplement (CNN for segmentation). Use the supplement's block list and the config's filter sizes to build the network, and check the layer count yourself.
- Dropout meaning. The paper says "dropout with probability 0.5". In the TensorFlow
1.x API, the second argument is a keep probability. The code passes
config.dropout(0.5) to the decoder blocks. Confirm which convention you implement. - Batch normalisation appears in the code and is absent from the paper. Leaving it out will change training dynamics.
- Test-set emissions. Emissions come from
x_testin the code. A faithful reimplementation follows the paper (training data) but gets different segmentation scores than the released code. Expect the released numbers to be optimistic. - Interval extraction depends on the HMM transition matrix, the three bridging filters and the 20-sample input smoothing, none of which the paper describes. Expect interval errors when you rebuild only the paper's version.
- The interval-based filter keeps only ECGs whose four intervals agree with MUSE within 10%. This subset is used to fit the models. The paper says the subset had no appreciable difference in patient characteristics tab. S1-tab. S3. That check does not show how much data was dropped, which is not stated.
- Dichotomy cut points. The text says controls are below the median for LV mass index and left atrial volume, and above it for e'. Cases are "above or below the 10th percentile". The direction for each target is not spelled out. Pick the reading that matches the target's clinical meaning and document the choice.
- Left atrial volume prediction is weak in this paper (AUROC 0.62 for enlargement). The authors attribute this to the ECG missing large atrial volumes § Results (ecgAI Performance to Quantify Cardiac Structure). Do not expect it to transfer.
- Table and figure labels. In the disease figure, panel F is used for MVP ROC and for a variable-importance plot, and the caption lists violin panels G to I fig. 5. The text cites a supplementary figure for MVP fig. S2. Verify panels against the rendered PDF before citing them.
- Lead attribution. The text gives "1.4 segments 12-16" under lead V1 for PAH, but tab. S12 assigns 1.4 to lead I, and lead V1 segments 12-16 is 1.6. Trust the table.
- Typo in the control counts. The 2017 control cell of the left atrial enlargement table reads "1206 (986)", which cannot be a valid count and percentage pair tab. S10. Check the rendered table before using it.
- Cohort and label scope. Single centre; sinus rhythm only; the disease labels were partly defined by chart review and a second cardiologist's over-read. Expect different label quality elsewhere § Methods (Selection of studies for model development).
- Tracking threshold. The 80% sensitivity and 90% specificity point is drawn in fig. 6 but its score is not given. The three highlighted trajectories are illustrative, not a validated cohort result.
- Segmentation training data is small (170 strips) and the labels are per millisecond and hand-made. The paper does not report a repeat with other labellers.
- Statistics. AUROC confidence intervals use DeLong § Methods (Statistical Methods). Only one value per patient is used in pairwise comparisons § Methods (Statistical Methods). The paper does not say whether the disease models were evaluated on the matched controls alone or on other sampling schemes.
Lineage
- Builds on: the U-Net architecture (Ronneberger et al., 2015; cited in the paper as Ronneberger:2015vw), adapted to 1-D input § Supplement (CNN for segmentation). Standard HMM formalism, cited to Rabiner § Methods (Enhancing ECG segmentation with HMMs). Gradient-boosted trees for the regression and classification models § Methods (ECG-Derived Estimates of Cardiac structure and Function).
- Compared against: the authors name several ECG deep-learning and feature-based studies, but do not compare numbers directly § Discussion.
- Companion work: the authors' echocardiogram segmentation pipeline (cited in the paper as Zhang:wd), which the ECG segmentation builds on § Methods (Selection of studies for model development) § Methods (Convolutional Neural Networks for ECG segmentation).
- Superseded by: not known from content in this wiki.
Source and license
Adapted from “Automated and Interpretable Patient ECG Profiles for Disease Detection, Tracking, and Discovery” by Geoffrey H. Tison, Jeffrey Zhang, Francesca N. Delling, Rahul C. Deo (arXiv:1807.02569), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://bitbucket.org/rahuldeo/ecgai at commit 99bdaa94eaa5 (none (no LICENSE file in the repository)). Any quoted code is shown under that license.