Классификация сигналов с использованием основанных на вейвлете Функций и Машинах опорных векторов

Этот пример показов, как классифицировать сигналы электрокардиограммы (ЭКГ) человека с помощью основанных на вейвлете редукций данных и классификатора машины опорных векторов (SVM). Задача классификации сигналов упрощается путем преобразования необработанных сигналов ЭКГ в намного меньший набор функций, которые служат в совокупности, чтобы дифференцировать различные классы. Для запуска этого примера необходимо иметь Wavelet Toolbox™, Signal Processing Toolbox™ и Statistics and Machine Learning Toolbox™. Данные, используемые в этом примере, являются общедоступными от PhysioNet.

Описание данных

Этот пример использует данные ЭКГ, полученные из трех групп или классов людей: людей с сердечной аритмией, людей с застойным сердечным отказом и людей с нормальными синусовыми ритмами. В примере используются 162 записи ЭКГ из трех баз данных PhysioNet: База данных аритмии MIT-BIH [3] [7], База данных нормального синусового ритма MIT-BIH [3] и База данных застойной сердечной недостаточности BIDMC [1] [ Всего насчитывается 96 записей от лиц с аритмией, 30 записей от лиц с застойным сердечным отказом и 36 записей от лиц с нормальными синусовыми ритмами. Цель состоит в том, чтобы обучить классификатор для различения аритмии (ARR), застойного сердечного отказа (CHF) и нормального синусового ритма (NSR).

Загрузка данных

Первый шаг - загрузка данных из репозитория GitHub. Чтобы загрузить данные, нажмите Code и выберите Download 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 содержит данные, используемые в этом примере. Файл .txt, Modified_physionet_data.txt, требуется политикой копирования PhysioNet и предоставляет атрибуты источника для данных, а также описание шагов предварительной обработки, применяемых к каждой записи ЭКГ.

Загрузка файлов

Если вы следовали инструкциям по загрузке в предыдущем разделе, введите следующие команды, чтобы разархивировать два файла архива.

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

После разархивации файла ECGData.zip загрузите данные в MATLAB.

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

ECGData массив структур с двумя полями: Data и Labels. Data представляет собой 162 на 65536 матрицу, где каждая строка является дискретизацией записи ЭКГ в 128 герц. Labels - массив ячеек 162 на 1 с диагностическими метками, по одному для каждой строки Data. Три диагностические категории: 'ARR' (аритмия), 'CHF' (застойный сердечный отказ) и 'NSR' (нормальный синусовый ритм).

Создайте обучающие и тестовые данные

Случайным образом разделите данные на два набора - обучающие и тестовые данные. Функция помощника helperRandomSplit выполняет случайное разделение. helperRandomSplit принимает требуемый процент разделения для обучающих данных и ECGData. The helperRandomSplit функция выводит два набора данных вместе с набором меток для каждого. Каждая строка trainData и testData является сигналом ЭКГ. Каждый элемент trainLabels и testLabels содержит метку класса для соответствующей строки матриц данных. В этом примере мы случайным образом присваиваем 70% процентов данных в каждом классе набору обучающих данных. Оставшиеся 30% удерживаются для проверки (предсказания) и присваиваются тестовому набору.

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

В trainData 113 записей установил и 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×1

   59.2920
   18.5841
   22.1239

Ctest = countcats(categorical(testLabels))./numel(testLabels).*100
Ctest = 3×1

   59.1837
   18.3673
   22.4490

График выборок

Постройте первые несколько тысяч выборок четырех случайным образом выбранных записей из ECGData. Функция помощника helperPlotRandomRecords делает это. helperPlotRandomRecords принимает ECGData и случайный seed как вход. Начальный seed устанавливается равным 14, так что строится по меньшей мере одна запись от каждого класса. Можно выполнять helperPlotRandomRecords с ECGData как единственный входной параметр столько раз, сколько вы хотите получить представление о разнообразии форм волны ЭКГ, сопоставленных с каждым классом. Исходный код для этой вспомогательной функции можно найти в разделе Вспомогательные функции в конце этого примера.

helperPlotRandomRecords(ECGData,14)

Редукция данных

Извлеките функции, используемые в классификации сигналов для каждого сигнала. Этот пример использует следующие функции, извлеченные на 8 блоках каждого сигнала приблизительно одну минуту в длительности (8192 выборки):

  • Коэффициенты авторегрессионной модели (AR) порядка 4 [8].

  • Значения энтропии (SE) Shannon для максимального перекрытия дискретного преобразования пакета вейвлет (MODPWT) на уровне 4 [5].

  • Мультифрактальные оценки лидера вейвлета второго кумулянта шкальных показателей и области значений экспонентов Холдера, или особенности спектра [4].

Кроме того, для каждого сигнала по всей длине данных [6] извлекают многоуровневые оценки отклонения вейвлетов. Используется объективная оценка отклонения вейвлета. Это требует, чтобы в оценках отклонения использовались только уровни с, по крайней мере, одним коэффициентом вейвлета, не затронутым граничными условиями. Для длины сигнала 2 ^ 16 (65 536) и 'db2' вейвлет это приводит к уровням 14.

Эти функции были отобраны на основе опубликованных исследований, демонстрирующих их эффективность в классификации форм волны ЭКГ. Это не предназначено для того, чтобы быть исчерпывающим или оптимизированным списком функций.

Коэффициенты AR для каждого окна оцениваются с помощью метода Бурга, arburg. В [8] авторы использовали методы выбора порядка модели, чтобы определить, что модель AR (4) обеспечивает лучшую подгонку для форм волны ЭКГ в аналогичной задаче классификации. В [5] информационная теоретическая мера, энтропия Шеннона, была вычислена на терминальных узлах дерева вейвлет и использована со случайным классификатором лесов. Здесь мы используем неразрешенное преобразование вейвлет, modwpt, до уровня 4.

Определение энтропии Шеннона для неопределенного преобразования вейвлет после [5] определяется: SEj=-k=1Npj,k*logpj,k где N - количество соответствующих коэффициентов в j-ом узле и pj,k являются нормированными квадратами коэффициентов вейвлета пакета в j-м терминальном узле.

В качестве функций используются две фрактальные меры, оцененные вейвлет. Следуя [4], мы используем ширину спектра особенности, полученную из dwtleader как мера многофракционной природы сигнала ЭКГ. Мы также используем второй кумулянт показателей масштабирования. Масштабирующие экспоненты являются масштабируемыми экспонентами, описывающими поведение закона мощности в сигнале при различных разрешениях. Второй кумулянт широко представляет отклонение масштабирующих экспонентов от линейности.

Отклонение вейвлета для всего сигнала получено с помощью modwtvar. Отклонение вейвлета измеряет изменчивость сигнала по шкале или эквивалентную изменчивость сигнала в октавно-диапазонных частотных интервалах.

Всего 190 функции: 32 AR функции (4 коэффициента на блок), 128 значений энтропии Шеннона (16 значений на блок), 16 фрактальных оценок (2 на блок) и 14 оценок отклонения вейвлета.

The helperExtractFeatures функция вычисляет эти функции и конкатенирует их в вектор признаков для каждого сигнала. Исходный код для этой вспомогательной функции можно найти в разделе Вспомогательные функции в конце этого примера.

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

trainFeatures и testFeatures являются 113 на 190 и 49 на 190 матрицами, соответственно. Каждая строка этих матриц является вектором функций для соответствующих данных ЭКГ в trainData и testData, соответственно. При создании векторов функций данные уменьшаются с 65536 выборок до 190 векторов элемента. Это значительное сокращение данных, но цель - не просто сокращение данных. Цель состоит в том, чтобы уменьшить данные до намного меньшего набора признаков, который захватывает различие между классами, чтобы классификатор мог точно разделить сигналы. Индексы для функций, которые составляют оба trainFeatures и testFeatures содержатся в массиве структур, featureindices. Можно использовать эти индексы для исследования функций по группам. В качестве примера рассмотрим область значений экспонентов Холдера в спектрах особенности для первого временного окна. Постройте график данных для всего набора данных.

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

Можно выполнить однофакторный дисперсионный анализ этой функции и подтвердить то, что появляется в boxplot, а именно, что группы ARR и NSR имеют значительно больший область значений, чем группа CHF.

[p,anovatab,st] = anova1(allFeatures(:,featureindices.HRfeatures(1)),...
    allLabels);

c = multcompare(st,'display','off')
c = 3×6

    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

В качестве дополнительного примера рассмотрим различие в отклонение во втором самом низком частотном (второй по величине шкале) вейвлет поддиапазоне для этих трех групп.

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

Если вы выполняете дисперсионный анализ этой функции, вы обнаруживаете, что группа NSR имеет значительно более низкое отклонение в этом вейвлет, чем группы ARR и CHF. Эти примеры предназначены только для того, чтобы проиллюстрировать, как отдельные функции служат для разделения классов. Хотя одной функции недостаточно, цель состоит в том, чтобы получить достаточно богатый набор признаков, чтобы позволить классификатору разделять все три класса.

Классификация сигналов

Теперь, когда данные были сведены к вектору функций для каждого сигнала, следующим шагом является использование этих векторов функций для классификации сигналов ЭКГ. Вы можете использовать приложение Classification Learner, чтобы быстро оценить большое количество классификаторов. В этом примере используется мультиклассовый SVM с квадратичным ядром. Выполняются два анализа. Сначала мы используем набор данных в целом (наборы обучения и тестирования) и оцениваем скорость неправильной классификации и матрицу неточностей с помощью 5-кратной перекрестной валидации.

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
loss = 8.0247
[confmatCV,grouporder] = confusionmat([trainLabels;testLabels],classLabels);

5-кратная ошибка классификации составляет 8,02% (91,98% верно). Матрица неточностей, confmatCV, показывает, какие записи были неправильно классифицированы. grouporder задает упорядоченное расположение групп. Два из группы ARR были неправильно классифицированы как CHF, восемь из группы CHF были неправильно классифицированы как ARR и один как NSR, а два из группы NSR были неправильно классифицированы как ARR.

Точность, отзыв и F1 счет

В задаче классификации точностью для класса является количество правильных положительных результатов, разделенных на количество положительных результатов. Другими словами, из всех записей, которые классификатор присваивает заданной метке, какая пропорция на самом деле принадлежит классу. Вызов определяется как количество правильных меток, разделенных на количество меток для данного класса. В частности, из всех записей, принадлежащих классу, какая пропорция сделала нашу метку классификатора этим классом. Оценивая точность вашей системы машинного обучения, вы в идеале хотите сделать хорошо как на точности, так и на отзыве. Например, предположим, что у нас был классификатор, который пометил каждую отдельную запись как ARR. Тогда наш отзыв для класса ARR составил бы 1 (100%). Все записи, принадлежащие классу ARR, будут помечены как ARR. Однако точность будет низкой. Поскольку наш классификатор пометил все записи как ARR, в этом случае будет 66 ложных срабатываний для точности 96/162, или 0,5926. F1 счета является гармоническим средним значением точности и отзыва и, следовательно, обеспечивает одну метрику, которая суммирует эффективность классификатора с точки зрения как отзыва, так и точности. Следующая вспомогательная функция вычисляет точность, отзыв и F1 счетов для трех классов. Видно, как helperPrecisionRecall вычисляет точность, отзыв и F1 счет на основе матрицы неточностей путем изучения кода в разделе Вспомогательные функции.

CVTable = helperPrecisionRecall(confmatCV);

Вы можете просмотреть таблицу, возвращенную 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 

И точность, и отзыв хороши для классов ARR и NSR, в то время как отзыв значительно ниже для класса CHF.

Для следующего анализа мы подбираем мультикласс квадратичный SVM только к обучающим данным (70%), а затем используем эту модель, чтобы получить предсказания на 30% данных, сохраненных для проверки. В тестовом наборе 49 записей данных.

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

Используйте следующее, чтобы определить количество правильных предсказаний и получить матрицу неточностей.

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

Точность классификации на тестовом наборе данных составляет приблизительно 98%, и матрица неточностей показывает, что одна запись CHF была неправильно классифицирована как NSR.

Подобно тому, что было сделано в перекрестном валидационном анализе, получите точность, отзыв и F1 счетов для тестового набора.

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 

Классификация необработанных данных и кластеризация

Два естественных вопроса возникают из предыдущего анализа. Необходимы ли редукции данных в порядок для достижения хороших результатов классификации? Необходим ли классификатор, или эти функции могут разделять группы без классификатора? Для решения первого вопроса повторите результаты перекрестной проверки для необработанных данных временных рядов. Обратите внимание, что следующее является вычислительно дорогим шагом, потому что мы применяем SVM к матрице 162 на 65536. Если вы не хотите запускать этот шаг самостоятельно, результаты описаны в следующем абзаце.

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
loss = 33.3333
[confmatCVraw,grouporder] = confusionmat([trainLabels;testLabels],classLabels);
rawTable = helperPrecisionRecall(confmatCVraw);
disp(rawTable)
           Precision    Recall    F1_Score
           _________    ______    ________

    ARR        64          100     78.049 
    CHF       100       13.333     23.529 
    NSR       100       22.222     36.364 

Коэффициент неправильной классификации необработанных данных временных рядов составляет 33,3%. Повторение точности, отзыва и F1 счета обнаруживает очень плохие счета F1 как для групп CHF (23,52), так и для NSR (36,36). Получите дискретные коэффициенты преобразования Фурье (DFT) величины для каждого сигнала, чтобы выполнить анализ в частотном диапазоне. Поскольку данные являются реальными, мы можем добиться некоторого сокращения данных с помощью ДПФ, используя тот факт, что величины Фурье являются четной функцией.

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
loss = 19.1358
[confmatCVDFT,grouporder] = confusionmat([trainLabels;testLabels],classLabels);
dftTable = helperPrecisionRecall(confmatCVDFT);
disp(dftTable)
           Precision    Recall    F1_Score
           _________    ______    ________

    ARR     76.423      97.917     85.845 
    CHF        100      26.667     42.105 
    NSR     93.548      80.556     86.567 

Использование величин ДПФ снижает вероятность неправильной классификации до 19,13%, но это все еще более чем в два раза больше частоты ошибок, полученных с нашими 190 функциями. Эти анализы показывают, что классификатор выиграл от тщательного выбора функций.

Чтобы ответить на вопрос о роли классификатора, попытайтесь кластеризировать данные, используя только векторы функций. Используйте k-средних значений кластеризацию вместе со статистикой погрешностей, чтобы определить как оптимальное количество кластеров, так и назначение кластеров. Допускается использование от 1 до 6 кластеров для данных.

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

Статистика погрешностей указывает, что оптимальное количество кластеров составляет три. Однако, если вы посмотрите на количество записей в каждом из трех кластеров, то увидите, что кластеризация k-средних значений на основе векторов функций сделала плохую работу по разделению трех диагностических категорий.

countcats(categorical(eva.OptimalY))
ans = 3×1

    61
    74
    27

Напомним, что в классе ARR 96 человек, в классе CHF - 30, в классе NSR - 36.

Сводные данные

Этот пример использовал обработку сигналов для извлечения вейвлета признаков из сигналов ЭКГ и использовал эти функции для классификации сигналов ЭКГ в три класса. Это не только привело к значительному сокращению редукции данных данных, но и к различиям между классами ARR, CHF и NSR, что продемонстрировано результатами перекрестной валидации и эффективности классификатора SVM на тестовом наборе. Пример также продемонстрировал, что применение классификатора SVM к необработанным данным привело к плохой эффективности, как и кластеризация векторов функций без использования классификатора. Ни классификатора, ни только функции не было достаточно для разделения классов. Однако, когда редукция данных использовалась в качестве шага сокращения данных перед использованием классификатора, три класса были хорошо разделены.

Ссылки

  1. Baim DS, Colucci WS, Monrad ES, Smith HS, Wright RF, Lanoue A, Gauthier DF, Ransil BJ, Grossman W, Braunwald E. Выживаемость пациентов с тяжёлым застойным сердечным отказом, получавших J American College of Cardiology 1986 Mar; 7(3):661-670.

  2. Энгин, М., 2004. Классификация биений ЭКГ с использованием нейро-нечеткой сети. Pattern Recognition Letters, 25 (15), стр. 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 и PhysioNet: компоненты нового исследовательского ресурса для сложных физиологических сигналов. Циркуляция. Том 101, № 23, 13 июня 2000 года, стр. e215-e220. http://circ.ahajournals.org/content/101/23/e215.full

  4. Леонардуцци, Р.Ф., Шлоттхауэр, Г. и Торрес. M.E. 2010. Вейвлет на основе мультифрактального анализа вариабельности сердечного ритма во время ишемии миокарда. Engineering in Medicine and Biology Society (EMBC), 2010 Ежегодная международная конференция IEEE.

  5. Ли, Т. и Чжоу, М., 2016. Классификация ЭКГ с использованием вейвлет энтропии и случайных лесов. Энтропия, 18 (8), стр. 285.

  6. Махарадж, Э.А. и Алонсо, А.М. 2014. Дискриминантный анализ многомерных временных рядов: Применение к диагностике на основе сигналов ЭКГ. Вычислительная статистика и анализ данных, 70, стр. 67-87.

  7. Moody GB, Mark RG. Влияние базы данных аритмии MIT-BIH. IEEE Eng in Med and Biol 20 (3): 45-50 (май-июнь 2001). (PMID: 11446209)

  8. Zhao, Q. and Zhang, L., 2005. Редукция данных и классификация ЭКГ с использованием вейвлета преобразования и машин опорных векторов. Международная конференция IEEE по нейронным сетям и Brain,2, стр. 1089-1092.

Вспомогательные функции

helperPlotRandomRecords Строит четыре сигнала ЭКГ, случайным образом выбранных из ECGData.

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

helperExtractFeatures Извлечение коэффициентов вейвлета функций и AR для блоков данных заданного размера. Функции объединены в векторы функций.

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

helperPrecisionRecall возвращает точность, отзыв и F1 счетов на основе матрицы неточностей. Выводит результаты как таблицу 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

См. также

Функции

Приложения