Esta página aún no se ha traducido para esta versión. Puede ver la versión más reciente de esta página en inglés.

Clasificación de señales mediante características basadas en ondas y máquinas vectoriales de soporte

Este ejemplo muestra cómo clasificar las señales de electrocardiograma humano (ECG) mediante la extracción de entidades basada en ondas y un clasificador de máquina vectorial de soporte (SVM). El problema de la clasificación de señales se simplifica transformando las señales ECG sin procesar en un conjunto mucho más pequeño de características que sirven en conjunto para diferenciar diferentes clases. Debe tener Wavelet Toolbox™, Cuadro de herramientas de procesamiento de señales™ y Herramientas de estadísticas y aprendizaje automático™ para ejecutar este ejemplo. Los datos utilizados en este ejemplo están disponibles públicamente desde .PhysioNet

Descripción de los datos

Este ejemplo utiliza datos de ECG obtenidos de tres grupos, o clases, de personas: personas con arritmia cardíaca, personas con insuficiencia cardíaca congestiva y personas con ritmos sinuales normales. El ejemplo utiliza 162 grabaciones ECG de tres bases de datos PhysioNet: [3][7], [3] y [1][3].Base de datos de arritmias del MIT-BIHBase de datos de ritmo sinusal normal MIT-BIHLa base de datos de insuficiencia cardíaca congestiva BIDMC En total, hay 96 grabaciones de personas con arritmia, 30 grabaciones de personas con insuficiencia cardíaca congestiva y 36 grabaciones de personas con ritmos sinuales normales. El objetivo es entrenar a un clasificador para distinguir entre arritmia (ARR), insuficiencia cardíaca congestiva (CHF) y ritmo sinusal normal (NSR).

Descargar datos

El primer paso es descargar los datos del archivo .Repositorio GitHub Para descargar los datos, haga clic y seleccione .Clone or downloadDownload ZIP Guarde el archivo en una carpeta donde tenga permiso de escritura.physionet_ECG_data-master.zip En las instrucciones de este ejemplo se supone que ha descargado el archivo en el directorio temporal, (en MATLAB).tempdir Modifique las instrucciones posteriores para descomprimir y cargar los datos si decide descargar los datos en una carpeta diferente de .tempdir Si está familiarizado con Git, puede descargar la última versión de las herramientas ( ) y obtener los datos de un símbolo del sistema utilizandoGit git clone https://github.com/mathworks/physionet_ECG_data/ .

El archivo contienephysionet_ECG_data-master.zip

  • ECGData.zip

  • README.md

y ECGData.zip contiene

  • ECGData.mat

  • Modified_physionet_data.txt

  • License.txt.

ECGData.mat contiene los datos utilizados en este ejemplo. El archivo .txt, Modified_physionet_data.txt, es requerido por la política de copia de PhysioNet y proporciona las atribuciones de origen para los datos, así como una descripción de los pasos de preprocesamiento aplicados a cada registro ECG.

Cargar archivos

Si ha seguido las instrucciones de descarga de la sección anterior, escriba los siguientes comandos para descomprimir los dos archivos de archivado.

unzip(fullfile(tempdir,'physionet_ECG_data-master.zip'),tempdir) unzip(fullfile(tempdir,'physionet_ECG_data-master','ECGData.zip'),...     fullfile(tempdir,'ECGData')) 

Después de descomprimir el archivo ECGData.zip, cargue los datos en MATLAB.

load(fullfile(tempdir,'ECGData','ECGData.mat')) 

es una matriz de estructura con dos campos: y . es una matriz de 162 por 65536 donde cada fila es una grabación ECG muestreada a 128 hercios. es una matriz de celdas de 162 por 1 de etiquetas de diagnóstico, una para cada fila de .ECGDataDataLabelsDataLabelsData Las tres categorías de diagnóstico son: 'ARR' (arritmia), 'CHF' (insuficiencia cardíaca congestiva) y 'NSR' (ritmo sinusal normal).

Crear datos de entrenamiento y pruebas

