k artimiausių kaimynų metodas KNN
KNN (k nearest neighbors) metodas klasifikuoja tikrindamas kokioms klasėms priklauso artimiausi K kaimynai ir priskiria tai klasei, kuriai priklauso daugelis K kaimynų. Įėjimo vektorius gali turėti bet kokį požymių kiekį, pvz.: 1, 2, 10 ir daugiau. Euklido atstumą naudosime skaičiuojant atstumą tarp kaimynų, kurį lengva paskaičiuoti net ir daug dimensijų turinčiai erdvei. Išbandysime pasirašyti savo KNN funkciją bei palyginti rezultatą su Matlab knnclassify funkcija naudojant dvejų dimensijų duomenų aibę. Abejų klasių duomenys (0 – raudona, 1 – žalia) parodyti žemiau:
Eksperimentas labai paprastas. Užkrausime duomenis, kurie turi du požymius, o pačių duomenų yra kiek daugiau nei tūkstantis. Apmokymui imsime dešimt procentų duomenų atsitiktine tvarka, o tikslumą tikrinsime su likusiais.
Programa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | clc; close all; load apple.txt data = apple; % duomenys išmaišomi atsitiktine tvarka, nes kas kartą norime % naudoti vis kitą imti apmokymui, o likutį testavimui data = data(randperm(size(data, 1)), :); clear apple; % atvaizduojam abi klases figure(1); clf; hold on l = data(:, 3) == 0; d1 = data(l, 1 : 2)'; d2 = data(~l, 1 : 2)'; plot(d1(1, :), d1(2, :), 'r+'); plot(d2(1, :), d2(2, :), 'g+'); axis('equal'); p = 10; % kiek duomenų skirti apmokymui procentais features = 2; % požymių kiekis k = 3; % kiek kaimynų naudoti klasifikuojant q = int16(size(data, 1) * p / 100); % kiek duomenų skirti apmokymui training = data(1 : q, 1 : features); % apmokymo duomenys plot(training(:, 1), training(:, 2), 'b.'); % pažymėti, kurie duomenys dalyvauja apmokyme group = data(1 : q, features + 1); % apmokymo duomenų klasės total = size(data, 1); % duomenų kiekis correct1 = 0; correct2 = 0; for i = q + 1 : total % testuoti tik su tais duomenimis, kurie nenaudojami apmokymui g = data(i, features + 1); sample = data(i, 1 : features); c = knnclassify(sample, training, group, k); if c == g correct1 = correct1 + 1; else fprintf('Klaida: %d \n', i); end; c = myknnclassify(sample, training, group, k); if c == g correct2 = correct2 + 1; else fprintf('Klaida: %d \n', i); end; fprintf('Total iterations: %d, done: %d\n', total - q, i - q); end; fprintf('knnclassify rezultatas: %4.2f %%\n', 100 * correct1 / (total - q)); fprintf('myknnclassify rezultatas: %4.2f %%\n', 100 * correct2 / (total - q)); |
KNN funkcija:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function [class] = myknnclassify(sample, training, group, k) A = zeros(1, 2); % matrica artimiausiems kaimynams saugoti n = size(training, 1); % iš viso kaimynų kiekis for i = 1 : n % kiekvienam kaimynui atliekami skaičiavimai d = euclidean_distance(training(i, :), sample); % randamas Euklido atstumas s = size(A, 1); if s < k % jeigu artimiausių kaimynų atrinkta mažiau nei K, tai papildom A(s + 1, 1 : 2) = [group(i) d]; elseif A(k, 2) > d % jeigu artimiausių kaimynų atrinkta K, tolimiausią keičiam artimesniu A(k, 1 : 2) = [group(i) d]; end; A = sortrows(A, 2); % išrūšiuojam pagal atstumą end; m = max(group) + 1; % klasių kiekis B = zeros(1, m); for i = 1 : k % randam po kiek artimiausių kaimynų priklauso kiekvienai klasei B(A(i, 1) + 1) = B(A(i, 1) + 1) + 1; end; [maxC, maxI] = max(B); % klasės indeksas, kurioje daugiausiai artimiausių kaimynų [minC, minI] = min(B); % klasės indeksas, kurioje mažiausiai artimiausių kaimynų if maxC > minC % laimėtoja klasė, kuri turi daugiausia artimiausių kaimynų class = maxI - 1; else % jeigu visos klasės turi vienodą kaimynų kiekį (gali būti ir kitokie kriterijai) class = -1; % atmetimo (reject) klasė end; |
Euklido atstumas:
1 2 3 4 5 6 7 | function [d] = euclidean_distance(x, y) n = size(x, 2); d = 0; for i = 1 : n d = d + (x(i) - y(i)) ^ 2; end; d = d ^ 0.5; |
Abejų funkcijų rezultatai yra gana panašūs. Kadangi duomenų klasės nepersidengia ir yra gana toli viena nuo kitos, tai pakanka vos kelių procentų apmokymo duomenų, kad visus likusius duomenis abi funkcijos klasifikuotų šimto procentų tikslumu. Žemiau esančiame paveiksliuke matosi mėlynai pažymėti taškai, kurie buvo naudojami apmokymui ir yra atrinkti atsitiktine tvarka (vos 10 procentų nuo visų duomenų). Kiekvieną kartą užkrovus duomenis, parenkama vis kita 10 procentų duomenų imtis apmokymui, taip mes galime matyti kaip funkcijų tikslumas priklauso nuo skirtingų duomenų aibių, tačiau išlaikant norimą jos dydį:
myknnclassify funkcija yra dešimt kartų lėtesnė nei Matlab standartinė funkcija knnclassify ir kiek testavau, mažiau tiksli. Be to, aprašytoje gali būti (ir tikriausiai yra) klaidų, nes ji nėra pilnai ištestuota kaip Matlab funkcija. Todėl Matlab funkcija yra gerokai pranašesnė, kuri be to dar turi ir įvairių papildomų parametrų.

