主要内容

小波时间散射在心电信号分类中的应用

这个例子展示了如何使用小波时间散射和支持向量机分类器对心电图信号进行分类。万博1manbetx在小波散射中,数据通过一系列小波变换、非线性和平均来传播,以产生时间序列的低方差表示。小波时间散射产生的信号表示对输入信号的移位不敏感,而不牺牲类的可分辨性。您必须有小波工具箱™和统计和机器学习工具箱™来运行这个示例。本例中使用的数据可以从生理网.在这个例子中,您可以找到解决这个分类问题的深度学习方法基于小波分析和深度学习的时间序列分类在这个例子中是机器学习的方法基于小波特征和支持向量机的信号分类万博1manbetx

数据描述

本例使用了三组或三类人的ECG数据:心律失常者、充血性心力衰竭者和窦性心律正常者。该示例使用了来自三个PhysioNet数据库的162个ECG记录:MIT-BIH心律失常数据库[3] [5],MIT-BIH正常窦性心律数据库[3]BIDMC充血性心力衰竭数据库[2][3]。总共有来自心律失常患者的96次录音,来自充血性心力衰竭患者的30次录音,来自正常窦性心律患者的36次录音。目标是训练分类器来区分心律失常(ARR),充血性心力衰竭(CHF)和正常窦性心律(NSR)。

下载数据

第一步是从GitHub库.单击,下载数据代码并选择下载ZIP.保存文件physionet_ECG_data-main.zip在您有写权限的文件夹中。本例的说明假设您已经将文件下载到临时目录(tempdir在MATLAB中)。如果选择在不同的文件夹中下载数据,请修改解压缩和加载数据的后续说明tempdir

该文件physionet_ECG_data-main.zip包含

  • ECGData.zip

  • README.md

和ECGData.zip包含

  • ECGData.mat

  • Modified_physionet_data.txt

  • License.txt。

ECGData.mat持有s the data used in this example. The .txt file, Modified_physionet_data.txt, is required by PhysioNet's copying policy and provides the source attributions for the data as well as a description of the pre-processing steps applied to each ECG recording.

加载文件

如果您按照上一节中的下载说明进行下载,那么输入以下命令解压缩这两个存档文件。

解压缩(fullfile (tempdir,“physionet_ECG_data-main.zip”), tempdir)解压缩(fullfile (tempdir,“physionet_ECG_data-main”“ECGData.zip”),...fullfile (tempdir“ECGData”))

解压ECGData.zip文件后,将数据加载到MATLAB中。

负载(fullfile (tempdir“ECGData”“ECGData.mat”))

ECGData是具有两个字段的结构数组:数据而且标签数据是一个162 × 65536的矩阵,其中每一行都是以128赫兹采样的心电图记录。每个ECG时间序列的总持续时间为512秒。标签是一个162 × 1单元阵列的诊断标签,每行一个数据.三种诊断类型是:“ARR”(心律失常),“CHF”(充血性心力衰竭)和“NSR”(正常窦性心律)。

创建培训和测试数据

随机将数据分成两组——训练数据集和测试数据集。辅助函数helperRandomSplit执行随机分裂。helperRandomSplit接受训练数据所需的分割百分比ECGData.的helperRandomSplit函数输出两个数据集以及每个数据集的一组标签。每行trainData而且testData是心电信号。的每个元素trainLabels而且testLabels包含数据矩阵对应行的类标签。在这个例子中,我们随机将每个类中70%的数据分配给训练集。剩下的30%用于测试(预测),并分配给测试集。

Percent_train = 70;[trainData, testData trainLabels testLabels] =...helperRandomSplit (percent_train ECGData);

有113条记录trainData设置和49个记录在testData.通过设计,训练数据包含69.75%(113/162)的数据。回想一下,ARR类代表59.26%的数据(96/162),CHF类代表18.52% (30/162),NSR类代表22.22%(36/162)。检查每个类在训练集和测试集中的百分比。每个类别的百分比与数据集中的整体类别百分比一致。

