KNN算法(K近鄰算法)實現與剖析


KNN(K-Nearest Neighbors)算法,又稱K近鄰算法,單從字面意思我們就能知道,這個算法肯定是和距離有關的。

KNN算法的核心思想:

在一個特征空間中,如果某個樣本身邊和他最相鄰的K個樣本大多都屬於一個類別,那么這個樣本在很大程度上也屬於這個類別,且該樣本同樣具有這個類別的特性。

其實說白了就是“近朱者赤、近墨者黑”,你身邊離你最近的K個人中大多數人都屬於某一個類別,那么你很有可能也屬於這一個類別(當然,用人來舉例子不是很恰當)

該方法在“分類決策”上只依據最近鄰的k個樣本的類別來判斷待分樣本的類別,K通常是不大於20的一個整數,具體怎么選取,這個也很有學問,后邊會詳細講解。

 

上邊說了,一個待分樣本的所屬的類別,很大程度上取決於和他最近的K個樣本的類別,那么這個“最近”是如何計算出來的呢,比如一堆人站在一塊兒,我們可以可以輕易的計算出

一個人距他身邊的每個人的距離,那么數據呢?其實道理是一樣的,我們可以使用歐拉距離來計算,其實我們在中學幾何中學習二維平面內兩點間距離、三維空間內兩點間距離時已經學過了,

我們可以將二維數據看作是這兩個點都只有兩個特征,三維數據可以看成是有三個特征,那么當一組數據中每個數據都有多個特征時,我們也可以將其看作是多維空間中的一個點,

也同樣可以使用歐拉距離來計算。

   

 

        

 

 

 當拓展到多個特征之后,就會簡寫成上邊紅框中的公式,這在機器學習算法中較為常見。

KNN算法的計算步驟:

(1)計算待分類數據與各個樣本數據之間的距離

(2)對距離進行排序

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

(4)統計前k個點所屬的類別

(5)返回前K個點出現頻率最高的類別做為待分類數據的預測分類

 

手動封裝一個KNN算法:

import math
import numpy as np
from collections import Counter

class NKKClass(object):

    def __init__(self, K):
        # 初始化KNN類屬性
        assert K > 0, "常數K需為正整數"
        self.K = K
        self._X_train = None  # 私有的訓練特征數組
        self._y_train = None  # 私有的訓練標簽向量


    def fit(self, X_train, y_train):
        # 根據訓練特征數組X_train和標簽向量y_train來訓練模型(當然,KNN算法中是不需要訓練模型的)
        self._X_train = X_train
        self._y_train = y_train

    def predict(self, X_predict):
        # 傳入待預測的特征數據集X_predict,返回這個特征數據集所對應的標簽向量
        y_predict = [self._predict(i) for i in X_predict]
        return y_predict

    def _predict(self, i):
        # 給定單個特征數據,根據計算歐拉距離,返回預測標簽
        # 利用歐拉距離計算兩點間距離
        distances = [ math.sqrt(np.sum((x_train - i)**2))  for x_train in  self._X_train]
        nearset = np.argsort(distances)  #將數組升序排序,然后提取其所對應的索引index進行返回
        # 根據索引取出標簽向量中的值
        topK_y = [ self._y_train[index] for index in nearset[:self.K]]
        # 統計array中每個元素出現頻率,n=1表示取出出現頻率最高的那個元素
        votes = Counter.most_common(n=1)[0][0]
        return votes
  
def accuracy_score(self, y_test, y_predict):     # 根據train_test_split得到的y_test和預測得到的y_predict計算分類准確度     return sum(y_true == y_predict) / len(y_true)
  
def score(self, X_test, y_test):     # 根據 train_test_split拆分出來的X_test,y_test直接計算分類准確度     y_predict = self.predict(X_test)     return self.accuracy_score(y_test, y_predict)

 

上邊這個類其實就是模仿着 scikit-learn機器學習庫中封裝的的kNN算法來寫的。

 

下邊我們來加載  sklearn 庫中自帶的鳶尾花數據集來測試一下吧

 

 

我們獲取到數據集后,並不能直接將所有數據集都作為訓練數據集,還是需要留下一小部分作為測試數據集的,所以又牽扯到train_test_split的問題,而且鳶尾花數據集已經默認排過序了,

所以我們在進行train_test_split之前還需要先將特征數據集和標簽向量進行亂序才行的。

 

 

 

 

 

其實這個train_test_split過程,在sklearn中已經封裝好了,可以直接調用。

from sklearn.model_selection import train_test_split

train_test_split函數有4個參數,並且返回四個返回值:

4個參數:

train_data:需要被拆分的特征數組

train_target:需要被拆分的標簽向量

test_size:如果是浮點數,在0-1之間,表示測試數據集占總數據集的百分比,如果是整數,代表測試數據集的行數。

random_state:隨機種子,默認為None

4個返回值:

X_train 訓練特征數組

X_test 測試特征數組

y_train 訓練標簽向量

y_test 測試標簽向量

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=666)

 接下來調用sklearn庫,直接使用KNN算法對鳶尾花數據集進行預測,計算分類准確度:

# 加載sklearn庫中KNN算法的類
from sklearn.neighbors import KNeighborsClassifier
# 加載sklearn自帶的數據包
from sklearn import datasets
# 加載sklearn自帶的train_test_split函數
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


# 加載數據包中自帶的小數據集(鳶尾花數據集)
iris = datasets.load_iris()
X = iris.data  # 數據集的特征矩陣
y = iris.target  # 數據集的標簽向量

# 將數據集拆分,二八分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=5)

# 實例化,n_neighbors就是KNN算法中的那個K
KNN_classifier = KNeighborsClassifier(n_neighbors=6)
KNN_classifier.fit(X_train, y_train)  # 對訓練數據集進行擬合

predict_y_test = KNN_classifier.predict(X_test)  # 對測試的特征數組進行預測
# 針對train_test_split得到的y_test和預測出來的標簽向量進行計算分類准確度
Classification_accuracy = accuracy_score(y_test, predict_y_test)
print(Classification_accuracy)
# 針對train_test_split得到的測試用的特征數組和標簽向量,直接計算其分類准確度(不用先計算出測試標簽向量)
Classification_accuracy = KNN_classifier.score(X_test, y_test)
print(Classification_accuracy)

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM