KNN算法--簡化入門總結

訓練集與測試集

在機器學習中,數據有兩個集合,一個叫做訓練集-train:用於訓練算法模型,即已經知道我們所要求的數值,用以生成合適的算法模型;另一個叫做測試集-test:用於測試這個生成的模型可靠性。

KNN算法簡介

kNN算法,K最近鄰(k-NearestNeighbor)分類算法:從訓練樣本集中選擇k個與測試樣本“距離”最近的樣本,這k個樣本中出現頻率最高的類別即作爲測試樣本的類別。

kNN算法是一種無監督,適用於手寫識別等內容,需要提前給出定義距離的算法

算法過程

  1. 定義K值,K值代表了k臨近算法的k大小;

K取值一版不大於20

  1. 得出待分點與已知類別樣本點中,距離最近的k個樣本;
  2. 統計k個樣本中,各類別數量,取出現最多的類別就是待分點的類別

優缺點

優點:簡單,易於實現,不需參數估計與事先的訓練
缺點:懶惰算法,內存佔用大,需本地運行耗時很長

編程步驟

  1. 將樣本圖片轉化爲一個向量。例:圖片像素點爲32X32的數組,轉化爲1X1024的數組(即特徵向量)
  2. 如果訓練樣本中有10X10個圖,則可以合併成100X1024的矩陣
  3. 如果測試樣本中有10X5個圖,我們要讓程序自動判斷出每個圖片表示的數字。 測試圖片-----轉化爲1X1024的向量,計算其與訓練樣本中各圖的距離,對距離排序,選出最小的前K個,這K個都來自於訓練集,是已知其代表的數字的,所以被測試的圖代表數字最多的就是當前數

附代碼

第一步:轉化爲1*1024的特徵向量。程序中的filename是文件名,比如3_3.txt

<span style="font-family:SimSun;font-size:18px;">#樣本是32*32的二值圖片,將其處理成1*1024的特徵向量
def img2vector(filename):
    returnVect = 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</span>

第二步、第三步:將訓練集圖片合併成100*1024的大矩陣,同時逐一對測試集中的樣本分類

<span style="font-family:SimSun;font-size:18px;">def handwritingClassTest():
    #加載訓練集到大矩陣trainingMat
    hwLabels = []
    trainingFileList = listdir('trainingDigits')           #os模塊中的listdir('str')可以讀取目錄str下的所有文件名,返回一個字符串列表
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]                  #訓練樣本的命名格式:1_120.txt
        fileStr = fileNameStr.split('.')[0]                #string.split('str')以字符str爲分隔符切片,返回list,這裏去list[0],得到類似1_120這樣的
        classNumStr = int(fileStr.split('_')[0])           #以_切片,得到1,即類別
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
        
    #逐一讀取測試圖片,同時將其分類   
    testFileList = listdir('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 = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr)
        if (classifierResult != classNumStr): errorCount += 1.0
    print "\nthe total number of errors is: %d" % errorCount
    print "\nthe total error rate is: %f" % (errorCount/float(mTest))</span>

這裏面的函數classify()爲分類主體函數,計算歐式距離,並最終返回測試圖片類別:

<span style="font-family:SimSun;font-size:18px;">#分類主體程序,計算歐式距離,選擇距離最小的k個,返回k箇中出現頻率最高的類別
#inX是所要測試的向量
#dataSet是訓練樣本集,一行對應一個樣本。dataSet對應的標籤向量爲labels
#k是所選的最近鄰數目
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]                       #shape[0]得出dataSet的行數,即樣本個數
    diffMat = tile(inX, (dataSetSize,1)) - dataSet       #tile(A,(m,n))將數組A作爲元素構造m行n列的數組
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)                  #array.sum(axis=1)按行累加,axis=0爲按列累加
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()             #array.argsort(),得到每個元素的排序序號
    classCount={}                                        #sortedDistIndicies[0]表示排序後排在第一個的那個數在原來數組中的下標
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #get(key,x)從字典中獲取key對應的value,沒有key的話返回0
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) #sorted()函數,按照第二個元素即value的次序逆向(reverse=True)排序
    return sortedClassCount[0][0]</span>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章