Divida aleatoriamente los datos en dos conjuntos: conjuntos de datos de entrenamiento y prueba. La función auxiliar realiza la división aleatoria. acepta el porcentaje de división deseado para los datos de entrenamiento y .helperRandomSplithelperRandomSplitECGData La función genera dos conjuntos de datos junto con un conjunto de etiquetas para cada uno.helperRandomSplit Cada fila de y es una señal ECG.trainDatatestData Cada elemento de y contiene la etiqueta de clase para la fila correspondiente de las matrices de datos.trainLabelstestLabels En este ejemplo, asignamos aleatoriamente el 70% de los datos de cada clase al conjunto de entrenamiento. El 30% restante se mantiene para las pruebas (predicción) y se asigna al conjunto de pruebas.

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

Hay 113 registros en el set y 49 registros en .trainDatatestData Por diseño, los datos de formación contienen el 69,75% (113/162) de los datos. Recuerde que la clase ARR representa el 59,26% de los datos (96/162), la clase CHF representa el 18,52% (30/162) y la clase NSR representa el 22,22% (36/162). Examine el porcentaje de cada clase en los conjuntos de entrenamiento y prueba. Los porcentajes de cada uno son coherentes con los porcentajes de clase globales del conjunto de datos.

Ctrain = countcats(categorical(trainLabels))./numel(trainLabels).*100 Ctest = countcats(categorical(testLabels))./numel(testLabels).*100 
 Ctrain =     59.2920    18.5841    22.1239   Ctest =     59.1837    18.3673    22.4490  

Muestras de parcela

Trazar las primeras miles de muestras de cuatro registros seleccionados al azar de .ECGData La función auxiliar hace esto. acepta y una semilla aleatoria como entrada.helperPlotRandomRecordshelperPlotRandomRecordsECGData El valor inicial se establece en 14 para que se trace al menos un registro de cada clase. Puede ejecutar con como único argumento de entrada tantas veces como desee para obtener una idea de la variedad de formas de onda ECG asociadas a cada clase.helperPlotRandomRecordsECGData Puede encontrar el código fuente de esta función auxiliar en la sección Funciones auxiliares al final de este ejemplo.

helperPlotRandomRecords(ECGData,14) 

Extracción de características

Extraiga las características utilizadas en la clasificación de señal para cada señal. Este ejemplo utiliza las siguientes características extraídas en 8 bloques de cada señal de aproximadamente un minuto de duración (8192 muestras):

  • Coeficientes del modelo autoregresivo (AR) de la orden 4 [8].

  • Valores de entropía de Shannon (SE) para la transformación máxima del paquete de wavelet discreto de solapamiento (MODPWT) en el nivel 4 [5].

  • Las estimaciones de líder de ondas multifractales del segundo cumulante de los exponentes de escala y el rango de exponentes de titular, o espectro de singularidad [4].

Además, se extraen estimaciones de varianza de onda multiescala para cada señal a lo largo de toda la longitud de datos [6]. Se utiliza una estimación imparcial de la varianza del wavelet. Esto requiere que sólo se utilicen niveles con al menos un coeficiente de wavelet no afectado por las condiciones de contorno en las estimaciones de varianza. Para una longitud de señal de 2 a 16 (65,536) y la onda 'db2' esto da como resultado 14 niveles.

Estas características fueron seleccionadas en base a investigaciones publicadas que demuestran su eficacia en la clasificación de formas de onda ECG. Esto no pretende ser una lista exhaustiva u optimizada de características.

Los coeficientes AR para cada ventana se estiman utilizando el método Burg, .arburg En [8], los autores utilizaron métodos de selección de orden de modelo para determinar que un modelo AR(4) proporcionaba el mejor ajuste para las formas de onda ECG en un problema de clasificación similar. En [5], una medida teórico de la información, la entropía shannonera, se calculó en los nodos terminales de un árbol de paquetes de wavelet y se utilizó con un clasificador de bosque aleatorio. Aquí usamos la transformación del paquete del wavelet no diezmado, abajo al nivel 4.modwpt

La definición de la entropía de Shannon para la transformación de paquete de wavelet no diezmada después de [5] es dada por: $SE_{j} = -\sum_{k=1}^{N}p_{j,k}*\log{p_{j,k}}$ Dónde $N$ es el número de los coeficientes correspondientes en el nodo j-ésimo y $p_{j,k}$ son los cuadrados normalizados de los coeficientes de paquetes wavelet en el nodo terminal j-th.

