async def score_record(self, record, annotation): """Obtain detector performance for an annotated record. Parameters ---------- record : 1d array The raw physiological record. annotation : 1d array The manual extrema annotations. Returns ------- precision : float The detectors precision on the record given the tolerance. sensitivity : float The detectors sensitivity on the record given the tolerance. """ detector_annotation = self.detector(record, self.sfreq) comparitor = compare_annotations(detector_annotation, annotation, self.tolerance) tp = comparitor.tp fp = comparitor.fp fn = comparitor.fn sensitivity = tp / (tp + fn) precision = tp / (tp + fp) return precision, sensitivity
def extractRpeaks(rdnames, rpeak_lead, samplefrom=0, sampleto='end', verbose=False): allsymbols = [] for rdname in rdnames: print(rdname) sig, fields = wfdb.rdsamp('mitdb/'+rdname, channels='all', sampfrom=samplefrom, sampto=sampleto) ann_ref = wfdb.rdann('mitdb/'+rdname,'atr', sampfrom=samplefrom, sampto=None if sampleto=='end' else sampleto) peak_channel = 0 if rpeak_lead in fields['sig_name']: peak_channel = fields['sig_name'].index(rpeak_lead) else: continue xqrs = processing.XQRS(sig=sig[:,peak_channel], fs=fields['fs']) xqrs.detect() acts = xqrs.qrs_inds comparitor = processing.compare_annotations(ref_sample=ann_ref.sample[1:], test_sample=xqrs.qrs_inds, window_width=int(0.1 * fields['fs']), signal=sig[:,peak_channel]) if verbose: comparitor.print_summary() matched_inds = comparitor.matching_sample_nums outpath = 'mitdb/'+rdname + '.Rpeaks' with open(outpath, 'wb') as handle: pickle.dump({'acts':acts, 'matched_inds':matched_inds, 'anns': ann_ref.symbol[1:]}, handle)
def test_plot(self): record_name = self.mitdb + "100" sig, fields = wfdb.rdsamp(record_name, channels=[0]) print(sig.__class__, sig) print(fields.__class__, fields) ann_ref = wfdb.rdann(record_name, 'atr') xqrs = processing.XQRS(sig=sig[:, 0], fs=fields['fs']) print(xqrs) xqrs.detect() comparitor = processing.compare_annotations(ann_ref.sample[1:], xqrs.qrs_inds, int(0.1 * fields['fs']), sig[:, 0]) comparitor.print_summary() comparitor.plot()
def test_xqrs(self): """ Run xqrs detector on record 100 and compare to reference annotations """ sig, fields = wfdb.rdsamp('sample-data/100', channels=[0]) ann_ref = wfdb.rdann('sample-data/100','atr') xqrs = processing.XQRS(sig=sig[:,0], fs=fields['fs']) xqrs.detect() comparitor = processing.compare_annotations(ann_ref.sample[1:], xqrs.qrs_inds, int(0.1 * fields['fs'])) assert comparitor.sensitivity > 0.99 assert comparitor.positive_predictivity > 0.99
def calc_ECG_annotation(annotation_GT, reconstructed, fs=360): qrs_inds = processing.xqrs_detect(sig=reconstructed, fs=fs, verbose=True) # Compare detected qrs complexes to reference annotation. # Note, first sample in 100.atr is not a qrs.ֶ comparitor = processing.compare_annotations(ref_sample=annotation_GT, test_sample=qrs_inds, window_width=int(0.1 * fs), signal=reconstructed) F_mesure = 2 * (comparitor.positive_predictivity * comparitor.sensitivity) / (comparitor.positive_predictivity + comparitor.sensitivity) return [ len(annotation_GT), comparitor.n_test, comparitor.tp, comparitor.fp, comparitor.fn, comparitor.positive_predictivity, comparitor.sensitivity, F_mesure ]
def test_xqrs(self): """ Run xqrs detector on record 100 and compare to reference annotations """ sig, fields = wfdb.rdsamp('sample-data/100', channels=[0]) ann_ref = wfdb.rdann('sample-data/100','atr') xqrs = processing.XQRS(sig=sig[:,0], fs=fields['fs']) xqrs.detect() comparitor = processing.compare_annotations(ann_ref.sample[1:], xqrs.qrs_inds, int(0.1 * fields['fs'])) assert comparitor.specificity > 0.99 assert comparitor.positive_predictivity > 0.99 assert comparitor.false_positive_rate < 0.01
def benchmark_record(record, sampling_rate, annotation, tolerance, detector): """Obtain detector performance for an annotated record. Parameters ---------- record : array The raw physiological record. sampling_rate: int The sampling rate of the record in Hertz. annotation : array The manual extrema annotations. tolerance : int Maximum difference in millisecond that is permitted between the manual annotation and the annotation generated by the detector. detector : function A function that takes a physiological record as first positional argument as well as a `sampling_rate` keyword argument. Returns ------- precision : float The detectors precision on the record given the tolerance. sensitivity : float The detectors sensitivity on the record given the tolerance. """ detector_annotation = detector(record, sampling_rate=sampling_rate) comparitor = compare_annotations(detector_annotation, annotation, tolerance) tp = comparitor.tp fp = comparitor.fp fn = comparitor.fn sensitivity = tp / (tp + fn) precision = tp / (tp + fp) return precision, sensitivity
import matplotlib.pyplot as plt import wfdb from wfdb import processing sig, fields = wfdb.rdsamp('100', channels=[0], sampto=15000, pb_dir='mitdb/') ann_ref = wfdb.rdann('100', 'atr', sampto=15000, pb_dir='mitdb/') #使用XQRS算法 xqrs = processing.XQRS(sig=sig[:, 0], fs=fields['fs']) xqrs.detect() #这里还可以直接使用xqrs_detection #qrs_inds=processing.xqrs_detect(sig=sig[:,0], fs=fields['fs']) #下面进行算法的结果和注释中的结果相对比 #注意:在100.atr中的qrs注释第一个数是18,而18这个位置上并没有峰值,真正的第一个峰值是在第二个数77开始的所以是[1:] comparitor = processing.compare_annotations(ref_sample=ann_ref.sample[1:], test_sample=xqrs.qrs_inds, window_width=int(0.1 * fields['fs']), signal=sig[:, 0]) #输出结果 comparitor.print_summary() fig = comparitor.plot(title='XQRS detected QRS vs reference annotations', return_fig=True) # display(fig[0]) plt.show(fig[0]) #这一步必须加,不然图片会一闪而逝
ecg = np.ravel(pd.read_csv(record, sep=" ", usecols=[1], header=None)) except FileNotFoundError: print(f"no ECG available for {record}") continue try: manupeaks = np.ravel(pd.read_csv(annotation, header=None)) except FileNotFoundError: print(f"no annotations available for {annotation}") continue algopeaks = ecg_peaks(ecg, sfreq) if algopeaks.size > 1: comparitor = compare_annotations(manupeaks, algopeaks, tolerance) tp = comparitor.tp fp = comparitor.fp fn = comparitor.fn # plt.figure() # plt.plot(ecg) # plt.scatter(manupeaks, ecg[manupeaks], c="m") # plt.scatter(algopeaks, ecg[algopeaks], c='g', marker='X', s=150) sensitivity.append(float(tp) / (tp + fn)) precision.append(float(tp) / (tp + fp)) print(f"sensitivity = {sensitivity[-1]}, precision = {precision[-1]}") print(f"mean precision = {np.mean(precision)}, std precision = {np.std(precision)}") print(f"mean sensitivity = {np.mean(sensitivity)}, std sensitivity = {np.std(sensitivity)}")
tolerance = int(np.rint(.05 * sfreq)) # tolerance must be in samples for wfdb print( f"Setting tolerance for match between algorithmic and manual annotation" f" to {tolerance} samples, corresponding to 50 milliseconds at a sampling rate of {sfreq}." ) sensitivity = [] precision = [] for subject in subjects: data = np.loadtxt(os.path.join(record_dir, subject[0])) annotation = np.loadtxt(os.path.join(annotation_dir, subject[1])) peaks = ppg_peaks(data, sfreq) comparitor = compare_annotations(peaks, annotation, tolerance) tp = comparitor.tp fp = comparitor.fp fn = comparitor.fn sensitivity.append(float(tp) / (tp + fn)) precision.append(float(tp) / (tp + fp)) print(f"sensitivity = {sensitivity[-1]}, precision = {precision[-1]}") print( f"mean precision = {np.mean(precision)}, std precision = {np.std(precision)}" ) print( f"mean sensitivity = {np.mean(sensitivity)}, std sensitivity = {np.std(sensitivity)}" )
f"Setting tolerance for match between algorithmic and manual annotation" f" to {tolerance} sample(s), corresponding to {tolerance / sfreq} seconds" f" at a sampling rate of {sfreq}.") sensitivity = [] precision = [] for subject in data_dir.iterdir(): f = h5py.File(subject, "r") record = np.ravel(f["signal"]["pleth"]["y"]) annotation = np.ravel(f["labels"]["pleth"]["peak"]["x"]) peaks = ppg_peaks(record, sfreq) comparitor = compare_annotations(annotation, peaks, tolerance) tp = comparitor.tp fp = comparitor.fp fn = comparitor.fn sensitivity.append(tp / (tp + fn)) precision.append(tp / (tp + fp)) print(f"\nResults {subject}") print("-" * len(str(subject))) print(f"sensitivity = {sensitivity[-1]}") print(f"precision = {precision[-1]}") print(f"\nAverage results over {len(precision)} records") print("-" * 31) print(