【Machine learing】之KNN

進入大學最先接觸的是機器學習,吳恩達老師的機器學習課程激起了我學習的興趣,因此自己很想深入的瞭解機器學習算法,加之很想學好python,在此驅動下,我堅持學習Machine learning的相關算法。
最簡單最初級的分類器是將全部的訓練數據所對應的類別都記錄下來,當測試對象的屬性和某個訓練對象的屬性完全匹配時,便可以對其進行分類。但是怎麼可能所有測試對象都會找到與之完全匹配的訓練對象呢,其次就是存在一個測試對象同時與多個訓練對象匹配,導致一個訓練對象被分到了多個類的問題,基於這些問題呢,就產生了KNN。

1.KNN概述

KNN是通過測量不同特徵值之間的距離進行分類。它的思路是:如果一個樣本在特徵空間中的k個最相似(即特徵空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別,其中K通常是不大於20的整數。KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。

下面通過一個簡單的例子說明一下:如下圖,綠色圓要被決定賦予哪個類,是紅色三角形還是藍色四方形?如果K=3,由於紅色三角形所佔比例爲2/3,綠色圓將被賦予紅色三角形那個類,如果K=5,由於藍色四方形比例爲3/5,因此綠色圓被賦予藍色四方形類。
在這裏插入圖片描述
由此也說明了KNN算法的結果很大程度取決於K的選擇。

在KNN中,通過計算對象間距離來作爲各個對象之間的非相似性指標,避免了對象之間的匹配問題,在這裏距離一般使用歐氏距離或曼哈頓距離:
在這裏插入圖片描述
同時,KNN通過依據k個對象中佔優的類別進行決策,而不是單一的對象類別決策。這兩點就是KNN算法的優勢。

接下來對KNN算法的思想總結一下:就是在訓練集中數據和標籤已知的情況下,輸入測試數據,將測試數據的特徵與訓練集中對應的特徵進行相互比較,找到訓練集中與之最爲相似的前K個數據,則該測試數據對應的類別就是K個數據中出現次數最多的那個分類,其算法的描述爲:

1)計算測試數據與各個訓練數據之間的距離;

2)按照距離的遞增關係進行排序;

3)選取距離最小的K個點;

4)確定前K個點所在類別的出現頻率;

5)返回前K個點中出現頻率最高的類別作爲測試數據的預測分類。

2.Python實現

首先,建立一個KNN.py文件對算法的可行性進行驗證,如下:

#coding:utf-8

from numpy import *
import operator

##給出訓練數據以及對應的類別
def createDataSet():
    group = array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5]])
    labels = ['A','A','B','B']
    return group,labels

###通過KNN進行分類
def classify(input,dataSe t,label,k):
    dataSize = dataSet.shape[0]
    ####計算歐式距離
    diff = tile(input,(dataSize,1)) - dataSet
    sqdiff = diff ** 2
    squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而得到新的一個行向量
    dist = squareDist ** 0.5
    
    ##對距離進行排序
    sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標

    classCount={}
    for i in range(k):
        voteLabel = label[sortedDistIndex[i]]
        ###對選取的K個樣本所屬的類別個數進行統計
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    ###選取出現的類別次數最多的類別
    maxCount = 0
    for key,value in classCount.items():
        if value > maxCount:
            maxCount = value
            classes = key

    return classes

接下來,在命令行窗口輸入如下代碼:

#-*-coding:utf-8 -*-
import sys
sys.path.append("...文件路徑...")
import KNN
from numpy import *
dataSet,labels = KNN.createDataSet()
input = array([1.1,0.3])
K = 3
output = KNN.classify(input,dataSet,labels,K)
print("測試數據爲:",input,"分類結果爲:",output)

回車之後的結果爲:

測試數據爲: [ 1.1 0.3] 分類爲: A

答案符合我們的預期,要證明算法的準確性,勢必還需要通過處理複雜問題進行驗證,之後另行說明。

這是第一次用python編的一個小程序,勢必會遇到各種問題,在此次編程調試過程中遇到了如下問題:

1 導入.py文件路徑有問題,因此需要在最開始加如下代碼:

import sys
  sys.path.append(“文件路徑”),這樣就不會存在路徑有誤的問題了;

2 在python提示代碼存在問題時,一定要及時改正,改正之後保存之後再執行命令行,這一點跟MATLAB是不一樣的,所以在python中最好是敲代碼的同時在命令行中一段一段的驗證;

3 在調用文件時函數名一定要寫正確,否則會出現:‘module’ object has no attribute ‘creatDataSet’;

4 ‘int’ object has no attribute ‘kclassify’,這個問題出現的原因是之前我講文件保存名爲k.py,在執行

output = K.classify(input,dataSet,labels,K)這一句就會出錯。根據函數式編程的思想,每個函數都可以看爲是一個變量而將K賦值後,調用k.py時就會出現問題。

3.MATLAB實現
之前一直在用MATLAB做聚類算法的一些優化,其次就是數模的一些常用算法,對於別的算法,還真是沒有上手編過,基礎還在,思想還在,當然要動手編一下,也是不希望在學python的同時對MATLAB逐漸陌生吧,走走停停,停很重要。
首先,建立KNN.m文件,如下:

%% KNN
clear all
clc
%% data
trainData = [1.0,2.0;1.2,0.1;0.1,1.4;0.3,3.5];
trainClass = [1,1,2,2];
testData = [0.5,2.3];
k = 3;

%% distance
row = size(trainData,1);
col = size(trainData,2);
test = repmat(testData,row,1);
dis = zeros(1,row);
for i = 1:row
    diff = 0;
    for j = 1:col
        diff = diff + (test(i,j) - trainData(i,j)).^2;
    end
    dis(1,i) = diff.^0.5;
end

%% sort
jointDis = [dis;trainClass];
sortDis= sortrows(jointDis');
sortDisClass = sortDis';

%% find
class = sort(2:1:k);
member = unique(class);
num = size(member);

max = 0;
for i = 1:num
    count = find(class == member(i));
    if count > max
        max = count;
        label = member(i);
    end
end

disp('最終的分類結果爲:');
fprintf('%d\n',label)

運行之後的結果是,最終的分類結果爲:2。和預期結果一樣。

以上,是對本次算法的整理和總結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章