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 wavelet y máquinas de vectores de soporte

Este ejemplo muestra cómo clasificar las señales de electrocardiograma humano (ECG) mediante la extracción de características basadas en wavelet y un clasificador de máquina de vectores de soporte (SVM). El problema de la clasificación de la señal se simplifica mediante la transformación de las señales de ECG sin procesar en un conjunto mucho más pequeño de características que sirven en conjunto para diferenciar diferentes clases. Debe tener la caja de herramientas Wavelet™, la caja de herramientas de procesamiento de señal™ y™ de herramientas estadísticas y aprendizaje automático para ejecutar este ejemplo. Los datos utilizados en este ejemplo están disponibles públicamente.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 sinusales normales. El ejemplo utiliza 162 grabaciones de ECG de tres bases de datos de PhysioNet: [3] [7], [3] y [1] [3].MIT-BIH base de datos de arritmiasMIT-BIH base de datos de ritmo sinusal normalLa 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 sinusales normales. El objetivo es entrenar un clasificador para distinguir entre arritmias (ARR), insuficiencia cardíaca congestiva (CHF) y ritmo sinusal normal (NSR).

Descargar datos

El primer paso es descargar los datos de la.Repositorio de GitHub Para descargar los datos, haga clic y seleccione.Clone or downloadDownload ZIP Guarde el archivo en una carpeta en la que tenga permiso de escritura.physionet_ECG_data-master.zip Las instrucciones de este ejemplo suponen que ha descargado el archivo en el directorio temporal (en MATLAB).tempdir Modifique las instrucciones subsiguientes para descomprimir y cargar los datos si decide descargar los datos de la carpeta diferente.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 usando.Gitgit 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 pre-procesamiento aplicados a cada grabación ECG.

Cargue archivos

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

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 162-by-65536 en la que cada fila es una grabación de ECG muestreada a 128 Hertz. es una matriz de celdas de diagnóstico de 162-by-1, 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 prueba

Divida aleatoriamente los datos en dos conjuntos: conjuntos de datos de entrenamiento y pruebas. 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 de 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 un 70% de los datos de cada clase al conjunto de entrenamiento. El 30% restante se mantiene para las pruebas (predicción) y se asignan al conjunto de pruebas.

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

Hay 113 registros en el conjunto y 49 registros en.trainDatatestData Por diseño, los datos de entrenamiento 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 generales 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  

Las muestras de parcela

Trace los primeros miles de muestras de cuatro registros seleccionados aleatoriamente.ECGData La función auxiliar hace esto. acepta y una semilla aleatoria como entrada.helperPlotRandomRecordshelperPlotRandomRecordsECGData La semilla inicial se establece en 14 para que se Trace al menos un registro de cada clase. Puede ejecutar con el único argumento de entrada tantas veces como desee para tener una idea de la variedad de formas de onda de ECG asociadas con 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 operaciones utilizadas en la clasificación de la señal para cada señal. Este ejemplo utiliza las siguientes características extraídas en 8 bloques de cada señal aproximadamente un minuto de duración (8192 muestras):

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

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

  • Las estimaciones del líder de wavelet multifractal del segundo acumulador de los exponentes de escalado y el rango de exponentes del soporte, o espectro de singularidad [4].

Adicionalmente, se extraen estimaciones de varianza de wavelet multiescala para cada señal a lo largo de toda la longitud de datos [6]. Se utiliza una estimación imparcial de la varianza de wavelet. Esto requiere que solo se utilicen niveles con al menos un coeficiente de wavelet no afectados por condiciones de contorno en las estimaciones de desviación. Para una longitud de señal de 2 ^ 16 (65.536) y la wavelet ' DB2 ', esto da como resultado 14 niveles.

Estas características fueron seleccionadas en base a la investigación publicada demostrando su efectividad en la clasificación de formas de onda de ECG. Esto no pretende ser una lista exhaustiva o optimizada de características.

Los coeficientes de AR para cada ventana se estiman utilizando el método de 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 de ECG en un problema de clasificación similar. En [5], una medida teórica de la información, la entropía de Shannon, se calculó en los nodos terminales de un árbol de paquetes de wavelet y se usaba con un clasificador de bosque aleatorio. Aquí usamos la transformada de paquetes de wavelet no diezmada, hasta el nivel 4.modwpt

La definición de la entropía de Shannon para la transformada de paquete wavelet no diezmada siguiente [5] viene dada por: Dónde es el número de los coeficientes correspondientes en el nodo j-ésimo y son los cuadrados normalizados de los coeficientes del paquete de wavelet en el nodo terminal j-TH.

Dos medidas fractales estimadas por métodos de wavelet se utilizan como características. Después de [4], utilizamos el ancho del espectro de singularidad obtenido como medida de la naturaleza multifractal de la señal de ECG.dwtleader También utilizamos el segundo acumulante de los exponentes de escalado. Los exponentes de escalado son exponentes basados en escala que describen el comportamiento de la ley de potencia en la señal en diferentes resoluciones. El segundo acumulante representa en general la desviación de los exponentes de escala de la linealidad.

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

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

