1. 程式人生 > >KNN分類演算法及MATLAB程式與結果

KNN分類演算法及MATLAB程式與結果

K鄰近演算法

 

KNN演算法的決策過程

  k-Nearest Neighbor algorithm 
  右圖中,綠色圓要被決定賦予哪個類,是紅色三角形還是藍色四方形?如果K=3,由於紅色三角形所佔比例為2/3,綠色圓將被賦予紅色三角形那個類,如果K=5,由於藍色四方形比例為3/5,因此綠色圓被賦予藍色四方形類。
  K最近鄰(k-Nearest Neighbor,KNN)分類演算法,是一個理論上比較成熟的方法,也是最簡單的機器學習演算法之一。該方法的思路是:如果一個樣本在特徵空間中的k個最相 似(即特徵空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。KNN演算法中,所選擇的鄰居都是已經正確分類的物件。該方法在定類決 策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。 KNN方法雖然從原理上也依賴於極限定理,但在類別決策時,只與極少量的相鄰樣本有關。由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方 法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合。
  KNN演算法不僅可以用於分類,還可以用於迴歸。通過找出一個樣本的k個最近鄰居,將這些鄰居的屬性的平均值賦給該樣本,就可以得到該樣本的屬性。更有用的方法是將不同距離的鄰居對該樣本產生的影響給予不同的權值(weight),如權值與距離成正比。
  該演算法在分類時有個主要的不足是,當樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量 很小時,有可能導致當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本佔多數。因此可以採用權值的方法(和該樣本距離小的鄰居權值大)來改進。該方法 的另一個不足之處是計算量較大,因為對每一個待分類的文字都要計算它到全體已知樣本的距離,才能求得它的K個最近鄰點。目前常用的解決方法是事先對已知樣 本點進行剪輯,事先去除對分類作用不大的樣本。該演算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域採用這種演算法比較容易產生誤 分。

        相比於之前介紹的SVM及BP演算法,KNN演算法思想比較簡單,它沒有訓練出模板model,然後利用model進行測試的過程,而是直接就是訓練,利用已知的有標記的樣本,進來一個樣本就計算它與這些已知樣本的距離,然後對這些距離中挑K個最小的進行投票,看K個最接近的樣本中哪一個樣本所佔的個數多,就判斷為哪一類。

前面也提到了KNN演算法的一個當樣本不平衡時,如一個類的樣本容量很大,而其他類樣本容量 很小時,有可能導致當輸入一個新樣本時,該樣本的K個鄰居中大容量類的樣本佔多數,為此我覺得可以在每類中隨機抽取相同的樣本數進行重組成新的樣本,然後再進行KNN演算法,記為改進方法1,或者調節距離的權重,距離越小的投票時的權重值就越大,記為改進方法2。下面是KNN演算法的MATLAB程式碼,及沒有用隨機抽樣的方法進行的試驗結果(三類資料分別為150 50 50),和改進方法1,及改進方法2的結果對比。

未改進的結果,由於其中一類樣本是150個,其他兩類是50,所以資料有偏斜,結果為:

整體分類精度為:0.90476
類別1的分類精度為:0.94118
類別2的分類精度為:0.58824
類別3的分類精度為:1

改進方法一,隨機抽樣組成新的樣本,新樣本中,各類的樣本數相同。結果為:

整體分類精度為:0.94048
類別1的分類精度為:0.94118
類別2的分類精度為:0.76471
類別3的分類精度為:1

改進方法二,增大最小距離的投票權重,當然也可能是我的權重選的不合適,結果為:

整體分類精度為:0.90476
類別1的分類精度為:0.94118
類別2的分類精度為:0.58824
類別3的分類精度為:1

可見和沒加權重的未改進結果相同,當然我也試過好多數值,如果不當,精度還會下降。

把改進方法一和改進方法二相結合的結果:

整體分類精度為:0.90476
類別1的分類精度為:0.94118
類別2的分類精度為:0.76471
類別3的分類精度為:0.94

只是類別三的精度相對於改進方法一有所下降,所以看來還是樣本資料的分均勻程度對分類的結果影響比較大。

下面是程式的原始碼:

clear all;
close all;
clc;
load D:\碩士學習資料3\碩士畢設資料\區域生長等分割演算法程式\遺傳分割\MYGAseg\特徵選擇\traindata.mat
load D:\碩士學習資料3\碩士畢設資料\區域生長等分割演算法程式\遺傳分割\MYGAseg\特徵選擇\testdata.mat
load D:\碩士學習資料3\碩士畢設資料\區域生長等分割演算法程式\遺傳分割\MYGAseg\特徵選擇\trainlabel.mat
load D:\碩士學習資料3\碩士畢設資料\區域生長等分割演算法程式\遺傳分割\MYGAseg\特徵選擇\testlabel.mat
 traindata=traindata(1:99,:);
 trainlabel=trainlabel(1:99,1);
[predictlabel,acc]=myKNN(traindata,trainlabel,testdata,testlabel,15);

function [predictlabel,acc]=myKNN(traindata,trainlabel,testdata,testlabel,K)
[mtrain,ntrain]=size(traindata);
[mtest,ntest]=size(testdata); 
juli=zeros(mtest,mtrain);%每一行儲存的是一個樣本與所有訓練樣本的距離
sortjuli=zeros(mtest,mtrain);
zuobiaojuli=zeros(1,mtest);
num1=0;
num2=0;
num3=0;
rightnum=0;%記錄整體分類正確的個數
rightnum1=0;
rightnum2=0;
rightnum3=0;
for i=1:mtest
    for j=1:mtrain
        juli(i,j)=sqrt((sum(testdata(i,:)-traindata(j,:)).^2));%計算每個測試樣本與每個訓練樣本的oushi距離
    end
end
for i=1:mtest
   [ sortjuli,zuobiaojuli]=sort(juli(i,:));%sort函式預設返回的是由小到大的排序結果
   sorttrainlabel=trainlabel(zuobiaojuli);%標籤也相應的改變順序
   ksortjuli(1,:)=sortjuli(1,1:K);%取距離和座標的前k個
   ksorttrainlabel=sorttrainlabel(1:K,1);
   for j=1:K%統計前K個結果中那個的數目多
       if j==1%如果是排在第一位的,也就是距離最小的,那麼投票權重加大4
         if  ksorttrainlabel(j,1)==1
           num1=num1+5;
       end
       if  ksorttrainlabel(j,1)==2
           num2=num2+5;
       end
       if  ksorttrainlabel(j,1)==3
           num3=num3+5;
       end  
       elseif j==2%排在第二位的權重加大2,當然也可以自行改變
           if  ksorttrainlabel(j,1)==1
           num1=num1+2;
       end
       if  ksorttrainlabel(j,1)==2
           num2=num2+2;
       end
       if  ksorttrainlabel(j,1)==3
           num3=num3+2;
       end  
       else
       if  ksorttrainlabel(j,1)==1
           num1=num1+1;
       end
       if  ksorttrainlabel(j,1)==2
           num2=num2+1;
       end
       if  ksorttrainlabel(j,1)==3
           num3=num3+1;
       end   
       end
   end
    A=[num1 num2 num3];
    Xsort=sort(A);%按照從小到大排序
        if Xsort(1,end)==num1
            predictlabel(i,1)=1;
        elseif Xsort(1,end)==num2
            predictlabel(i,1)=2;
        elseif Xsort(1,end)==num3
            predictlabel(i,1)=3;
        end
        if predictlabel(i,1)==testlabel(i,1)
            rightnum=rightnum+1;
        end         
        if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==1
            rightnum1=rightnum1+1;
        end    
        if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==2
            rightnum2=rightnum2+1;
        end     
        if predictlabel(i,1)==testlabel(i,1)&&testlabel(i,1)==3
            rightnum3=rightnum3+1;
        end     
        
        num1=0;%清0
        num2=0;
        num3=0;
end
leibie1=size(find(testlabel==1),1);%找出測試樣本1的個數
leibie2=size(find(testlabel==2),1);
leibie3=size(find(testlabel==3),1);
acc1=rightnum1/leibie1;
acc2=rightnum2/leibie2;
acc3=rightnum3/leibie3;
acc=rightnum/mtest;%總體分類精度
disp(['整體分類精度為:',num2str(acc)]);
disp(['類別1的分類精度為:',num2str(acc1)]);
disp(['類別2的分類精度為:',num2str(acc2)]);
disp(['類別3的分類精度為:',num2str(acc3)]);

K最鄰近密度估計技術是一種分類方法,不是聚類方法。

不是最優方法,實踐中比較流行。

通俗但不一定易懂的規則是:

1.計算待分類資料和不同類中每一個數據的距離(歐氏或馬氏)。

2.選出最小的前K資料個距離,這裡用到選擇排序法。

3.對比這前K個距離,找出K個數據中包含最多的是那個類的資料,即為待分類資料所在的類。

不通俗但嚴謹的規則是:

給定一個位置特徵向量x和一種距離測量方法,於是有:

1.在N個訓練向量外,不考慮類的標籤來確定k鄰近。在兩類的情況下,k選為奇數,一般不是類M的倍數。

2.在K個樣本之外,確定屬於wi,i=1,2,...M類的向量的個數ki,顯然sum(ki)=k。

3.x屬於樣本最大值ki的那一類wi。