В этом примере показано, как выполнить классификацию с помощью дискриминантного анализа, наивных классификаторов Байеса и деревьев решений. Предположим, что у вас есть набор данных, содержащий наблюдения с измерениями на различных переменных (называемых предикторами) и их известных метках классов. Если вы получаете значения предиктора для новых наблюдений, можете ли вы определить, к каким классам, вероятно, относятся эти наблюдения? Это проблема классификации.
Данные по радужке Фишера состоят из измерений длины чашелистика, ширины чашелистика, длины лепестка и ширины лепестка для 150 образцов радужки. Из каждого из трёх видов 50 экземпляров. Загрузите данные и посмотрите, как измерения сепаля различаются между видами. Можно использовать два столбца, содержащие измерения сепаля.
load fisheriris f = figure; gscatter(meas(:,1), meas(:,2), species,'rgb','osd'); xlabel('Sepal length'); ylabel('Sepal width'); N = size(meas,1);
Предположим, вы измеряете чашелистик и лепесток из радужки, и вам нужно определить его вид на основе этих измерений. Один из подходов к решению этой проблемы известен как дискриминантный анализ.
The fitcdiscr
функция может выполнять классификацию, используя различные типы дискриминантного анализа. Сначала классифицируйте данные с помощью стандартного линейного дискриминантного анализа (LDA).
lda = fitcdiscr(meas(:,1:2),species); ldaClass = resubPredict(lda);
Наблюдения с известными метками классов обычно называются обучающими данными. Теперь вычислите ошибку восстановления, которая является ошибкой неправильной классификации (доля неправильно классифицированных наблюдений) на набор обучающих данных.
ldaResubErr = resubLoss(lda)
ldaResubErr = 0.2000
Можно также вычислить матрицу неточностей на набор обучающих данных. Матрица неточностей содержит информацию об известных метках классов и предсказанных метках классов. Вообще говоря, элемент (i, j) в матрице неточностей является количеством выборок, чья известная метка класса является классом i и чей предсказанный класс является j. Диагональные элементы представляют правильно классифицированные наблюдения.
figure ldaResubCM = confusionchart(species,ldaClass);
Из 150 обучающих наблюдений 20% или 30 наблюдений неправильно классифицируются линейной дискриминантной функцией. Можно увидеть, какие таковые они представляют, нарисовав X через неправильно классифицированные точки.
figure(f) bad = ~strcmp(ldaClass,species); hold on; plot(meas(bad,1), meas(bad,2), 'kx'); hold off;
Функция разделила плоскость на области, разделенные линиями, и присвоила различные области различным видам. Одним из способов визуализации этих областей является создание сетки с (x, y) значениями и применение функции классификации к этой сетке.
[x,y] = meshgrid(4:.1:8,2:.1:4.5); x = x(:); y = y(:); j = classify([x y],meas(:,1:2),species); gscatter(x,y,j,'grb','sod')
Для некоторых наборов данных области для различных классов плохо разделены линиями. Когда это так, линейный дискриминантный анализ не подходит. Вместо этого вы можете попробовать квадратичный дискриминантный анализ (QDA) для наших данных.
Вычислите ошибку реституции для квадратичного дискриминантного анализа.
qda = fitcdiscr(meas(:,1:2),species,'DiscrimType','quadratic'); qdaResubErr = resubLoss(qda)
qdaResubErr = 0.2000
Вы вычислили ошибку восстановления. Обычно люди больше заинтересованы в тестовой ошибке (также называемой ошибкой обобщения), которая является ожидаемой ошибкой предсказания на независимом наборе. На самом деле ошибка реституции, вероятно, не оценит ошибку теста.
В этом случае у вас нет другого набора маркированных данных, но можно симулировать его, выполнив перекрестную валидацию. Стратифицированная 10-кратная перекрестная валидация является популярным выбором для оценки тестовой ошибки в алгоритмах классификации. Он случайным образом делит набор обучающих данных на 10 непересекающихся подмножеств. Каждое подмножество имеет примерно равный размер и примерно те же пропорции классов, что и в наборе обучающих данных. Удалите одно подмножество, обучите классификационную модель с помощью других девяти подмножеств и используйте обученную модель для классификации удаленного подмножества. Можно повторить это, удалив каждый из десяти подмножеств по одному.
Поскольку перекрестная валидация случайным образом делит данные, ее результат зависит от начального случайного seed. Чтобы воспроизвести точные результаты в этом примере, выполните следующую команду:
rng(0,'twister');
Первое использование cvpartition
сгенерировать 10 несвязанных стратифицированных подмножеств.
cp = cvpartition(species,'KFold',10)
cp = K-fold cross validation partition NumObservations: 150 NumTestSets: 10 TrainSize: 135 135 135 135 135 135 135 135 135 135 TestSize: 15 15 15 15 15 15 15 15 15 15
The crossval
и kfoldLoss
методы могут оценить ошибку неправильной классификации как для LDA, так и для QDA с помощью данного раздела данных cp
.
Оцените истинную ошибку теста для LDA, используя 10-кратную стратифицированную перекрестную валидацию.
cvlda = crossval(lda,'CVPartition',cp);
ldaCVErr = kfoldLoss(cvlda)
ldaCVErr = 0.2000
Ошибка перекрестной проверки LDA имеет то же значение, что и ошибка реституции LDA для этих данных.
Оцените истинную ошибку теста для QDA, используя 10-кратную стратифицированную перекрестную валидацию.
cvqda = crossval(qda,'CVPartition',cp);
qdaCVErr = kfoldLoss(cvqda)
qdaCVErr = 0.2200
QDA имеет немного большую ошибку перекрестной валидации, чем LDA. Это показывает, что более простая модель может получить сопоставимую, или лучшую эффективность, чем более сложная модель.
The fitcdiscr
функция имеет другие два других типа, 'DiagLinear' и 'DiagQuadratic'. Они аналогичны 'линейным' и 'квадратичным', но с диагональными оценками ковариационной матрицы. Эти диагональные варианты являются конкретными примерами наивного классификатора Байеса, потому что они предполагают, что переменные являются условно независимыми, учитывая метку класса. Наивные классификаторы Байеса относятся к числу наиболее популярных классификаторов. Хотя предположение об условной независимости классов между переменными не верно в целом, было обнаружено, что наивные классификаторы Байеса хорошо работают на практике во многих наборах данных.
The fitcnb
функция может использоваться, чтобы создать более общий тип наивного классификатора Байеса.
Сначала моделируйте каждую переменную в каждом классе, используя Гауссово распределение. Можно вычислить ошибку восстановления и ошибку перекрестной проверки.
nbGau = fitcnb(meas(:,1:2), species); nbGauResubErr = resubLoss(nbGau) nbGauCV = crossval(nbGau, 'CVPartition',cp); nbGauCVErr = kfoldLoss(nbGauCV) labels = predict(nbGau, [x y]); gscatter(x,y,labels,'grb','sod')
nbGauResubErr = 0.2200 nbGauCVErr = 0.2200
До сих пор вы предполагали, что переменные из каждого класса имеют многомерное нормальное распределение. Часто это разумное предположение, но иногда вы можете быть не готовы сделать это предположение или вы можете ясно видеть, что это не верно. Теперь попробуйте смоделировать каждую переменную в каждом классе, используя оценку плотности ядра, которая является более гибким непараметрическим методом. Здесь мы устанавливаем ядро на box
.
nbKD = fitcnb(meas(:,1:2), species, 'DistributionNames','kernel', 'Kernel','box'); nbKDResubErr = resubLoss(nbKD) nbKDCV = crossval(nbKD, 'CVPartition',cp); nbKDCVErr = kfoldLoss(nbKDCV) labels = predict(nbKD, [x y]); gscatter(x,y,labels,'rgb','osd')
nbKDResubErr = 0.2067 nbKDCVErr = 0.2133
Для этого набора данных наивный классификатор Байеса с оценкой плотности ядра получает меньшую ошибку реституции и ошибку перекрестной валидации, чем наивный классификатор Байеса с Гауссовым распределением.
Другой алгоритм классификации основан на дереве решений. Дерево решений является набором простых правил, таких как «если длина сепаля меньше 5,45, классифицируйте образец как setosa». Деревья решений также непараметричны, потому что они не требуют никаких допущений о распределении переменных в каждом классе.
The fitctree
функция создает дерево решений. Создайте дерево решений для данных радужной оболочки глаза и посмотрите, насколько хорошо она классифицирует ирисы в виды.
t = fitctree(meas(:,1:2), species,'PredictorNames',{'SL' 'SW' });
Интересно увидеть, как метод дерева решений делит плоскость. Используйте тот же метод, что и выше, чтобы визуализировать области, присвоенные каждому виду.
[grpname,node] = predict(t,[x y]); gscatter(x,y,grpname,'grb','sod')
Другой способ визуализации дерева решений - нарисовать схему правила принятия решений и присвоений классов.
view(t,'Mode','graph');
Это загроможденное дерево использует ряд правил формы «SL < 5.45», чтобы классифицировать каждый образец в один из 19 терминальных узлов. Чтобы определить назначение вида для наблюдения, начните с верхнего узла и примените правило. Если точка удовлетворяет правилу, вы берете левый путь, а если нет - правильный путь. В конечном счете вы достигаете терминального узла, который присваивает наблюдение одному из трех видов.
Вычислите ошибку восстановления и ошибку перекрестной проверки для дерева решений.
dtResubErr = resubLoss(t)
cvt = crossval(t,'CVPartition',cp);
dtCVErr = kfoldLoss(cvt)
dtResubErr = 0.1333 dtCVErr = 0.3000
Для алгоритма дерева решений оценка ошибки перекрестной валидации значительно больше, чем ошибка реституции. Это показывает, что сгенерированное дерево перегружает набор обучающих данных. Другими словами, это дерево, которое хорошо классифицирует исходный набор обучающих данных, но структура дерева чувствительна к этому конкретному набору обучающих данных, так что его эффективность по новым данным, вероятно, ухудшится. Часто можно найти более простое дерево, которое работает лучше, чем более сложное дерево на новых данных.
Попробуйте обрезать дерево. Сначала вычислите ошибку восстановления для различных подмножеств исходного дерева. Затем вычислите ошибку перекрестной проверки для этих поддеревьев. График показывает, что ошибка реституции чрезмерно оптимистична. Он всегда уменьшается, когда размер дерева растет, но за пределами определенной точки, увеличение размера дерева увеличивает частоту ошибок перекрестной валидации.
resubcost = resubLoss(t,'Subtrees','all'); [cost,secost,ntermnodes,bestlevel] = cvloss(t,'Subtrees','all'); plot(ntermnodes,cost,'b-', ntermnodes,resubcost,'r--') figure(gcf); xlabel('Number of terminal nodes'); ylabel('Cost (misclassification error)') legend('Cross-validation','Resubstitution')
Какое дерево вы должны выбрать? Простым правилом является выбор дерева с наименьшей ошибкой перекрестной валидации. Хотя это может быть удовлетворительно, вы можете предпочитать использовать более простое дерево, если оно примерно так же хорошо, как и более сложное дерево. В данном примере возьмем самое простое дерево, которое находится в пределах одной стандартной ошибки минимума. Это правило по умолчанию, используемое cvloss
метод ClassificationTree
.
Вы можете показать это на графике, вычислив значение среза, которое равно минимальной стоимости плюс одна стандартная ошибка. «Лучший» уровень, вычисленный cvloss
метод является наименьшим деревом под этой отсечкой. (Обратите внимание, что bestlevel
= 0 соответствует несрезанному дереву, поэтому вы должны добавить 1, чтобы использовать его в качестве индекса в выходные выходы вектора от cvloss
.)
[mincost,minloc] = min(cost); cutoff = mincost + secost(minloc); hold on plot([0 20], [cutoff cutoff], 'k:') plot(ntermnodes(bestlevel+1), cost(bestlevel+1), 'mo') legend('Cross-validation','Resubstitution','Min + 1 std. err.','Best choice') hold off
Наконец, можно просмотреть обрезанное дерево и вычислить для него предполагаемую ошибку неправильной классификации.
pt = prune(t,'Level',bestlevel); view(pt,'Mode','graph')
cost(bestlevel+1)
ans = 0.2467
В этом примере показано, как выполнить классификацию в MATLAB ® с помощью функций Statistics and Machine Learning Toolbox™.
Этот пример не предназначен для идеального анализа данных радужной оболочки глаза Фишера, на самом деле использование измерений лепестка вместо или в дополнение к измерениям сепаля может привести к лучшей классификации. Кроме того, этот пример не предназначен для сравнения сильных и слабых сторон различных алгоритмов классификации. Вы можете найти полезным выполнить анализ на других наборах данных и сравнить различные алгоритмы. Существуют также функции Toolbox, которые реализуют другие алгоритмы классификации. Например, можно использовать TreeBagger
для выполнения агрегации загрузочных стропов для ансамбля деревьев принятия решений, как описано в примере Bootstrap Aggregation (Bagging) из классификационных деревьев с использованием TreeBagger.