Ctrain = countcats(categorical(trainLabels))./numel(trainLabels).*100
Ctrain =3×159.2920 18.5841 22.1239
Ctest = countcats(categorical(testLabels))./numel(testLabels).*100
ct =3×159.1837 18.3673 22.4490

情节样品

绘制4个随机选择的记录的前几千个样本ECGData.辅助函数helperPlotRandomRecords这是否。helperPlotRandomRecords接受ECGData和一个随机种子作为输入。初始种子设置为14,以便绘制每个类的至少一条记录。你可以执行helperPlotRandomRecordsECGData作为唯一的输入参数,你可以多次获得与每个类别相关的ECG波形的多样性。您可以在本例末尾的支持函数一节中找到这个函数和所有辅助函数的源代码。万博1manbetx

helperPlotRandomRecords (ECGData 14)

小波时间散射

在小波时间散射网络中指定的关键参数是时不变的尺度,小波变换的数量,以及每个小波滤波器组中每八度的小波数。在许多应用中,两个滤波器组的级联足以达到良好的性能。在这个例子中,我们用默认滤波器组构造了一个小波时间散射网络:第一个滤波器组中每八度有8个小波,第二个滤波器组中每八度有1个小波。不变性尺度设置为150秒。

N = size(ECGData.Data,2);小波散射(“SignalLength”N“InvarianceScale”, 150,“SamplingFrequency”, 128);

您可以用下面的方法可视化两个滤波器组中的小波滤波器。

[fb,f,filterparams] = filterbank(sn);图subplot(211) plot(f,fb{2}.psift) xlim([0 128])网格标题(“第一滤波器组小波滤波器”);Subplot (212) plot(f,fb{3}.psift) xlim([0 128])网格标题(“第二滤波器组小波滤波器”);包含(“赫兹”);

为了演示不变性尺度,获得尺度函数的傅里叶反变换,并将其置于0秒的时间中心。两条垂直的黑线表示-75秒和75秒的边界。此外,从第一个滤波器组绘制最粗尺度(最低频率)小波的实部和虚部。注意,最粗尺度的小波不超过由尺度函数的时间支持决定的不变尺度。万博1manbetx这是小波时间散射的一个重要性质。

图;Phi = ifftshift(ifft(fb{1}.phift));psiL1 = ifftshift(ifft(fb{2}.psift(:,end)));T = (-2^15:2^15-1).*1/128;Scalplt = plot(t,);持有网格ylim(1.6[-1.5军医的军医]);Plot ([-75 -75],[-1.5e-4],“k——”);Plot ([75 75],[-1.5e-4 1.6e-4],“k——”);包含(“秒”);ylabel (“振幅”);wavplt = plot(t,[real(psiL1) imag(psiL1)]);图例([scalplt wavplt(1) wavplt(2)],{“扩展功能”“Wavelet-Real部分”“Wavelet-Imaginary部分”});标题({“扩展功能”“最粗尺度小波第一滤波器组”})举行

在构建散射网络后,将训练数据的散射系数作为矩阵得到。当你奔跑featureMatrix对于多个信号,每一列都被视为单个信号。

