【機器學習實戰】KNN近鄰算法

K-近鄰算法概述

採用不同特徵值之間的距離方法進行分類

優點:精度高、對異常值不敏感、無數據輸入假定

缺點:計算複雜度高,空間複雜度高

適用範圍:數值類型和標稱型

 

有一個訓練樣本集,每個樣本都有標籤,輸入新數據,將新數據和舊的進行比較,然後提取最相似數據的標籤。一般是選擇K個,不大於20,最後選擇k個最相似數據中出現次數最多的分類,作爲新數據的分類。

電影:親吻次數、打鬥次數來分類愛情片還是動作片

數據如下:

電影名稱

打鬥鏡頭

親吻鏡頭

電影類型

California Man

3

104

愛情片

He's Not Really into Dues

2

100

愛情片

Robo Salyer 3000

99

5

動作片

計算出新電影與舊電影的距離,按照距離遞增排序,找到k個距離最近的電影,它們的類型來決定未知電影的類型

2.1.1 準備:適用Python導入數據

代碼:kNN.py

from numpy import *
import operator

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

 

2.1.2 從文本文件中解析數據

僞代碼

對未知類別屬性的數據集中的每個點依次執行以下操作:

  1. 計算已知類別數據集中點與當前點之間的距離
  2. 按照距離遞增排序
  3. 選取與當前點距離最小的k個點
  4. 確定前k個點所在類別的出現頻率
  5. 返回前K個點出現頻率最高的類別作爲當前點的預測分類
def classifyKNN(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
    # 距離計算
    diffMat = tile(inx,(dataSetSize,1)) - dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()
    classCount = {}
    # 選擇k個點
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel ] = classCount.get(voteIlabel ,0) + 1
   # 排序
   sortedClassCount = sorted(classCount.iteritems(),key=operator.itegetter(1),reverse=True)     
   return sortedClassCount[0][0]
kNN.classifyKNN([0,0],group,labels,3)  

使用的是歐式距離

d= sqrt( (xA0-xB0)^2 + (xA1-xB1)^2)

點(0,0)與(1,2)的距離是:sqrt(5)

np.tile(testData, (rowSize, 1)) 是將 testData 這個數據擴展爲 rowSize 列,這樣能避免運算錯誤;

sorted(count.items(), key=operator.itemgetter(1), reverse=True) 排序函數,裏面的參數 key=operator.itemgetter(1), reverse=True 表示按照 count 這個字典的值(value)從高到低排序,如果把 1 換成 0,則是按字典的鍵(key)從高到低排序。把 True 換成 False 則是從低到高排序。

 

完整的的代碼

#!/user/bin/env python
#-*- coding:utf-8 -*-
import numpy as np
import operator as opt

# 標準化數據
def normData(dataSet):
    maxVals = dataSet.max(axis=0)#按列獲取最大值,並返回數組
    minVals = dataSet.min(axis=0)
    ranges = maxVals - minVals
    retData = (dataSet - minVals) / ranges
    return retData, ranges, minVals
    
def kNN(dataSet, labels, testData, k):
    distSquareMat = (dataSet - testData) ** 2 # 計算差值的平方
    distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和,axis=0則按列計算
    distances = distSquareSums ** 0.5 # 開根號,得出每個樣本到測試點的距離
    sortedIndices = distances.argsort() # 排序,得到排序後的下標
    indices = sortedIndices[:k] # 取最小的k個
    labelCount = {} # 存儲每個label的出現次數,出現次數最多的就是我們要選擇的類別
    for i in indices:
        label = labels[i]
        labelCount[label] = labelCount.get(label, 0) + 1 # 次數加一,使用字典的get方法,第一次出現時默認值是0
    sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) # 對label出現的次數從大到小進行排序
 return sortedCount[0][0] # 返回出現次數最大的label
 
if __name__ == "__main__":
 dataSet = np.array([[2, 3], [6, 8]])#訓練集
 normDataSet, ranges, minVals = normData(dataSet)
 labels = ['a', 'b']#訓練集分別爲a和b類
 testData = np.array([3.9, 5.5])#測試數據
 normTestData = (testData - minVals) / ranges#同樣需要將測試數據標準化
 result = kNN(normDataSet, labels, normTestData, 1)#k=1
 print(result)  


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