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

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

数据描述

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

下载数据

第一步是从GitHub库。要下载数据,请单击克隆或下载选择下载ZIP.保存文件physionet_ECG_data-master.zip在您具有写入权限的文件夹中。本例的说明假定您已将文件下载到临时目录(坦普迪尔在MATLAB中)。如果您选择在不同的文件夹中下载数据,请修改后续解压缩和加载数据的说明坦普迪尔.如果您熟悉Git,可以下载最新版本的工具(git)并使用从系统命令提示符获取数据git克隆https://github.com/mathworks/physionet_ECG_data/

档案physionet_ECG_data-master.zip包含

  • ECGData.zip

  • README.md

而ECGData.zip包含

  • ECGData.mat

  • 修改的_physinet_data.txt

  • License.txt。

ECGData.mat保存本例中使用的数据。physinet的复制策略需要.txt文件Modified_physinet_data.txt,该文件提供数据的源属性以及应用于每个ECG记录的预处理步骤的说明。

加载文件

如果您按照前一节中的下载说明操作,请输入以下命令来解压缩这两个归档文件。

解压缩(fullfile (tempdir,“physionet_ECG_data-master.zip”), tempdir)解压缩(fullfile (tempdir,“physionet_ECG_data-master”,“ECGData.zip”),...完整文件(tempdir,“ECGData”))

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

加载(完整文件)(tempdir,“ECGData”,“ECGData.mat”))

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

创建培训和测试数据

将数据随机分为两组-训练数据集和测试数据集HelperAndSplit执行随机拆分。HelperAndSplit接受训练数据的所需分割百分比,并埃格达塔.的HelperAndSplit函数输出两个数据集以及每个数据集的一组标签列车数据测试数据是一个ECG信号。每个元素列车标签测试标签包含数据矩阵对应行的类标签。在本例中,我们将每个类中70%的数据随机分配给训练集。剩余的30%用于测试(预测)并分配给测试集。

列车百分比=70;[列车数据、测试数据、列车标签、测试标签]=...helperRandomSplit (percent_train ECGData);

数据库中有113条记录列车数据创历史最高纪录49项测试数据. 通过设计,训练数据包含69.75%(113/162)的数据。回想一下,ARR类别代表59.26%的数据(96/162),CHF类别代表18.52%(30/162),NSR类别代表22.22%(36/162)。检查培训和测试集中每个班级的百分比。每个班级的百分比与数据集中的整体班级百分比一致。