Se utilizan dos medidas fractales estimadas por los métodos de wavelet como características. Después de [4], utilizamos la anchura del espectro de singularidad obtenido como medida de la naturaleza multifractal de la señal ECG.dwtleader También usamos el segundo cumulante de los exponentes de escala. Los exponentes de escala son exponentes basados en escala que describen el comportamiento de la ley de potencia en la señal a diferentes resoluciones. El segundo cumulante representa ampliamente la salida de los exponentes de escala de la linealidad.

La varianza de la onda para toda la señal se obtiene utilizando .modwtvar La varianza de onda mide la variabilidad en una señal por escala, o la variabilidad equivalente en una señal sobre intervalos de frecuencia de banda de octava.

En total hay 190 características: 32 características AR (4 coeficientes por bloque), 128 valores de entropía shannon (16 valores por bloque), 16 estimaciones fractales (2 por bloque) y 14 estimaciones de varianza de wavelet.

La función calcula estas entidades y las concatena en un vector de entidades para cada señal.helperExtractFeatures Puede encontrar el código fuente de esta función auxiliar en la sección Funciones auxiliares al final de este ejemplo.

timeWindow = 8192; ARorder = 4; MODWPTlevel = 4; [trainFeatures,testFeatures,featureindices] = ...     helperExtractFeatures(trainData,testData,timeWindow,ARorder,MODWPTlevel); 

y son 113-por-190 y 49-por-190 matrices, respectivamente.trainFeaturestestFeatures Cada fila de estas matrices es un vector de entidades para los datos ECG correspondientes en y , respectivamente.trainDatatestData Al crear vectores de entidades, los datos se reducen de 65536 muestras a 190 vectores de elementos. Se trata de una reducción significativa de los datos, pero el objetivo no es solo una reducción de los datos. El objetivo es reducir los datos a un conjunto mucho más pequeño de entidades que captura la diferencia entre las clases para que un clasificador pueda separar con precisión las señales. Los índices de las entidades, que componen ambos y están contenidos en la matriz de estructura, .trainFeaturestestFeaturesfeatureindices Puede utilizar estos índices para explorar entidades por grupo. Por ejemplo, examine el rango de exponentes de soporte en los espectros de singularidad para la primera ventana de tiempo. Trazar los datos para todo el conjunto de datos.

allFeatures = [trainFeatures;testFeatures]; allLabels = [trainLabels;testLabels]; figure boxplot(allFeatures(:,featureindices.HRfeatures(1)),allLabels,'notch','on') ylabel('Holder Exponent Range') title('Range of Singularity Spectrum by Group (First Time Window)') grid on 

Puede realizar un análisis unidireccional de la varianza en esta característica y confirmar lo que aparece en la gráfica de caja, a saber, que los grupos ARR y NSR tienen un rango significativamente mayor que el grupo CHF.

[p,anovatab,st] = anova1(allFeatures(:,featureindices.HRfeatures(1)),...     allLabels); c = multcompare(st,'display','off') 
 c =      1.0000    2.0000    0.0176    0.1144    0.2112    0.0155     1.0000    3.0000   -0.1591   -0.0687    0.0218    0.1764     2.0000    3.0000   -0.2975   -0.1831   -0.0687    0.0005  

Como ejemplo adicional, considere la diferencia de varianza en la segunda subbanda de wavelet de frecuencia más baja (segunda escala más grande) para los tres grupos.

boxplot(allFeatures(:,featureindices.WVARfeatures(end-1)),allLabels,'notch','on') ylabel('Wavelet Variance') title('Wavelet Variance by Group') grid on 

Si realiza un análisis de varianza en esta característica, encontrará que el grupo NSR tiene una varianza significativamente menor en esta subbanda de wavelet que los grupos ARR y CHF. Estos ejemplos solo están diseñados para ilustrar cómo las entidades individuales sirven para separar las clases. Aunque una sola entidad por sí sola no es suficiente, el objetivo es obtener un conjunto de características lo suficientemente rico como para permitir que un clasificador separe las tres clases.

Clasificación de señales

Ahora que los datos se han reducido a un vector de entidad es para cada señal, el siguiente paso es utilizar estos vectores de entidades para clasificar las señales ECG. Puede usar la aplicación Classification Learner para evaluar rápidamente un gran número de clasificadores. En este ejemplo, se utiliza una SVM multiclase con un kernel cuadrático. Se realizan dos análisis. En primer lugar, usamos todo el conjunto de datos (conjuntos de entrenamiento y pruebas) y estimamos la tasa de clasificación errónea y la matriz de confusión mediante la validación cruzada de 5 veces.

