機器學習 K-Nearst-Neighbors算法

機器學習 K近鄰(K-Nearest-Neighbors)算法剖析

一、 讀懂該算法所具備的相關知識

  1. 熟練掌握Python語言

  2. 線性代數矩陣常見的基本運算

  3. 歐幾里得定律,計算矩陣中兩點之間的距離。

二、 生活案例-K近鄰算法

電影可以按照題材分類,然而題材本身是如何定義的?由誰來判定某部電影屬於哪個題材?也就是說同一題材的電影具有哪些公共特徵?這些都是在進行電影分類時必須要考慮的問題。每部電影在風格上的確有可能會和同題材的電影相近。那麼動作片具有哪些共有特徵,使得動作片之間非常類似,而與愛情片存在着明顯的差別呢?動作片中也會存在接吻鏡頭,愛情片中也會存在打鬥場景,我們不能單純依靠是否存在打鬥或者親吻來判斷影片的類型。但是愛情片中的親吻鏡頭更多,動作片中的打鬥場景也更頻繁,基於此類場景在某部電影中出現的次數可以用來進行電影分類。

基於電影中出現的親吻、打鬥出現的次數,使用K近鄰算法構造程序,自動劃分電影的題材類型。

簡單地說,K近鄰算法採用測量不同特徵值之間的距離方法進行分類。

K近鄰算法(K-NN), 它的工作原理是:存在一個樣本數據集合,也稱作訓練樣本集,並且樣本集中每個數據都存在標籤,即我們知道樣本集中每一數據與所屬分類的對應關係。輸人沒有標籤的新數據後,將新數據的每個特徵與樣本集中數據對應的特徵進行比較,然後算法提取樣本集中特徵最相似數據(最近鄰)的分類標籤。一般來說,我們只選擇樣本數據集中前K個最相似的數據,這就是K-近鄰算法中K的出處,通常K是不大於20的整數。最後,選擇k個最相似數據中出現次數最多的分類,作爲新數據的分類。

現在我們回到前面電影分類的例子,使用K-近鄰算法分類愛情片和動作片。有人曾經統計過很多電影的打鬥鏡頭和接吻鏡頭,圖2-1顯示了6部電影的打鬥和接吻鏡頭數。

假如有一部未看過的電影,如何確定它是愛情片還是動作片呢?我們可以使用k-近鄰算法來解決這個問題。

接下來有一部未知電影,如圖,首先我們需要知道這個未知電影存在多少個打鬥鏡頭和接吻鏡頭,圖中問號位置是該未知電影出現的鏡頭數圖形化展示,具體數字如下圖

即使不知道未知電影屬於哪種類型,我們也可以通過某種方法計算出來。首先計算未知電影與樣本集中其他電影的距離,如下表所示。此處暫時不要關心如何計算得到這些距離值,使用 Python實現電影分類應用時,會提供具體的計算方

以上主要講解如何在實際環境中應用K-近鄰算法,如果通過Python編程語言來實現K-近鄰算法進而讓機器幫助人類來對電影進行分類,這就是機器學習。

   在動物界,我們可以開發一個鳥類分類系統,這樣鳥類專家就可以下崗了,當有一隻未知類型的鳥,我們只需要通過機器學習k近鄰算法就可以區分出這隻鳥是什麼類型的。

現在我們得到了樣本集中所有電影與未知電影的距離,按照距離遞增排序,可以找到K個距離最近的電影。假定K=3,則三個最靠近的電影依次是<<CaliforniaMan>> <<He’s Not Really into Dudes>> <<BeautifulWoman>> K-近鄰算法按照距離最近的三部電影的類型,決定未知電影的類型,而這三部電影全是愛情片,因此我們判定未知電影是愛情片

三、 K-近鄰算法的基本實現

K-近鄰算法的一般實現流程如下:

a) 收集數據:可以使用任何方法

b) 準備數據:距離計算所需要的數值,最好是結構化的數據格式。

c) 分析數據:可以使用任何方法。

d) 訓練算法:此步驟不適用於1 近鄰算法。

e) 測試算法:計算錯誤率。

