function [classOK, knnClass, votes] = myKnnClass(K, realClassX, distances); % myKnnClass gives the classification result with K-nearest neighbour % % This is optimized for Assignment #2 in T-61.2010 in Autumn 2006, % and won't work in general cases. % % [classOK, knnClass, votes] = myKnnClass(K, realClassX, distances) % % myKnnClass classifies the test vector "x" with a known class % "realClassX" and with a vector "distances" containing distances % from test vector "x" to all possible training samples. % Possible classes are 'Setosa', 'Versicolor', % and 'Virginica' according to famous "iris data". % Classification is based on "K" nearest neighbours. % If there are several classes with the same amount of neighours, % class is randomly one of those. % % If the classification is correct, "classOK" gets 1, otherwise 0. % The class by the classifier is given in "knnClass". % "votes" contains amount of hits. % % K number of neighbours, normally odd K = {1, 3, 5} % realClassX (char) real class of the vector "x", one of % 'Setosa', 'Versicolor', or 'Virginica'. % In this Assignment #2 this is % "sTestD.label{i}", where i refers to index % number of vector "x", i = 1..N. % distances (60x1) vector containing distances from % test sample x to each of data points in % the training set % classOK 1 if classified correctly; otherwise 0. % In other words, if the correct class % is e.g. 'Setosa' and the classified % class is 'Setosa', 1 is returned. % knnClass (char) class given by k-nn classifier, % one of 'Setosa', 'Versicolor', 'Virginica' % votes (1x3) hits for 'Setosa', 'Versicolor', and % 'Virginica', respectively. sum(votes) == K % % Example: % % K = 5; % we want now classify according to 5 nearest neighbours % for m = [1 : % distances = ; % % vector containing Euclidian distances from % % the testvector "x" with index m (sTestD.data(m,:), % % sTestD.label{m}), to each of vectors in training set % % sTrainD.data, size (60 x 1) % [c_ok, class_by_kNN, votes] = ... % myKnnClass(K, sTestD.label{m}, distances); % % end; % % % Demo results with e.g. sTestD.label{2} == 'Virginica' % % c_ok == 1 --> classification of sTestD.data(2,:) was correct % % class_by_kNN == 'Virginica' --> classifier gave Virginica % % votes = [0 0 5] --> all 5 closest neighbours to a test point % % were Virginica % % % Demo results with e.g. sTestD.label{4} == 'Versicolor' % % c_ok == 0 --> classification of sTestD.data(4,:) was incorrect % % class_by_kNN == 'Virginica' --> classifier gave Virginica % % votes = [0 2 3] --> 2 closest neighbours to a test point % % were Versicolor, 3 closest to Virginica % % Jukka Parviainen, 9.11.2006 / 16.12.2005 / 28.11.2005 % Vectors of the first class in training set % are sTrainD.data(classBorders(1):classBorders(2), :), % the second set sTrainD.data(classBorders(3):classBorders(4), :), % and last class sTrainD.data(classBorders(5):classBorders(6), :). classBorders = [1 20 21 40 41 60]; % Vector "distances" is normally euklidian distance from % the test sample x to each training point, % distances(1) = ((x_1 - t_1)^2 + (x_2 - t_2)^2 + ...). % Square root is not needed because only ordering is needed. if (prod(size(distances)) ~= classBorders(6)) error('Wrong size of vector "distances"'); end; [s1, s2] = sort(distances); KNInd = s2(1:K); % K closest neighbours votes(1) = sum((KNInd >= classBorders(1)) & (KNInd <= classBorders(2))); votes(2) = sum((KNInd >= classBorders(3)) & (KNInd <= classBorders(4))); votes(3) = sum((KNInd >= classBorders(5)) & (KNInd <= classBorders(6))); [m1, m2] = sort(votes, 'descend'); % if equal, then flip the coin if (m1(1) == m1(2)) if (rand(1,1) >= 0.5) tmp = m1(1); m1(1) = m1(2); m1(2) = tmp; tmp = m2(1); m2(1) = m2(2); m2(2) = tmp; end; end; if (strcmp(realClassX, 'Setosa')) rCXInd = 1; elseif (strcmp(realClassX, 'Versicolor')) rCXInd = 2; elseif (strcmp(realClassX, 'Virginica')) rCXInd = 3; else error('Unknown class type'); end; if (m2(1) == rCXInd) classOK = 1; else classOK = 0; end; switch m2(1) case 1, knnClass = 'Setosa'; case 2, knnClass = 'Versicolor'; case 3, knnClass = 'Virginica'; otherwise error('Unknown class label'); end;