1. 程式人生 > >機器學習之KNN(k近鄰)演算法

機器學習之KNN(k近鄰)演算法

1、演算法介紹
k近鄰演算法是學習機器學習的入門演算法,可實現分類與迴歸,屬於監督學習的一種。演算法的工作原理是:輸入一個訓練資料集,訓練資料集包括特徵空間的點和點的類別,可以是二分類或是多分類。預測時,輸入沒有類別的點,找到k個與該點距離最接近的點,使用多數表決的方法,得出最後的預測分類。


2、演算法優缺點
優點:沒有高深的數學思想,容易理解,精度高,對異常值不敏感,無資料輸入假定;
缺點:計算複雜度高,空間複雜度高;
理解:因為knn演算法是尋找與目標點接近的點,在計算時,異常值與目標點的“距離”會較遠,所以對於異常值不敏感。但是,對於每一個目標點,都要計算一次。若是訓練資料集數量很大,且資料集的點維度高,這樣計算起來十分費時。因此,也誕生了kd樹等優化演算法。


3、演算法三要素
knn演算法三要素分別為:度量距離,k值,決策規則。
3.1、度量距離
特徵空間中的兩個例項點的距離是兩個例項點相似程度的反映。K近鄰法的特徵空間一般是n維實數向量空間R^n。
對於兩個樣本點之間
機器學習之KNN(k近鄰)演算法
距離(閔可夫斯基(Minkowski)距離)定義為
機器學習之KNN(k近鄰)演算法
當p=1時,該距離稱為曼哈頓距離,也稱為街區距離;
當p=2時,該距離稱為歐式距離,這也是高中數學中求二維空間或是三維空間中兩點距離的方法;knn演算法也一般取歐式距離。
當p為無窮大時,該距離稱為切比雪夫距離。
3.2、k值
k值的選擇會對k近鄰法的結果產生重大影響。在應用中,k值一般取一個比較小的數值,通常採用交叉驗證法來選取最優的k值。
3.3、決策規則


通常採用多數表決的方式,在k個距離較近的點中,哪一個分類較多即作為最後的預測結果。


4、數學例子
訓練資料集

x1 x2 分類
1 1.1 A
1 1 A
0 0 B
0 0.2 B

測試資料集(0,0.1)
對於(0,0.1),取歐式距離,k=3:
L=[(1-0)^2+(1.1-0.1)^2]^0.5=√2
L=[(1-0)^2+(1-0.1)^2]^0.5=√1.81
L=[(0-0)^2+(0-0.1)^2]^0.5=√0.01
L=[(0-0)^2+(0.2-0.1)^2]^0.5=√0.01
取k=3,即取L=√1.81,A類;L=√0.01,B類;L=√0.01,B類;
根據多數表決規則,(0,0.1)屬於B類


5、資料預處理:歸一化數值
為了防止某一特徵對結果的影響太大,故常採用資料歸一化對資料進行預處理。
歸一化是將特徵數值轉化為0到1之間的值
公式為:newValue = (oldValue - min)/(max - min)


6、knn演算法程式碼實現
6.1、Python程式碼:

def calDistance(vector1, vector2, q):#定義計算閔可夫斯基距離的函式
    distance = 0.0
    n = len(vector1)
    for i in range(n):
        distance += pow(abs(vector1[i] - vector2[i]), q)
    return round(pow(distance, 1.0 / q), 3)

def findNearestNeighbor(train_x,train_y,item,q=2,k=10):
    neighbors = []#儲存訓練集與目標點的結果【訓練集點,該點分類,距離】
    k_neighbors = {}#儲存十個近鄰的結果及投票次數
    for x,y in zip(train_x,train_y):#遍歷訓練集和目標點的距離,並存儲在neighbors
        distance = calDistance(x,item,q)
        neighbors.append([x,y,distance])
    neighbors.sort(key=lambda x:x[2])#根據距離進行排序
    for i in range(k):#遍歷結果,將k個最近鄰的點的結果寫成字典形式
        k_neighbors.setdefault(neighbors[i][1],0)
        k_neighbors[neighbors[i][1]] += 1

    # 返回排序後的k個近鄰鍵值對
    nearest_neighbor = sorted(k_neighbors.items(),key=lambda x:x[1],reverse=True)
    #返回最大的投票數那個key
    return nearest_neighbor[0][0]

if __name__ == '__main__':
    data_x = [[1,1],[1,1.1],[0,0],[0,0.2]]
    data_y = ['A','A','B','B']
    item = [0,0]
    q = 2
    k = 3
    result = findNearestNeighbor(train_x=data_x,train_y=data_y,item=item,q=q,k=k)
    print('預測分類為:',result)

6.2、sklearn庫的實現

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn import datasets

iris = datasets.load_iris()#鳶尾花資料是一個字典,鳶尾花特徵的key是data,型別的key是target
iris_X = iris.data# 拆分屬性資料
iris_y = iris.target# 拆分類別資料
# 拆分測試集和訓練集,並進行預測,其中訓練集80%,測試集20%
iris_X_train , iris_X_test, iris_y_train ,iris_y_test = train_test_split(iris_X, iris_y, test_size=0.2,random_state=0)

knn = KNeighborsClassifier(n_neighbors=10,p=2)#建立knn演算法
knn.fit(iris_X_train, iris_y_train)# 提供訓練集進行訓練
predict_result = knn.predict(iris_X_test)# 預測測試集鳶尾花型別
correct_rate = knn.score(iris_X_test, iris_y_test)#計算正確率

print('預測結果',predict_result)
print('預測準確率',str(correct_rate*100)+'%')

參考書籍:
《統計學習方法》--李航
《機器學習實戰》--Peter


本次的學習就到此結束啦!感興趣的讀者或者想和我聊聊的請私信我,或者關注公眾號:程式設計師吃橘子