La función computa estas características y las conforma en un vector de entidad 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 función para los datos de ECG correspondientes en y, respectivamente.trainDatatestData Al crear vectores de entidad, los datos se reducen de 65536 muestras a 190 vectores de elemento. Esta es 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 de características mucho más pequeño que capture 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. Como ejemplo, examine el rango de exponentes de Holder en los espectros de singularidad para la primera ventana de tiempo. Trace 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, es decir, 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 subbanda de wavelet de la segunda 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 función, encontrará que el grupo NSR tiene una varianza significativamente menor en esta subbanda de wavelet que los grupos ARR y CHF. Estos ejemplos solo pretenden ilustrar cómo las características individuales sirven para separar las clases. Aunque una característica por sí sola no es suficiente, el objetivo es obtener un conjunto de características suficientemente enriquecido para permitir que un clasificador separe las tres clases.

Clasificación de señal

Ahora que los datos se han reducido a un vector de características para cada señal, el siguiente paso es utilizar estos vectores de función para clasificar las señales de ECG. Puede usar la aplicación clasificación de aprendizaje para evaluar rápidamente un gran número de clasificadores. En este ejemplo, se utiliza una SVM de varias clases con un kernel cuadrático. Se realizan dos análisis. Primero usamos todo el conjunto de datos (conjuntos de entrenamiento y pruebas) y calculamos la tasa de clasificación errónea y la matriz de confusión usando 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 erróneamente. 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 entre el número de resultados positivos. En otras palabras, de todos los registros que el clasificador asigna a una etiqueta determinada, qué proporción pertenece realmente a la clase. La recuperación se define como el número de etiquetas correctas dividido entre el número de etiquetas de una clase determinada. Concretamente, de todos los registros pertenecientes a una clase, qué proporción hizo nuestra etiqueta clasificador como esa clase. Al juzgar la precisión de su sistema de aprendizaje automático, idealmente desea hacerlo bien tanto en precisión como en recuperación. Por ejemplo, supongamos que teníamos un clasificador que etiquetó cada uno de los registros como ARR. Entonces nuestro retiro para la clase ARR sería 1 (100%). Todos los registros pertenecientes a la clase ARR se etiquetarán como ARR. Sin embargo, la precisión sería baja. Dado 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 puntuación 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 de varias clases a los datos de entrenamiento solamente (70%) y, a continuación, utilice ese modelo para realizar predicciones sobre el 30% de los datos mantenidos 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 clasificación en el DataSet de prueba es de aproximadamente 98% y la matriz de confusión muestra que un registro CHF se clasificó erróneamente como NSR.

Similar a lo que se hizo en el análisis de validación cruzada, obtener 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

Dos preguntas naturales surgen del análisis anterior. ¿Es necesaria la extracción de características para lograr buenos resultados de clasificación? ¿Es necesario un clasificador, o estas características pueden separar los grupos sin un clasificador? Para abordar la primera pregunta, repita los resultados de la validación cruzada para los datos de series de tiempo sin procesar. Tenga en cuenta que el siguiente es un paso costoso computacionalmente porque estamos aplicando el SVM a una matriz 162-by-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 de tiempo sin procesar es 33,3%. La repetición de la precisión, la recuperación y el análisis de la puntuación F1 revelan puntuaciones F1 muy deficientes 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 incluso.

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 a 19,13%, pero que es todavía más del doble de la tasa de error obtenida con nuestras características 190. 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úster. Permite 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  

El estadístico 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 características ha hecho un trabajo deficiente al 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

En este ejemplo se usó el procesamiento de señales para extraer características de wavelet de la señal ECG y se utilizaron esas características para clasificar las señales ECG en tres clases. La extracción de características no solo tuvo como resultado 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 agrupar los vectores de entidades sin utilizar un clasificador. Ni el clasificador ni las características por sí solos eran suficientes para separar las clases. Sin embargo, cuando se usó 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 Colegio Americano de Cardiología 1986 mar; 7 (3): 661-670.

  2. Engin, M., 2004. Clasificación ECG Beat utilizando red neuro-difusa. Cartas de reconocimiento de patrones, 25 (15), págs. 1715-1722.

  3. Goldberger AL, Amaral LAN, Glass L, Hausdorff JM, Ivanov PCh, Mark RG, Mietus JE, Moody GB, Peng C-K, Stanley HE. Fisiobank, 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. FORENSE 2010. Análisis multifractal basado en el líder wavelet de la variabilidad de la frecuencia cardíaca durante la isquemia miocárdica. Ingeniería en la sociedad de medicina y Biología (EMBC), 2010 Conferencia Internacional anual del IEEE.

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

  6. Maharaj, a. m. y Alonso, A.M. 2014. Análisis discriminante de series temporales multivariadas: Aplicación al diagnóstico basado en señales ECG. Estadísticas computacionales y análisis de datos, 70, PP. 67-87.

  7. Moody GB, Mark RG. El impacto de la base de datos de arritmias 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 de vectores de soporte. Conferencia Internacional IEEE sobre redes neuronales y cerebro, 2, PP. 1089-1092.

Funciones de soporte

Traza cuatro señales de ECG elegidas aleatoriamente.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 características de wavelet y los coeficientes de AR para los bloques de los datos de un tamaño especificado.helperExtractFeatures Las entidades se concatenan en vectores de entidad.

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 basadas en la matriz de confusión.helperPrecisionRecall Genera los resultados como una tabla de 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