Chapman-Shaoxing ECG Database (10,646 patients)

Open Completed

Quick facts

Format12-lead · 10 s · 500 Hz · CSV (µV)
Patients10,646
Records10,646
Leads12
LicenseCC0 1.0
OriginChapman University; Shaoxing People's Hospital — China / USA

Overview

The original figshare release of the Chapman-Shaoxing database: 10,646 twelve-lead ECGs, one per patient, each 10 seconds at 500 Hz. Signals are CSV rather than WFDB — one file per record, 5,000 rows × 12 lead columns with a header, in the standard lead order — and are stored in microvolts, which ECGBench converts to millivolts via signal_unit_scale: 0.001.

Labels are unusually rich for an open ECG dataset: a single-label Rhythm class (11 values), a space-separated multi-label Beat annotation (57 codes), age and sex, and eleven automated measurements — ventricular and atrial rate, QRS duration, QT and QTc, R and T axes, QRS count, and the QRS/T fiducial offsets. A denoised copy of every signal ships alongside as ECGDataDenoised/.

The collection is six separate files and its metadata is .xlsx, so acquisition needs examples/download_chapman_figshare.py rather than ECGBench’s single-archive auto-download.

Rhythm distribution (all 10,646 records)

CodeRhythmRecords
SBSinus bradycardia3,889
SRSinus rhythm1,826
AFIBAtrial fibrillation1,780
STSinus tachycardia1,568
SVTSupraventricular tachycardia587
AFAtrial flutter445
SASinus irregularity399
ATAtrial tachycardia121
AVNRTAV node reentrant tachycardia16
AVRTAV reentrant tachycardia8
SAAWRSinus atrium to atrial wandering rhythm7

About those counts

These are recomputed from the shipped Diagnostics.xlsx, and they match the paper’s figures — 10,646 records over 11 rhythm classes. Rhythm is single-label, so the counts sum exactly to the record total.

Beat is a different quantity: space-separated and multi-label, averaging 0.84 codes per record with 5,419 records carrying NONE. Do not add the two tables together.

Note the class imbalance: the rarest rhythm (SAAWR) has 7 records, fewer than the 10 folds, so StratifiedKFold warns and those records cannot appear in every fold. That is a property of the data, not a splitting fault.

Validation summary (500 Hz)

VersionRecordsNote
original10,646all records, with is_valid + quality_issues
clean10,60799.6% pass rate
excluded3938 amplitude outliers, 49 flat-lead issues (overlapping)

Fetching and building the splits

# Six files, 2.8 GB. md5-verified, resumable, converts the .xlsx metadata.
python examples/download_chapman_figshare.py --dest /path/to/chapman-figshare/

ecgbench splits --dataset chapman_shaoxing --data-path /path/to/chapman-figshare/

Loading with ECGBench

from ecgbench import ECGDataset

ds = ECGDataset(
    "chapman_shaoxing",
    split="train",
    version="clean",
    data_path="/path/to/chapman-figshare/",
    labels=True,
)

sample = ds[0]
sample["signal"].shape          # (12, 5000), float32, millivolts
sample["labels"]["Rhythm"]      # 'AFIB'
sample["labels"]["Beat"]        # 'LVHV'  (space-separated, multi-label)
sample["labels"]["QTCorrected"] # 454

# Signals are stored in microvolts; signal_unit_scale converts them to mV,
# so the tensor above is already in mV. Ask for microvolts back with
# units="uV", and select leads by name:
two = ECGDataset("chapman_shaoxing", split="train",
                 data_path="/path/to/chapman-figshare/",
                 leads=["II", "V5"], units="uV")
two[0]["signal"].shape  # (2, 5000)
two.units               # 'uV'