K--近鄰算法解析

代碼測試環境:Python,需要安裝Numpy庫

首先講解關於K--近鄰算法的工作原理:

       K--近鄰算法的工作原理是根據所給已知標籤的數據集計算出與未知標籤數據的最近的K個數據,這K個數據的標籤中所佔比重最大的那個數據的標籤即爲所要預測數據的標籤。下面進行詳細解釋一下:假設現在有一個已知標籤數據的樣本,它包含5個屬性值,則這個樣本被稱作訓練樣本集。當輸入一個沒有標籤的數據樣本時。訓練樣本中的所有數據就會計算與這個沒有標籤的數據樣本之間的距離(具體的計算公式稍後會詳細講解),最後得出與這個測試樣本之間最近的K個訓練樣本數據。K一般不超過20.最後選擇出這K個相似數據中出現最多的分類作爲預測數據的分類。

詳細講解K--近鄰算法的實現過程:

       首先創建一個名爲KNN.py的文件在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

    在上面的代碼中首先導入了一個計算包NumPy,還有一個運算符模塊operator。接下來createDataSet()函數用於創建一個數據集和標籤,首先是一個二維數組接下來是其對應的標籤。從文件中輸入的數據格式也像上面一樣,這裏爲了講解自己創造的數據集。接下來開始真正的實施KNN算法,在KNN.py文件中加入如下代碼:

def classify0(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={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]
  這個函數有四個輸入參數,inX爲測試數據集,dataSet是去除標籤的訓練數據集,labels是標籤列表,k是要預測的最相似數據集的個數。

  首先計算出訓練數據集中所包含數據的條數。接下來的第3~~6行是進行距離的計算。這裏用到的距離計算公式是歐氏距離計算公式,也就是我們從初中就用到的兩點之間的距離計算公式。對!沒錯!這裏不再具體解釋。計算出所有訓練數據到預測點的距離之後就要對其進行排序,然後取出距離測試點最近的K個點。最後根據最近的點的出現次數進行排序,這裏按照從大到小的順序進行排序,所以第一個就是我們想要的最佳答案。


接下來我們根據具體的數據進行算法的實現,我們所使用的數據格式如下所示:datingTestSet.txt下載 (提取碼:6fa1)

40920	8.326976	0.953952	largeDoses
14488	7.153469	1.673904	smallDoses
26052	1.441871	0.805124	didntLike
75136	13.147394	0.428964	didntLike
38344	1.669788	0.134296	didntLike
72993	10.141740	1.032955	didntLike
35948	6.830792	1.213192	largeDoses
42666	13.276369	0.543880	largeDoses
67497	8.631577	0.749278	didntLike
35483	12.273169	1.508053	largeDoses
50242	3.723498	0.831917	didntLike
63275	8.385879	1.669485	didntLike
5569	4.875435	0.728658	smallDoses
51052	4.680098	0.625224	didntLike
77372	15.299570	0.331351	didntLike
43673	1.889461	0.191283	didntLike
61364	7.516754	1.269164	didntLike
69673	14.239195	0.261333	didntLike
15669	0.000000	1.250185	smallDoses
28488	10.528555	1.304844	largeDoses
6487	3.540265	0.822483	smallDoses
37708	2.991551	0.833920	didntLike

這裏的前三列是屬性列,最後一列是標籤列。這裏我們首先將文本解析爲算法能夠讀取的格式。在KNN.py文件中添加下面這個函數:

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         
    returnMat = zeros((numberOfLines,3))       
    classLabelVector = []                      
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

這個函數比較簡單這裏不再詳細介紹,就是將數據解析爲屬性矩陣和標籤列表,和上面的數據格式一樣。接下來我們需要對數據進行準備工作:

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))   
    return normDataSet, ranges, minVals
這個函數的主要功能是對數據進行歸一化。這裏進行歸一化的原因是避免在計算兩點之間的距離是由於其中一個屬性之間相差較大影響其他屬性在計算中發揮的作用。這裏的歸一化就是使其所有屬性值都處於0到1之間,具體的做法就是找到每個屬性中的最小值和最大值,然後用現有屬性之減去最小值除以最大值和最小值的差。這就是上面的代碼完成的工作。好了!到這裏大部分工作基本已經完成,最後要做的就是進行測試:

def datingClassTest():
    hoRatio = 0.10
    datingDataMat,datingLabels = file2matrix('datingTestSet.txt')
    normMat,ranges,minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classifyO(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print "the classifier came back with : %d ,the real answer is ; %d " % (classifierResult , datingLabels[i])
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    print "the total error rate is : %f the error number is %d" % (errorCount /float(numTestVecs),errorCount)
這個函數是對上面的代碼進行測試,我們注意到裏邊有一個變量hoRatio這個變量決定有多少數據是訓練數據,多少數據是測試數據。所以我們可以改變它的值來觀察預測結果的變化。同時我們也可以改變K的之來進行結果的觀察。我們可以在IDLE終端輸入KNN.datingClassTest()觀察輸出結果。到這裏我們已經完成算法的所有代碼的實現。KNN算法總體來說並不難,很容易理解。下一節我將爲大家展示一個實例的應用。


   小弟在這獻醜了,希望能給大家一點幫助,歡迎大家前來圍觀更歡迎大家七嘴八舌!罵人


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