K-近鄰算法的Python實現 : 源代碼分析


網上介紹K-近鄰算法的樣例非常多。其Python實現版本號基本都是來自於機器學習的入門書籍《機器學習實戰》,盡管K-近鄰算法本身非常easy,但非常多剛開始學習的人對其Python版本號的源碼理解不夠,所以本文將對其源碼進行分析。


什么是K-近鄰算法?

簡單的說,K-近鄰算法採用不同特征值之間的距離方法進行分類。所以它是一個分類算法。

長處:無數據輸入假定,對異常值不敏感

缺點:復雜度高


好了,直接先上代碼,等會在分析:(這份代碼來自《機器學習實戰》)

def classify0(inx, dataset, lables, k):
    dataSetSize = dataset.shape[0]
    diffMat = tile(inx, (dataSetSize, 1)) - dataset
    sqDiffMat = diffMat**2
    sqDistance = sqDiffMat.sum(axis=1)
    distances = sqDistance**0.5
    sortedDistances = distances.argsort()
    classCount={}
    for i in range(k):
        label = lables[sortedDistances[i]]
        classCount[label] = classCount.get(label, 0) + 1
    sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

 

該函數的原理是:

存在一個樣本數據集合,也稱為訓練集,在樣本集中每一個數據都存在標簽。在我們輸入沒有標簽的新數據后,將新數據的每一個特征與樣本集中相應的特征進行比較,然后提取最相似(近期鄰)的分類標簽。

一般我們僅僅選樣本數據集中前K 個最相似的數據。最后。出現次數最多的分類就是新數據的分類。


classify0函數的參數意義例如以下:

inx : 是輸入沒有標簽的新數據,表示為一個向量。

dataset: 是樣本集。

表示為向量數組。

labels:相應樣本集的標簽。

k:即所選的前K。


用於產生數據樣本的簡單函數:


def create_dataset():
    group = array([[1.0, 1.1], [1.0, 1.1], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


注意,array是numpy里面的。

我們須要實現import進來。

from numpy import *
import operator


我們在調用時。

group,labels = create_dataset()
result = classify0([0,0], group, labels, 3)
print result

顯然,[0,0]特征向量肯定是屬於B 的,上面也將打印B。


知道了這些。剛開始學習的人應該對實際代碼還是非常陌生。不急,正文開始了!


源代碼分析


dataSetSize = dataset.shape[0]

shape是array的屬性,它描寫敘述了一個數組的“形狀”,也就是它的維度。比方,

In [2]: dataset = array([[1.0, 1.1], [1.0, 1.1], [0, 0], [0, 0.1]])

In [3]: print dataset.shape
(4, 2)

所以,dataset.shape[0] 就是樣本集的個數。


diffMat = tile(inx, (dataSetSize, 1)) - dataset

tile(A,rep)函數是基於數組A來構造數組的,詳細怎么構造就看第二個參數了。其API介紹有點繞,但簡單的使用方法相信幾個樣例就能明確。

我們看看tile(inx, (4, 1))的結果,

In [5]: tile(x, (4, 1))
Out[5]: 
array([[0, 0],
       [0, 0],
       [0, 0],
       [0, 0]])

你看。4擴展的是數組的個數(本來1個。如今4個),1擴展的是每一個數組元素的個數(原來是2個,如今還是兩個)。

為證實上面的結論,

In [6]: tile(x,(4,2))
Out[6]: 
array([[0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0]])

和。

In [7]: tile(x,(2,2))
Out[7]: 
array([[0, 0, 0, 0],
       [0, 0, 0, 0]])

關於,tile的詳細使用方法。請自行查閱API DOC。


得到tile后,減去dataset。

這類似一個矩陣的減法。結果仍是一個 4 * 2的數組。

In [8]: tile(x, (4, 1)) - dataset
Out[8]: 
array([[-1. , -1.1],
       [-1. , -1.1],
       [ 0. ,  0. ],
       [ 0. , -0.1]])

結合歐式距離的求法,后面的代碼就清晰些,對上面結果平方運算,求和。開方。

我們看看求和的方法,

sqDiffMat.sum(axis=1)

當中。

In [14]: sqDiffmat
Out[14]: 
array([[ 1.  ,  1.21],
       [ 1.  ,  1.21],
       [ 0.  ,  0.  ],
       [ 0.  ,  0.01]])


求和的結果是對行求和,是一個N*1的數組。

假設要對列求和,

sqlDiffMat.sum(axis=0)

argsort()是對數組升序排序的。


classCount是一個字典,key是標簽。value是該標簽出現的次數。


這樣。算法的一些詳細代碼細節就清楚了。





免責聲明!

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



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