f) 使用算法:首先需要輸入樣本數據和結構化的輸出結果,然後運行女-近鄰算法判定輸 入數據分別屬於哪個分類,最後應用對計算出的分類執行後續的處理。

  1. K-近鄰算法訓練數據

    在一個座標中有四組數據如下圖,並且這四個數據都有標籤,能夠標識出這四個數據點都屬於什麼類別的,即標籤類別。現在有一個陌生的數據點過來,請你通過機器學習算法讓機器能夠判斷出該數據點是那個類別的。

group([1, 1], [1, 1.1], [0, 0], [0, 0.1])

A(1, 1) A(1, 1.1) B(0, 0) B(0, 0.1)

Labels= [A, A, B, B]

注意:Label包含的元素個數等於group矩陣的行數

  1. K-近鄰算法實現原理

l 計算已知類別數據集中的點與當前點之間的距離;

l 按照距離遞增次序排序;

l 選取與當前點距離最小的k個點;

l 確定前k個點所在類別的出現頻率;

l 返回前k個點出現頻率最高的類別作爲當前點的預測分類。

  1. 創建一個名爲kNN.pyPython文件,內容如下

from numpy import *

import operator

#算法訓練數據集

def createDataSet():

group =array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])

   # x座標和y座標在1附近的歸類到A,在0附近的點歸類到B

   labels =['A','A','B','B']

   returngroup,labels

#算法實現方法

def classify0(inX, dataSet, labels, k ) :

dataSetSize = daCaSet.shape[0]

#距離計算

diffMat = tile(inX, (dataSetSize,1)) - dataSet

sqDiffMat = diffMat**2

sqDistances = sqDiffMat.sum(axis=l)

distances = sqDistances**O.5

sortedDistIndicies =distances.argaort ()

#選 擇 距 離 最 小 的k個點

classCount={}

for i in range(k):

voteIlabel = labels[sortedDistIndicies[i]]

classCount[votellabel] = classCount.get{voteIlabel,0) + 1

sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1), reverse=True)

return sortedClassCount[0] [0]

  1. 代碼詳細註釋如下:

'''

導入numpy模塊,該模塊用於數據NumPy系統

是Python的一種開源的數值計算擴展。

這種工具可用來存儲和處理大型矩陣。

'''

fromnumpy import *

importoperator #提供了一系列的函數操作

"""

定義機器學習訓練數據集和分類標籤數據。

"""

defcreateDataSet():

group =array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])

   # x座標和y座標在1附近的歸類到A,在0附近的點歸類到B

   labels = ['A','A','B','B']

   return group,labels

"""

實現K-近鄰算法,對數據點進行機器自動分類

   inX:需要讓機器進行分類的數據點例如:[0,0] 或者[1.4,1.6]等數據點

   dataSet:機器學習的訓練數據

   labels:   機器學習的訓練數據的已知分類

   k: inX輸入數據與訓練數據之間的距離個數的前k個,

   這個距離會按照從小到達進行排序。

"""

defclassify0(inX, dataSet, labels, k):