features = [trainFeatures; testFeatures]; rng(1) template = templateSVM(...     'KernelFunction','polynomial',...     'PolynomialOrder',2,...     'KernelScale','auto',...     'BoxConstraint',1,...     'Standardize',true); model = fitcecoc(...     features,...     [trainLabels;testLabels],...     'Learners',template,...     'Coding','onevsone',...     'ClassNames',{'ARR','CHF','NSR'}); kfoldmodel = crossval(model,'KFold',5); classLabels = kfoldPredict(kfoldmodel); loss = kfoldLoss(kfoldmodel)*100 [confmatCV,grouporder] = confusionmat([trainLabels;testLabels],classLabels); 
 loss =      8.0247  

El error de clasificación de 5 veces es 8,02% (91,98% correcto). La matriz de confusión, , muestra qué registros se clasificaron incorrectamente. da el orden de los grupos.confmatCVgrouporder Dos del grupo ARR fueron clasificados erróneamente como CHF, ocho del grupo CHF fueron clasificados erróneamente como ARR y uno como NSR, y dos del grupo NSR fueron clasificados erróneamente como ARR.

Precisión, Recuperación y Puntuación F1

En una tarea de clasificación, la precisión de una clase es el número de resultados positivos correctos dividido por el número de resultados positivos. En otras palabras, de todos los registros que el clasificador asigna una etiqueta determinada, qué proporción pertenece realmente a la clase. La recuperación se define como el número de etiquetas correctas dividido por el número de etiquetas de una clase determinada. Específicamente, de todos los registros pertenecientes a una clase, ¿qué proporción calificó nuestro clasificador como esa clase. Al juzgar la precisión de su sistema de aprendizaje automático, lo ideal es que desee hacerlo bien tanto en precisión como en recuperación. Por ejemplo, supongamos que teníamos un clasificador que etiquetaba cada registro como ARR. Entonces nuestro retiro para la clase ARR sería 1 (100%). Todos los registros pertenecientes a la clase ARR se etiquetarían como ARR. Sin embargo, la precisión sería baja. Debido a que nuestro clasificador etiquetó todos los registros como ARR, habría 66 falsos positivos en este caso para una precisión de 96/162, o 0.5926. La partitura F1 es la media armónica de precisión y recuperación y, por lo tanto, proporciona una única métrica que resume el rendimiento del clasificador en términos de recuperación y precisión. La siguiente función auxiliar calcula las puntuaciones de precisión, recuperación y F1 para las tres clases. Puede ver cómo calcula la precisión, la recuperación y la puntuación F1 en función de la matriz de confusión examinando el código en la sección Funciones auxiliares.helperPrecisionRecall

CVTable = helperPrecisionRecall(confmatCV); 

Puede mostrar la tabla devuelta con el siguiente comando.helperPrecisionRecall

disp(CVTable) 
           Precision    Recall    F1_Score            _________    ______    ________      ARR     90.385      97.917         94      CHF     91.304          70     79.245      NSR     97.143      94.444     95.775   

Tanto la precisión como la recuperación son buenas para las clases ARR y NSR, mientras que la recuperación es significativamente menor para la clase CHF.

Para el siguiente análisis, ajustamos una SVM cuadrática multiclase solo a los datos de entrenamiento (70%) y luego usa ese modelo para hacer predicciones sobre el 30% de los datos retenidos para las pruebas. Hay 49 registros de datos en el conjunto de pruebas.

model = fitcecoc(...      trainFeatures,...      trainLabels,...      'Learners',template,...      'Coding','onevsone',...      'ClassNames',{'ARR','CHF','NSR'}); predLabels = predict(model,testFeatures); 

Utilice lo siguiente para determinar el número de predicciones correctas y obtener la matriz de confusión.

correctPredictions = strcmp(predLabels,testLabels); testAccuracy = sum(correctPredictions)/length(testLabels)*100 [confmatTest,grouporder] = confusionmat(testLabels,predLabels); 
 testAccuracy =     97.9592  

La precisión de la clasificación en el conjunto de datos de prueba es aproximadamente del 98% y la matriz de confusión muestra que un registro CHF fue clasificado erróneamente como NSR.

De forma similar a lo que se hizo en el análisis de validación cruzada, obtenga precisión, recuperación y las puntuaciones F1 para el conjunto de pruebas.