scat_features_train = featureMatrix(sn,trainData');

的输出featureMatrix这里是409 × 16 × 113。张量的每一页,scat_features_train,为一个信号的散射变换。基于尺度函数的带宽,对小波散射变换进行关键的时间下采样。在这种情况下,409个散射路径中的每一个都有16个时间窗口。

为了得到与SVM分类器兼容的矩阵,将多信号散射变换重塑为每一列对应一个散射路径,每一行是一个散射时间窗口的矩阵。在这种情况下,您将获得1808行,因为训练数据中的113个信号中的每个信号都有16个时间窗口。

Nwin = size(scat_features_train,2);Scat_features_train = permute(Scat_features_train,[2 3 1]);Scat_features_train =重塑(Scat_features_train,...大小(scat_features_train 1) *大小(scat_features_train, 2), []);

对测试数据重复此过程。最初,scat_features_test是409乘16乘49,因为训练集中有49种ECG波形。对SVM分类器进行重塑后,特征矩阵为784 × 416。

scat_features_test = featureMatrix(sn,testData');Scat_features_test = permute(Scat_features_test,[2 3 1]);Scat_features_test =重塑(Scat_features_test...大小(scat_features_test 1) *大小(scat_features_test, 2), []);

因为对于每个信号,我们获得了16个散射窗口,我们需要创建标签来匹配窗口的数量。辅助函数createSequenceLabels这是基于窗口的数量。

[sequence_labels_train,sequence_labels_test] = createSequenceLabels(Nwin,trainLabels,testLabels);

交叉验证

为了分类,进行了两种分析。第一种方法利用所有的散射数据,拟合一个二次核的多类支持向量机。在整个数据集中总共有2592个散射序列,162个信号中每个16个。错误率,或损失,估计使用5倍交叉验证。

Scat_features = [scat_features_train;scat_features_test];allLabels_scat = [sequence_labels_train;sequence_labels_test];rng (1);template = templateSVM(...“KernelFunction”多项式的...“PolynomialOrder”2,...“KernelScale”“汽车”...“BoxConstraint”, 1...“标准化”,真正的);分类svm = fitcecoc(...scat_features,...allLabels_scat,...“学习者”模板,...“编码”“onevsone”...“类名”, {“加勒比海盗”瑞士法郎的“签约”});kfoldmodel = crossval(classificationSVM,“KFold”5);

计算损失和混淆矩阵。显示精度。

predLabels = kfoldPredict(kfoldmodel);损失= kfoldLoss(kfoldmodel)*100;confmatCV = confismat (allLabels_scat,predLabels)
confmatCV =3×31535 0 1 1 479 0 0 0 576
流(“准确度为%2.2f %。\n”100 -损失);
准确率为99.92%。

准确率为99.88%,这是相当好的,但实际结果更好,考虑到这里每个时间窗口是单独分类的。每个信号有16个单独的分类。使用简单多数投票获得每个散射表示的单个类预测。

Classes = categorical({“加勒比海盗”瑞士法郎的“签约”});[ClassVotes,ClassCounts] = helperMajorityVote(predLabels,[trainLabels;testLabels)、类);

根据每组散射时间窗口的类预测模式确定实际交叉验证精度。如果一个给定集合的模态不是唯一的,helperMajorityVote返回由指示的分类错误“NoUniqueMode”.这导致混淆矩阵中有一个额外的列,在这种情况下全为零,因为每个散射预测集都存在唯一的模式。

CVaccuracy = sum(eq(ClassVotes,categorical([trainLabels;testLabels]))) / 162 * 100;流(“真正的交叉验证准确率为%2.2f %。”, CVaccuracy);
真正的交叉验证准确率为100.00%。
MVconfmatCV = confusionmat(categorical([trainLabels;testLabels]), ClassVotes);MVconfmatCV
MVconfmatCV =4×496 0 0 0 30 0 0 0 36 0 0 0 0 0 0

散射对交叉验证模型中的所有信号进行了正确的分类。如果你仔细研究ClassCounts,你可以看到2个错误分类的时间窗口confmatCV归因于两个信号,其中16个散射窗口中的15个被正确分类。

支持向量机分类

在接下来的分析中,我们只对训练数据(70%)拟合了一个多类二次SVM,然后使用该模型对用于测试的30%的数据进行预测。在测试集中有49个数据记录。使用多数投票的个别散射窗口。

型号= fitcecoc(...scat_features_train,...sequence_labels_train,...“学习者”模板,...“编码”“onevsone”...“类名”, {“加勒比海盗”瑞士法郎的“签约”});predLabels = predict(model,scat_features_test);[TestVotes,TestCounts] = helperMajorityVote(predLabels,testLabels,classes);testaccuracy = sum(eq(TestVotes,categorical(testLabels)))/numel(testLabels)*100;流(“测试准确度为%2.2f %。\ n”, testaccuracy);
测试准确率为97.96%。
confusionchart(分类(testLabels)、TestVotes)

测试数据集上的分类准确率约为98%。混淆矩阵显示一条CHF记录被错误地分类为ARR。其他48个信号都被正确分类。

总结

本例使用小波时间散射和支持向量机分类器将心电图波形分为三个诊断类之一。小波散射被证明是一种强大的特征提取器,它只需要用户指定的最小参数集就能产生一组用于分类的鲁棒特征。将其与示例进行比较基于小波特征和支持向量机的信号分类万博1manbetx,这需要大量的专业知识来手工制作用于分类的特征。使用小波时间散射,您只需要指定时不变性的尺度、滤波器组(或小波变换)的数量以及每八度的小波数。小波散射变换和支持向量机分类器的组合在交叉验证模型上产生了100%的分类,当将支持向量机应用于保留测试集的散射变换时,98%的正确分类。

参考文献

  1. 安登,J.,马拉特,S. 2014。深散射光谱,IEEE信号处理学报,62,16,pp. 4114-4128。

  2. Baim DS, Colucci WS, Monrad ES, Smith HS, Wright RF, Lanoue A, Gauthier DF, Ransil BJ, Grossman W, Braunwald E.口服米力酮治疗严重充血性心力衰竭患者的生存。美国心脏病学会1986年3月;7(3): 661 - 670。

  3. Goldberger AL, Amaral LAN, Glass L, Hausdorff JM, Ivanov PCh, Mark RG, Mietus JE, Moody GB, Peng C-K, Stanley HE。PhysioBank, PhysioToolkit,和PhysioNet:复杂生理信号新研究资源的组成部分。循环.第101卷,第23期,2000年6月13日,第e215-e220页。http://circ.ahajournals.org/content/101/23/e215.full

  4. 马拉特,S., 2012。群不变散射。通讯与应用数学,65,10,pp. 1331-1398。

  5. 穆迪GB,马克RG。MIT-BIH心律失常数据库的影响。IEEE Eng in Med and biology 20(3):45-50 (May-June 2001)。(PMID: 11446209)

万博1manbetx支持功能

helperPlotRandomRecords图中随机选取四个心电信号ECGData

函数helperPlotRandomRecords (ECGData randomSeed)此函数仅用于支持XpwWaveletMLExample。万博1manbetx它可能%更改或在将来的版本中删除。如果输入参数个数= = 2 rng (randomSeed)结束M = size(ECGData.Data,1);idxsel = randperm(M,4);numplot = 1:4 subplot(2,2,numplot) plot(ECGData.Data(idxsel(numplot),1:3000)) ylabel(“伏”如果Numplot > xlabel(“样本”结束标题(ECGData.Labels {idxsel (numplot)})结束结束

helperMajorityVote为每一组散射时间窗口查找预测类标签中的模式。该函数返回每一组散射时间窗口的类标签模式和类预测的数量。如果没有唯一模式,helperMajorityVote返回一个“error”的类标签,以指示散射窗口集是一个分类错误。

函数[ClassVotes,ClassCounts] = helperMajorityVote(predLabels,origLabels,classes)此函数支持ecgwavettimescatt万博1manbetxeringexample。它可能%更改或在将来的版本中删除。如果标签不是分类的,则创建分类数组predLabels = categorical(predLabels);origLabels = categorical(origLabels);%期望predLabels和origLabels都是分类向量Npred =数字(predLabels);Norig =数字(origLabels);Nwin = Npred/Norig;predLabels =重塑(predLabels,Nwin,Norig);ClassCounts = countcats(predLabels);[mxcount,idx] = max(ClassCounts);ClassVotes = classes(idx);检查最大值中是否有任何联系,并确保它们被标记为如果该模式出现多次,则错误%modecnt = modecount(ClassCounts,mxcount);ClassVotes(modecnt>1) = categorical({“错误”});ClassVotes = ClassVotes(:);%-------------------------------------------------------------------------函数modecnt = modecount(ClassCounts,mxcount) modecnt = Inf(size(ClassCounts,2),1);nc = 1:size(ClassCounts,2) modecnt(nc) = histc(ClassCounts(:,nc),mxcount(nc));结束结束% EOF结束

另请参阅

相关的话题