'''

   shape函數用於讀取矩陣的長度,shape[0]

   就是讀取矩陣的第一維度的長度

   根據上面訓練數據集的情況,

   group矩陣第一維的長度是dataSetSize= 4

   '''

   dataSetSize = dataSet.shape[0]



   '''

   tile函數用於創造一個長度爲4的一維矩陣,矩陣中的元素爲inX,

   然後與dataSet訓練矩陣做減法

   矩陣的減法是爲了後面這兩個矩陣中元素之間的距離計算做準備。

   tile(inX,(dataSetSize,1))

          array([[0, 0],

   [0, 0],

   [0, 0],

   [0, 0]])



    dataSet:

             array([[ 1. ,  1.1],

   [ 1. ,  1. ],

   [ 0. ,  0. ],

   [ 0. ,  0.1]])



     兩個矩陣做完減法diffMat結果如下:

          array([[-1. ,-1.1],

   [-1. , -1. ],

   [ 0. ,  0. ],

   [ 0. , -0.1]])

   '''

   diffMat = tile(inX,(dataSetSize,1)) -dataSet

   '''

   sqDiffMat

          array([[ 1.  , 1.21],

   [ 1.  , 1.  ],

   [ 0.  , 0.  ],

   [ 0.  , 0.01]])

   '''

   sqDiffMat = diffMat**2 #對矩陣減法結果做冪次運算

  

   '''

          計算矩陣中每個元素冪次運算之後的和

          sqDistances =array([ 2.21,  2.  , 0.  ,  0.01])

   '''

   sqDistances = sqDiffMat.sum(axis=1)

   '''

   做開平方運算出inX未知點與訓練數據四個點之間的距離

   array([ 1.48660687,  1.41421356,  0. , 0.1])

   '''

   distances = sqDistances**0.5



   '''

          按着inX距離訓練數據點距離的從小到大順序的索引值進行排序

          也及時argsort()函數的返回結果

          排序後從小到大距離的索引值被放到list中[2,3,1,0]

   '''

   sortedDistIndecies = distances.argsort()

  

   #選擇距離最小的k個點

  

   '''

   定義一個空字典,字典中元素key的值爲標籤分類名,即是A或者B

   value的值爲根據距離計算出標籤類別出現的頻率數。

   '''

   classCount = {}

   '''

   這裏k的值是根據訓練數據量來設置的,本次訓練數據爲4個

   所以k的值可以設置爲3就是計算 inX 數據與訓練數據4個的距離

   中取前3個距離來進行統計,看前3個當中inX 得出的標籤分類出現

   的頻率數

   k取3,則在循環中i的值一次爲 0 1 2

   '''

   for i in range(k):

          '''

          sortedDistIndecies[i]的值 當i=0是獲得其中第一個元素的值2

          那麼第一個元素2 就是inX距離四個點之間前k個距離的第一個距離的索引值

          訓練數據如下:

   group =array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])

   labels =['A','A','B','B'] # x座標和y座標在1附近的歸類到A,在0附近的點歸類到B

                 sortedDistIndecies= [2,3,1,0]

                            [1.0,1.1] [1.0,1.0]    [0,0]  [0,0.1]

                                  A(0)      A(1)       B(2)   B(3)

                 array([1.48660687,  1.41421356,  0. , 0.1])

在這裏我們計算出了inX數據點與訓練數據四個點的距離,計算順序也是按着矩陣的元素

排練的順序計算出的,那麼這裏的順序很重要,因爲在訓練數據集中順序和它的標籤分類

是一一對應的,所以計算出的距離索引的值和標籤是一對一對應的。當我們把距離索引的值

按着距離的從小到大排列,然後放到一個list當中,此時索引的值就是標籤的分類了。

這就是 voteIabel = labels[sortedDistIndecies[i]]這一句話的含義。sortedDistIndecies = [2,3,1,0]

'''

voteIlabel =labels[sortedDistIndecies[i]] #獲取第k個距離最小的標籤分類

         

          '''

          這裏的+1 是爲了計算classCount字典中key對應的value的值,key其實就是標籤的分類

          value的值,就是某一分類出現的次數,如果相同的key出現了,那麼這個key的分類對應

          的值就加了兩次1 變爲2. 那麼最後我們就可以統計出標籤出現頻率最高的一個做爲陌生

          inX數據點的分類,最爲準確了。

          '''

          classCount[voteIlabel] =classCount.get(voteIlabel,0)+1



          '''

          循環結束後classCount字典的元素結果爲

          classCount ={['A',1],['B',2]}

          '''

          '''

          classCount.iteritems()方法返回一個iterator對象

          key=operator.itemgetter(1)按着key進行排序,此時的key的值對應的是字典中

          value的值,即按每個字典元素value的值進行排序

          reverse=True 指的是反轉按着倒序排列。

          sortedClassCount= [('B',2),('A',1)]

          '''

          sortedClassCount =sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)

          #返回統計分類頻率最好的類別元素,作爲陌生數據分類的最終結果。

          return sortedClassCount[0][0]
  1. 測試:
    
    classify0([0,0], dataset,label,3);
    
    結果分類爲:B
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章