testTable = helperPrecisionRecall(confmatTest); disp(testTable) 
           Precision    Recall    F1_Score            _________    ______    ________      ARR        100         100        100      CHF        100      88.889     94.118      NSR     91.667         100     95.652   

Clasificación de datos sin procesar y clustering

El análisis anterior surge de dos preguntas naturales. ¿Es necesaria la extracción de características para lograr buenos resultados de clasificación? ¿Es necesario un clasificador o estas entidades pueden separar los grupos sin un clasificador? Para abordar la primera pregunta, repita los resultados de validación cruzada para los datos de serie temporal sin procesar. Tenga en cuenta que lo siguiente es un paso computacionalmente costoso porque estamos aplicando la SVM a una matriz de 162 por 65536. Si no desea ejecutar este paso usted mismo, los resultados se describen en el párrafo siguiente.

rawData = [trainData;testData]; Labels = [trainLabels;testLabels]; rng(1) template = templateSVM(...     'KernelFunction','polynomial', ...     'PolynomialOrder',2, ...     'KernelScale','auto', ...     'BoxConstraint',1, ...     'Standardize',true); model = fitcecoc(...     rawData,...     [trainLabels;testLabels],...     'Learners',template,...     'Coding','onevsone',...     'ClassNames',{'ARR','CHF','NSR'}); kfoldmodel = crossval(model,'KFold',5); classLabels = kfoldPredict(kfoldmodel); loss = kfoldLoss(kfoldmodel)*100 [confmatCVraw,grouporder] = confusionmat([trainLabels;testLabels],classLabels); rawTable = helperPrecisionRecall(confmatCVraw); disp(rawTable) 
 loss =     33.3333             Precision    Recall    F1_Score            _________    ______    ________      ARR        64          100     78.049      CHF       100       13.333     23.529      NSR       100       22.222     36.364   

La tasa de clasificación errónea para los datos de series temporales sin procesar es del 33,3%. La repetición de la precisión, la recuperación y el análisis de puntuación F1 revela puntuaciones de F1 muy pobres para los grupos CHF (23.52) y NSR (36.36). Obtenga los coeficientes de transformación de Fourier (DFT) discretos de magnitud para cada señal para realizar el análisis en el dominio de frecuencia. Debido a que los datos son de valor real, podemos lograr cierta reducción de datos utilizando el DFT aprovechando el hecho de que las magnitudes de Fourier son una función uniforme.

rawDataDFT = abs(fft(rawData,[],2)); rawDataDFT = rawDataDFT(:,1:2^16/2+1); rng(1) template = templateSVM(...     'KernelFunction','polynomial',...     'PolynomialOrder',2,...     'KernelScale','auto',...     'BoxConstraint',1,...     'Standardize',true); model = fitcecoc(...     rawDataDFT,...     [trainLabels;testLabels],...     'Learners',template,...     'Coding','onevsone',...     'ClassNames',{'ARR','CHF','NSR'}); kfoldmodel = crossval(model,'KFold',5); classLabels = kfoldPredict(kfoldmodel); loss = kfoldLoss(kfoldmodel)*100 [confmatCVDFT,grouporder] = confusionmat([trainLabels;testLabels],classLabels); dftTable = helperPrecisionRecall(confmatCVDFT); disp(dftTable) 
 loss =     19.1358             Precision    Recall    F1_Score            _________    ______    ________      ARR     76.423      97.917     85.845      CHF        100      26.667     42.105      NSR     93.548      80.556     86.567   

El uso de las magnitudes DFT reduce la tasa de clasificación errónea al 19,13%, pero eso sigue siendo más del doble de la tasa de error obtenida con nuestras 190 características. Estos análisis demuestran que el clasificador se ha beneficiado de una cuidadosa selección de características.

Para responder a la pregunta relativa al rol del clasificador, intente agrupar los datos utilizando solo los vectores de entidad. Utilice la agrupación en clústeres k-means junto con la estadística de separación para determinar el número óptimo de clústeres y la asignación de clústeres. Permita la posibilidad de 1 a 6 clústeres para los datos.

rng default eva = evalclusters(features,'kmeans','gap','KList',[1:6]); eva 
 eva =     GapEvaluation with properties:      NumObservations: 162          InspectedK: [1 2 3 4 5 6]     CriterionValues: [1.2777 1.3539 1.3644 1.3570 1.3591 1.3752]            OptimalK: 3  

La estadística de brecha indica que el número óptimo de clústeres es tres. Sin embargo, si observa el número de registros en cada uno de los tres clústeres, verá que la agrupación en clústeres k-means basada en los vectores de entidades ha hecho un trabajo deficiente de separar las tres categorías de diagnóstico.

countcats(categorical(eva.OptimalY)) 
 ans =      61     74     27  

Recuerde que hay 96 personas en la clase ARR, 30 en la clase CHF y 36 en la clase NSR.

Resumen

Este ejemplo utilizó el procesamiento de señales para extraer las características del wavelet de las señales ECG y utilizó esas características para clasificar las señales ECG en tres clases. La extracción de características no sólo dio lugar a una cantidad significativa de reducción de datos, sino que también capturó las diferencias entre las clases ARR, CHF y NSR, como lo demuestran los resultados de validación cruzada y el rendimiento del clasificador SVM en el conjunto de pruebas. En el ejemplo se demostró además que la aplicación de un clasificador SVM a los datos sin procesar daba como resultado un rendimiento deficiente, al igual que la agrupación en clústeres de los vectores de entidades sin usar un clasificador. Ni el clasificador ni las entidades por sí solas eran suficientes para separar las clases. Sin embargo, cuando se utilizaba la extracción de entidades como paso de reducción de datos antes del uso de un clasificador, las tres clases estaban bien separadas.

Referencias

  1. Baim DS, Colucci WS, Monrad ES, Smith HS, Wright RF, Lanoue A, Gauthier DF, Ransil BJ, Grossman W, Braunwald E. Supervivencia de pacientes con insuficiencia cardíaca congestiva grave tratados con milrinona oral. J American College of Cardiology 1986 Mar; 7(3):661-670.

  2. Engin, M., 2004. Clasificación de ritmos de ECG mediante red neurodifusión. Cartas de reconocimiento de patrones, 25(15), pp.1715-1722.

  3. Goldberger AL, Amaral LAN, Glass L, Hausdorff JM, Ivanov PCh, Mark RG, Mietus JE, Moody GB, Peng C-K, Stanley HE. PhysioBank, PhysioToolkit y PhysioNet: Componentes de un nuevo recurso de investigación para señales fisiológicas complejas. .Circulation Vol. 101, No 23, 13 de junio de 2000, pp. e215-e220.http://circ.ahajournals.org/content/101/23/e215.full

  4. Leonarduzzi, R.F., Schlotthauer, G., y Torres. M.E. 2010. El análisis multifractal basado en el líder de ondas de la variabilidad de la frecuencia cardíaca durante la isquemia miocárdica. Ingeniería en Medicina y Biología (EMBC), 2010 Conferencia Internacional Anual del IEEE.

  5. Li, T. y Zhou, M., 2016. Clasificación ECG mediante entropía de paquetes de ondas y bosques aleatorios. Entropía, 18(8), p.285.

  6. Maharaj, E.A. y Alonso, A.M. 2014. Análisis discriminatorio de series temporales multivariadas: Aplicación al diagnóstico basado en señales ECG. Estadísticas Computacionales y Análisis de Datos, 70, págs. 67-87.

  7. Moody GB, Mark RG. El impacto de la base de datos de arritmias del MIT-BIH. IEEE Eng en Med y Biol 20(3):45-50 (mayo-junio 2001). (PMID: 11446209)

  8. Zhao, Q. y Zhang, L., 2005. Extracción y clasificación de características de ECG mediante la transformación de wavelet y máquinas vectoriales de soporte. IEEE International Conference on Neural Networks and Brain,2, págs. 1089-1092.

Funciones de apoyo

Traza cuatro señales ECG elegidas aleatoriamente de .helperPlotRandomRecordsECGData

function helperPlotRandomRecords(ECGData,randomSeed) % This function is only intended to support the XpwWaveletMLExample. It may % change or be removed in a future release.  if nargin==2     rng(randomSeed) end  M = size(ECGData.Data,1); idxsel = randperm(M,4); for numplot = 1:4     subplot(2,2,numplot)     plot(ECGData.Data(idxsel(numplot),1:3000))     ylabel('Volts')     if numplot > 2         xlabel('Samples')     end     title(ECGData.Labels{idxsel(numplot)}) end  end 

