機器學習(七):k鄰近算法初級淺析案例

注:基於現有小案例攥寫

K 近鄰算法採用測量不同特徵值之間的距離方法進行分類:

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

缺點:計算複雜度高、空間複雜度高。

K 近鄰算法適用數據範圍爲:數值型和標稱型

標稱型:標稱型目標變量的結果只在有限目標集中取值,如真與假

數值型:數值型目標變量則可以從無限的數值集合中取值,如0.100,42.001等 

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

k鄰近算法的一般流程:

  1. 收集數據:可以使用任何方法。
  2. 準備數據:距離計算所需要的數值,最好是結構化的數據格式。
  3. 分析數據:可以使用任何方法。
  4. 訓練算法:此步驟不適用於 K 近鄰算法。
  5. 測試算法:計算錯誤率。
  6. 使用算法:首先需要輸入樣本數據和結構化的輸出結果,然後運行K 近鄰算法判定輸入數據分別屬於哪個分類,最後應用對計算出的分類執行後續的處理。

準備數據集:

http://labfile.oss.aliyuncs.com/courses/777/digits.zip

trainingDigits:訓練數據,1934 個文件,每個數字大約 200 個文件。

testDigits:測試數據,946 個文件,每個數字大約 100 個文件。

全部代碼如下:

import numpy as np
import operator
from os import listdir
def  handwritingclassTest():
    hwLabels =[]
    trainingFileList = listdir('digits/trainingDigits')
    m = len(trainingFileList)
    trainingMat = np.zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:]=im2vector('digits/trainingDigits/%s' % fileNameStr)
    testFileList = listdir('digits/testDigits')
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = im2vector('digits/testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)
        print("測試樣本 %d,分類器預測: %d,真實類別:%d" % (i+1,classifierResult,classNumStr))
        if(classifierResult != classNumStr):
            errorCount += 1.0
    print("\n錯誤分類計數:%d" % errorCount)
    print("\n錯誤分類 比例:%f" % (errorCount/float(mTest)))


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

def im2vector(filename):
    #創建向量
    returnVect = np.zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j]=int(lineStr[j])
    return returnVect
#im2vector('digits/testDigits/0_1.txt')
def classify0(inX,dataSet,labels,k):
    #獲取dataSet維度值
    dataSetSize = dataSet.shape[0]
    #矩陣運算,計算測試數據與每個 樣本數據對應數據項的差值
    diffMat = np.tile(inX,(dataSetSize,1)) - dataSet
    #進行平方運算
    sqDiffMat = diffMat**2
    #平方運算後以行 求和
    sqDistances = sqDiffMat.sum(axis=1)
    #取平方根,得到距離向量
    distances = sqDistances**0.5
    #按照距離進行排序,取出索引值
    sortedDistIndicies = distances.argsort()
    print(sortedDistIndicies)
    classCount={}
    #依次取出最近的樣本數據
    for i in range(k):
        #記錄改樣本所屬的類別
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    #對類別出現的頻次進行排序,從高到低,確定前 k 個點所在類別的出現頻率
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回前 k 個點出現頻率最高的類別作爲當前點的預測分類。
    return sortedClassCount[0][0]
#group,labels = createDataSet()
#print(classify0([0,0],group,labels,3))
handwritingclassTest()

最後運行情況:

解釋:

函數 img2vector,將圖像轉換爲向量:該函數創建 1x1024 的 NumPy 數組,然後打開給定的文件,循環讀出文件的前 32行,並將每行的頭 32 個字符值存儲在 NumPy 數組中,把一個 32x32 的二進制圖像矩陣轉換爲 1x1024 的向量,最後返回數組。

函數classify0,通過歐式距離公式,計算臨近點,選取與當前點距離最小的 k 個點,確定前 k 個點所在類別的出現頻率,返回前 k 個點出現頻率最高的類別作爲當前點的預測分類。

函數handwritingClassTest(),打開 兩個數據集,帶入上面兩個函數進行計算,進行分類,並與真實分類結果進行對比,得到最後 的錯誤分類比例。

上面的代碼中的錯誤分類比例是0.0105,可以通過修改k值,改變訓練樣本進行測試,進一步調進錯誤分類 比例。

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