Ctrain = countcats(分类(trainLabels)。/元素个数(trainLabels)。*100 . Ctest = countcats(categorical(testLabels))./numel(testLabels).*100 . Ctest = countcats(categorical(testLabels))./numel(testLabels). /
Ctrain=59.2920 18.5841 22.1239 Ctest=59.1837 18.3673 22.4490

绘图样本

绘制四个随机选择的记录的前几千个样本埃格达塔.辅助函数helperPlotRandomRecords这样做。helperPlotRandomRecords接受埃格达塔和一个随机种子作为输入。初始种子设置为14,这样每个类至少可以绘制一条记录。你可以执行helperPlotRandomRecords具有埃格达塔作为唯一的输入参数,只要你希望得到与每个类相关的各种心电图波形的感觉。您可以在本例末尾的支持函数一节中找到这个函数和所有帮助函数的源代码。万博1manbetx

helperPlotRandomRecords(ECGData,14)

小波时间散射

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

N =大小(ECGData.Data 2);科幻小说= waveletScattering (“SignalLength”N“不变性刻度”, 150,“采样频率”, 128);

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

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

为了演示不变性尺度,获取尺度函数的傅里叶逆变换,并将其在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;scaplt=plot(t,phi);保持网格ylim([-1.5e-4 1.6e-4]);绘图([-75-75],-1.5e-4 1.6e-4],“k——”);绘图([75],-1.5e-4 1.6e-4],“k——”); xlabel(“秒”);伊莱贝尔(“振幅”);wavplt=绘图(t,[real(psiL1)imag(psiL1)];图例([shopplt wavplt(1)wavplt(2)]{“缩放函数”,“小波实部”,“Wavelet-Imaginary部分”});标题({“缩放函数”;“最粗尺度小波第一滤波器组”})

在构建散射分解框架后,将训练数据的散射系数以矩阵形式求得。当您运行特征矩阵对于多个信号,每一列都被处理为单个信号。

scat_features_train = featureMatrix(科幻,trainData ');

产量特征矩阵这里是416乘16乘113。张量的每一页,scat_特色列车,是一个信号的散射变换。小波散射变换根据标度函数的带宽在时间上进行严格的降采样。在这种情况下,416条散射路径中的每一条都有16个时间窗口。

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

Nwin =大小(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是416 × 16 × 49,因为在训练集中有49种心电图波形。对SVM分类器进行整形后,特征矩阵为784 × 416。

scat_特征测试=特征矩阵(sf,testData');scat_特征测试=置换(scat_特征测试,[2 3 1]);scat_特征测试=重塑(scat_特征测试,...大小(scat_特征_测试,1)*大小(scat_特征_测试,2),[]);

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

[sequence\u labels\u train,sequence\u labels\u 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);模板= templateSVM (...“KernelFunction”,多项式的,...“多项式序”2....“KernelScale”,“自动”,...“BoxConstraint”1....“标准化”,真正的);classificationSVM = fitcecoc (...scat_features,...所有标签,...“学习者”模板,...“编码”,“一对一”,...“类名”, {“啊”;“瑞士法郎”;“签约”});kfoldmodel = crossval (classificationSVM,“KFold”, 5);

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

predLabels=kfoldPredict(kfoldmodel);loss=kfoldLoss(kfoldmodel)*100;confmatCV=confusionmat(所有标签,predLabels)fprintf('准确度为%2.2f % .\n'100 -损失);
confmatCV = 1535 0 1 1 479 0 0 576准确度为99.92%。

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

类别=分类({“啊”,“瑞士法郎”,“签约”}); [ClassVotes,ClassCounts]=helperMajorityVote(预标签,[trainLabels;testLabels],类);

根据每组散射时间窗口的类别预测模式确定实际交叉验证精度。如果该模式对于给定集合不是唯一的,助手主注返回由指示的分类错误“NonuniqueMode”。这会导致混淆矩阵中出现一个额外的列,在这种情况下,该列全部为零,因为每组散射预测都存在一个唯一的模式。

CVAccurance=总和(等式(类投票,分类([trainLabels;testLabels]))/162*100;fprintf('真正的交叉验证精度为%2.2f%。\n', CVaccuracy);MVconfmatCV = confusionmat (ClassVotes分类([trainLabels;testLabels]));MVconfmatCV
真实交叉验证准确率为100.00%。MVconfmatCV = 96 0 0 0 30 0 0 0 36 0 0 0 0 0

散射已正确分类交叉验证模型中的所有信号。如果您检查ClassCounts,您可以看到中的两个错误分类的时间窗口confmatCV归因于2个信号,其中15个散射窗被正确分类。

支持向量机分类

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

型号=fitcecoc(...scat_特色列车,...序列标签列车,...“学习者”模板,...“编码”,“一对一”,...“类名”, {“啊”,“瑞士法郎”,“签约”});predLabels =预测(模型、scat_features_test);[TestVotes, TestCounts] = helperMajorityVote (predLabels、testLabels、类);testaccuracy =总和(eq (TestVotes分类(testLabels))) /元素个数(testLabels) * 100;流('测试精度为%2.2f%\不, testaccuracy);testconfmat = confusionmat (TestVotes分类(testLabels));testconfmat
测试准确率为97.96%。testconfmat=29 1 0 0 0 8 0 0 0 0 11 0 0 0 0 0 0 0 0 0

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

总结

此示例使用小波时间散射和SVM分类器将ECG波形分类为三个诊断类别之一。小波散射被证明是一个功能强大的特征提取器,它只需要一组最小的用户指定参数即可生成一组鲁棒的分类特征。将此与示例进行比较基于小波特征和支持向量机的信号分类万博1manbetx,这需要大量的专业知识来手工制作用于分类的特征。使用小波时间散射,您只需要指定时间不变性的比例、滤波器组(或小波变换)的数量,以及每倍频程的小波数。将小波散射变换与SVM分类器相结合,可在交叉验证模型上实现100%的分类,并在将SVM应用于保持测试集的散射变换时实现98%的正确分类。

工具书类

  1. Anden J., Mallat, S. 2014。深散射谱,IEEE信号处理汇刊,62,16,414 -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.生理银行、生理工具包和生理网:复杂生理信号新研究资源的组成部分。循环第101卷,第23期,2000年6月13日,第e215-e220页。http://circ.ahajournals.org/content/101/23/e215.full

  4. Mallat,S.,2012。群不变散射。纯数学和应用数学中的通信,65,10,第1331-1398页。

  5. Moody GB,Mark RG.《麻省理工学院波黑心律失常数据库的影响》。医学和生物学IEEE Eng 20(3):45-50(2001年5-6月)。(PMID:11446209)

万博1manbetx辅助功能

helperPlotRandomRecords图中随机选取的四个心电信号埃格达塔

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

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

函数[ClassVotes, ClassCounts] = helperMajorityVote (predLabels、origLabels类)%该函数支持ecgwavettimescat万博1manbetxteringexample。它可能%更改或在未来的版本中删除。%如果标签尚未分类,则创建分类数组predLabels=分类(predLabels);origLabels=分类(origLabels);%预期PredLabel和OrigLabel都是分类向量npr =元素个数(predLabels);Norig =元素个数(origLabels);Nwin = npr / Norig;predLabels =重塑(predLabels Nwin Norig);ClassCounts = countcats (predLabels);[mxcount, idx] = max (ClassCounts);ClassVotes =类(idx);%检查最大值中的任何扎带,并确保它们标记为%错误,如果模式出现多次modecnt = modecount (ClassCounts mxcount);ClassVotes (modecnt > 1) =分类({“错误”}); 类别投票=类别投票(:);%-------------------------------------------------------------------------函数modecnt=modecount(ClassCounts,mxcount)modecnt=Inf(size(ClassCounts,2),1);对于c = 1:size(ClassCounts,2) modecnt(nc) = histc(ClassCounts(:,nc),mxcount(nc));终止终止%EOF终止

另见

相关话题