Extrae las entidades de wavelet y los coeficientes AR para bloques de los datos de un tamaño especificado.helperExtractFeatures Las entidades se concatenan en vectores de entidades.

function [trainFeatures, testFeatures,featureindices] = helperExtractFeatures(trainData,testData,T,AR_order,level) % This function is only in support of XpwWaveletMLExample. It may change or % be removed in a future release. trainFeatures = []; testFeatures = [];  for idx =1:size(trainData,1)     x = trainData(idx,:);     x = detrend(x,0);     arcoefs = blockAR(x,AR_order,T);     se = shannonEntropy(x,T,level);     [cp,rh] = leaders(x,T);     wvar = modwtvar(modwt(x,'db2'),'db2');     trainFeatures = [trainFeatures; arcoefs se cp rh wvar']; %#ok<AGROW>  end  for idx =1:size(testData,1)     x1 = testData(idx,:);     x1 = detrend(x1,0);     arcoefs = blockAR(x1,AR_order,T);     se = shannonEntropy(x1,T,level);     [cp,rh] = leaders(x1,T);     wvar = modwtvar(modwt(x1,'db2'),'db2');     testFeatures = [testFeatures;arcoefs se cp rh wvar']; %#ok<AGROW>  end  featureindices = struct(); % 4*8 featureindices.ARfeatures = 1:32; startidx = 33; endidx = 33+(16*8)-1; featureindices.SEfeatures = startidx:endidx; startidx = endidx+1; endidx = startidx+7; featureindices.CP2features = startidx:endidx; startidx = endidx+1; endidx = startidx+7; featureindices.HRfeatures = startidx:endidx; startidx = endidx+1; endidx = startidx+13; featureindices.WVARfeatures = startidx:endidx; end   function se = shannonEntropy(x,numbuffer,level) numwindows = numel(x)/numbuffer; y = buffer(x,numbuffer); se = zeros(2^level,size(y,2)); for kk = 1:size(y,2)     wpt = modwpt(y(:,kk),level);     % Sum across time     E = sum(wpt.^2,2);     Pij = wpt.^2./E;     % The following is eps(1)     se(:,kk) = -sum(Pij.*log(Pij+eps),2); end se = reshape(se,2^level*numwindows,1); se = se'; end   function arcfs = blockAR(x,order,numbuffer) numwindows = numel(x)/numbuffer; y = buffer(x,numbuffer); arcfs = zeros(order,size(y,2)); for kk = 1:size(y,2)     artmp =  arburg(y(:,kk),order);     arcfs(:,kk) = artmp(2:end); end arcfs = reshape(arcfs,order*numwindows,1); arcfs = arcfs'; end   function [cp,rh] = leaders(x,numbuffer) y = buffer(x,numbuffer); cp = zeros(1,size(y,2)); rh = zeros(1,size(y,2)); for kk = 1:size(y,2)     [~,h,cptmp] = dwtleader(y(:,kk));     cp(kk) = cptmp(2);     rh(kk) = range(h); end end 

devuelve las puntuaciones de precisión, recuperación y F1 en función de la matriz de confusión.helperPrecisionRecall Produce los resultados como una tabla MATLAB.

function PRTable = helperPrecisionRecall(confmat) % This function is only in support of XpwWaveletMLExample. It may change or % be removed in a future release. precisionARR = confmat(1,1)/sum(confmat(:,1))*100; precisionCHF = confmat(2,2)/sum(confmat(:,2))*100 ; precisionNSR = confmat(3,3)/sum(confmat(:,3))*100 ; recallARR = confmat(1,1)/sum(confmat(1,:))*100; recallCHF = confmat(2,2)/sum(confmat(2,:))*100; recallNSR = confmat(3,3)/sum(confmat(3,:))*100; F1ARR = 2*precisionARR*recallARR/(precisionARR+recallARR); F1CHF = 2*precisionCHF*recallCHF/(precisionCHF+recallCHF); F1NSR = 2*precisionNSR*recallNSR/(precisionNSR+recallNSR); % Construct a MATLAB Table to display the results. PRTable = array2table([precisionARR recallARR F1ARR;...     precisionCHF recallCHF F1CHF; precisionNSR recallNSR...     F1NSR],'VariableNames',{'Precision','Recall','F1_Score'},'RowNames',...     {'ARR','CHF','NSR'});  end