Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BTTR for atrial fibrillation in sinus-rhythm ECG (PTB-XL)

Reference pipeline for the paper "An interpretable tensor model for identifying atrial fibrillation in sinus-rhythm ECG: block-term tensor regression on PTB-XL, benchmarked against deep and foundation models" (Cornelissen & Faes). It applies real Block-Term Tensor Regression (Faes et al., the vendored bttrlib/) to PTB-XL and benchmarks it, under identical patient-grouped folds, against a clinical-feature logistic regression, an Attia-style 1-D CNN, an unsupervised CP/PARAFAC surrogate, and frozen HuBERT-ECG foundation-model embeddings. The glass-box BTTR matches or exceeds every baseline at no accuracy cost and yields directly inspectable (time x lead) weight maps. NB: PTB-XL has no outcome follow-up, so the AF-in-SR task is concurrent-association identification, not future-onset prediction.

BTTR is genuine block-term tensor regression (not a CP surrogate)

bttrlib/bttr.py + bttrlib/ace.py implement supervised, deflation-based BTTR: a mode-1 cross-covariance tensor between X and the +/-1 label is Tucker-decomposed each iteration; Automatic Component Extraction (ACE) selects each block's multilinear rank by a BIC sweep; a score vector is SVD-extracted and both X and the target are deflated before the next block, for K blocks. With enforce_rank_1=True each block is a readable (time x lead) weight map. This is structurally distinct from the unsupervised parafac CP surrogate in core/baselines.py (a separate baseline, not the method). bttrlib/ is vendored - never algorithm-edited (one tensorly>=0.8 compat shim only).

Layout (this is a package - run drivers from this directory)

  • bttrlib/ - vendored real BTTR: bttr.py (deflation loop), ace.py (automatic rank), imported as a top-level package (from bttrlib import BTTR).
  • core/ - shared library: config.py (paths + cohort/BTTR/tensorisation settings; edit PTBXL_DIR), data.py (PTB-XL loading), preprocess.py (wavelet denoise + tensorisation: window / median_beat / median_beat_rr), bttr_model.py (sklearn-style BTTRClassifier + block_maps()), baselines.py (clinical features + CP surrogate), evaluate.py (patient-grouped CV + bootstrap CI).
  • experiments/ - the keeper drivers that produce the paper numbers.
  • paper.py - the single entry point that runs the whole flow.
  • results/ - generated CSVs + block-map .npz/.png (regenerated by paper.py).

The algorithm lives in bttrlib/ (vendored BTTR) wrapped by core/bttr_model.py; the benchmark is driven by experiments/.

Data (public)

PTB-XL 1.0.3 (PhysioNet, DOI 10.13026/x4td-x982), used at 100 Hz. Open access (PhysioNet account, no DUA). Fetch selectively from the PhysioNet S3 open mirror s3://physionet-open/ptb-xl/: ptbxl_database.csv, scp_statements.csv, and the cohort records100/ files (a few MB; the full 1.8 GB zip is not needed). Set PTBXL_DIR in core/config.py to point at the download. HuBERT-ECG foundation-model weights (public; DOI 10.1101/2024.11.14.24317328) are fetched by the HuBERT step.

Reproduce

pip install -r requirements.txt
python paper.py            # runs the full flow; writes results/ (copy the two used figures into the manuscript figures dir)

Individual steps run as python -m experiments.<name>. The HuBERT step needs transformers + torch + network (downloads the weights once); the CNN baseline needs torch; both are benchmark baselines, not dependencies of BTTR.

Script -> result -> manuscript map

Script Produces Manuscript element
experiments/final_eval.py results/final_table.csv Table 1 (BTTR vs CP vs CNN vs HuBERT vs clinical)
experiments/plot_forest.py results/forest_auroc.png the forest figure
experiments/paired_test.py stdout Table 2 (paired differences) + Table 3 CNN rows
experiments/harden_afsr.py results/harden_afsr.csv Table 3 BTTR aligned/unaligned rows + the K-sweep; also the cohort builder used by the others
experiments/run_analyses.py results/analyses.csv map-stability r = 0.88
experiments/interpret_afsr.py results/interpret_afsr_afibonly_blocks.{npz,png} (+ secondary) the block-map figure
experiments/weight_fractions.py results/weight_fractions.csv the temporal weight fractions (atrial/QRS/ST/T)
experiments/run.py --task detect results/results_detect.csv the detection-context numbers
experiments/nested_afsr.py results/nested_afsr.csv the nested-CV robustness cross-check

experiments/attia_cnn.py (the CNN baseline, cnn_oof), hubert_probe.py (HuBERT embeddings + probe), and interpret.py (the block-map export helper) are imported by the drivers above.

About

Interpretable block-term tensor regression (BTTR) for identifying atrial fibrillation in sinus-rhythm ECG on PTB-XL, benchmarked against clinical, CNN, CP, and foundation-model baselines.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages