Этот пример показов, как классифицировать сигналы электрокардиограммы (ЭКГ) человека с помощью основанных на вейвлете редукций данных и классификатора машины опорных векторов (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] определяется: где - количество соответствующих коэффициентов в j-ом узле и являются нормированными квадратами коэффициентов вейвлета пакета в 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.
В задаче классификации точностью для класса является количество правильных положительных результатов, разделенных на количество положительных результатов. Другими словами, из всех записей, которые классификатор присваивает заданной метке, какая пропорция на самом деле принадлежит классу. Вызов определяется как количество правильных меток, разделенных на количество меток для данного класса. В частности, из всех записей, принадлежащих классу, какая пропорция сделала нашу метку классификатора этим классом. Оценивая точность вашей системы машинного обучения, вы в идеале хотите сделать хорошо как на точности, так и на отзыве. Например, предположим, что у нас был классификатор, который пометил каждую отдельную запись как 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 к необработанным данным привело к плохой эффективности, как и кластеризация векторов функций без использования классификатора. Ни классификатора, ни только функции не было достаточно для разделения классов. Однако, когда редукция данных использовалась в качестве шага сокращения данных перед использованием классификатора, три класса были хорошо разделены.
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.
Энгин, М., 2004. Классификация биений ЭКГ с использованием нейро-нечеткой сети. Pattern Recognition Letters, 25 (15), стр. 1715-1722.
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
Леонардуцци, Р.Ф., Шлоттхауэр, Г. и Торрес. M.E. 2010. Вейвлет на основе мультифрактального анализа вариабельности сердечного ритма во время ишемии миокарда. Engineering in Medicine and Biology Society (EMBC), 2010 Ежегодная международная конференция IEEE.
Ли, Т. и Чжоу, М., 2016. Классификация ЭКГ с использованием вейвлет энтропии и случайных лесов. Энтропия, 18 (8), стр. 285.
Махарадж, Э.А. и Алонсо, А.М. 2014. Дискриминантный анализ многомерных временных рядов: Применение к диагностике на основе сигналов ЭКГ. Вычислительная статистика и анализ данных, 70, стр. 67-87.
Moody GB, Mark RG. Влияние базы данных аритмии MIT-BIH. IEEE Eng in Med and Biol 20 (3): 45-50 (май-июнь 2001). (PMID: 11446209)
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