機器學習之K近鄰算法(KNN算法)

KNN算法可以說是機器學習分類中最簡單的一種算法了,KNN算法的工作原理是:存在一個樣本數據集,也稱訓練樣本集,在這個樣本集中每個數據都存在其對應的標籤,即我們知道樣本集中每一數據與所屬分類的對應關係。當我們輸入需要預測的數據時,我們將預測數據的每個特徵與樣本集中對應的特徵進行比較,然後提取樣本集中特徵最相似數據(最近鄰)的分類標籤。一般來說,我們只選擇樣本數據集中前K個最相似的數據,這就是KNN算法。通常來說我們的K都是不大於20的整數。最後我們選擇K個最相似數據中出現次數最多的分類,作爲預測數據的分類。

下面我們用python來實現KNN算法

'''
    KNN算法(k-近鄰算法)實習步驟(僞代碼)如下:
        對未知類別屬性的數據集中的點與當前點之間的距離執行以下操作:
        1.計算已知類別數據集中的點與當前點之間的距離
        2.按照距離遞增次序排序
        3.選取與當前點距離最小的k個點
        4.確定前k個點所在類別的出現頻率
        5.返回前k個點出現頻率最高的類別作爲當前點的預測分類
        
    計算距離時我們使用歐式距離公式
'''

# inX:用於分類的向量X(即需要預測數據), dataSet:輸入的訓練樣本集, labels:標籤向量, k:用於選擇最近鄰居的數目
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet   # tile()方法用於將輸入的預測數據擴展至於訓練樣本集同樣大小
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)  # axis=1 表示按列相加 即每行的所有列加一起求和
    distance = sqDistances**0.5
    # 按照升序進行快速排序,返回的是原數組的下標。
    # 比如,x = [30, 10, 20, 40]
    # 升序排序後應該是[10,20,30,40],他們的原下標是[1,2,0,3]
    # 那麼,numpy.argsort(x) = [1, 2, 0, 3]
    sortedDistIndicies = distance.argsort()  # 在這裏就相當於告訴了每行數據(即每個數據點)離預測數據點是第幾近
    classCount={}
    # 上面是距離的計算,,下面是選擇距離最小的k個點
    # 投票過程,就是統計前k個最近的樣本所屬類別包含的樣本個數
    for i in range(k):
        # index = sortedDistIndicies[i]是第i個最相近的樣本下標
        # voteIlabel = labels[index]是樣本index對應的分類結果('A' or 'B')
        voteIlabel = labels[sortedDistIndicies[i]]
        # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,則返回0
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)   # 排序
    return sortedClassCount[0][0]   # 返回第一近的數據點類別

下面我們使用KNN算法來進行手寫數字的識別,當然我們對於數據進行了預處理。手寫數字集來自www.manning.com/MachineLearninginAction中的CH02文件夾下的digits,zip

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


# 手寫數字識別系統的測試代碼
def handwritingClassTest():
    hwLabels = []
    trainingFileList = os.listdir('trainingDigits')  # 獲取目錄內容
    m = len(trainingFileList)
    # print(m)
    trainingMat = zeros((m, 1024))
    # 從文件名解析分類數字
    for i in range(m):
        fileNameStr = trainingFileList[i]
        # print(fileNameStr)
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = os.listdir("testDigits")
    errcount = 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):
            errcount += 1
    print("\nthe total number of erros is :%d" % errcount)
    print("\nthe total error rate is : %f" % (errcount/float(mTest)))

總結

  KNN算法是分類數據最簡單最有效的算法,KNN算法是基於實例的學習方法,使用算法時我們必須有接近實際數據的訓練樣本數據。KNN算法必須保存全部數據集,如果訓練數據集很大,必須使用大量的儲存空間。此外,由於必須對數據集中的每個數據計算距離值,所以實際用時會非常耗時。

  KNN算法的另一個缺陷是它無法給出任何數據的基礎結構信息,因此我們無法知曉平均實例樣本和典型實例樣本具有什麼特徵

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