1. 程式人生 > >K-近鄰演算法---分類

K-近鄰演算法---分類

使用 k 近鄰演算法改進網站的配對效果

# 匯入程式所需要的模組
import numpy as np
import operator

定義資料集匯入函式

file2matrix函式實現的功能是讀取檔案資料,函式返回的returnMat和classLabelVector分別是資料集的特徵矩陣和輸出標籤向量。

def file2matrix(filename):
    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}    # 三個類別
    fr = open(filename)    # 開啟檔案
    arrayOLines = fr.readlines()    # 逐行開啟
    numberOfLines = len(arrayOLines)            #得到檔案的行數
    returnMat = np.zeros((numberOfLines, 3))        #初始化特徵矩陣
    classLabelVector = []                       #初始化輸出標籤向量
    index = 0
    for line in arrayOLines:
        line = line.strip()    # 刪去字串首部尾部空字元
        listFromLine = line.split('\t')    # 按'\t'對字串進行分割,listFromLine 是列表
        returnMat[index, :] = listFromLine[0:3]    # listFromLine的0,1,2元素是特徵,賦值給returnMat的當前行
        if(listFromLine[-1].isdigit()):    # 如果listFromLine最後一個元素是數字
            classLabelVector.append(int(listFromLine[-1]))    # 直接賦值給classLabelVector
        else:    # 如果listFromLine最後一個元素不是數字,而是字串
            classLabelVector.append(love_dictionary.get(listFromLine[-1]))    # 根據字典love_dictionary轉化為數字
        index += 1
    return returnMat, classLabelVector    # 返回的類別標籤classLabelVector是1,2,3

定義特徵歸一化函式

這裡為什麼要對特徵進行歸一化?
因為在處理這種不同取值範圍的特徵值時,數值歸一化能夠將不同特徵的取值範圍限定在同一區間例如[0,1]之間,讓不同特徵對距離的計算影響相同。具體可看《機器學習實戰》第2.2.3節內容。

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    normDataSet = normDataSet/np.tile(ranges, (m, 1))   # normDataSet值被限定在[0,1]之間
    return normDataSet, ranges, minVals

定義 k 近鄰演算法

def classify0(inX, dataSet, labels, k):    # inX是測試集,dataSet是訓練集,lebels是訓練樣本標籤,k是取的最近鄰個數
    dataSetSize = dataSet.shape[0]    # 訓練樣本個數
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet    # np.tile: 重複n次
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5    # distance是inX與dataSet的歐氏距離
    sortedDistIndicies = distances.argsort()    # 返回排序從小到達的索引位置
    classCount = {}   # 字典儲存k近鄰不同label出現的次數
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1    # 對應label加1,classCount中若無此key,則預設為0
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)    # operator.itemgetter 獲取物件的哪個維度的資料
    return sortedClassCount[0][0]    # 返回k近鄰中所屬類別最多的哪一類

測試演算法:作為完整程式驗證分類器

def datingClassTest():
    hoRatio = 0.10      #整個資料集的10%用來測試
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')       #匯入資料集
    normMat, ranges, minVals = autoNorm(datingDataMat)    # 所有特徵歸一化
    m = normMat.shape[0]    # 樣本個數
    numTestVecs = int(m*hoRatio)    # 測試樣本個數
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(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" % (errorCount / float(numTestVecs)))    # 列印錯誤率
    print(errorCount)    # 列印錯誤個數
datingClassTest()

執行結果;
在這裡插入圖片描述

使用演算法:構建完整可用系統

根據使用者輸入,線上判斷類別。

def classifyPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    percentTats = float(input(\
                                  "percentage of time spent playing video games?"))
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = np.array([ffMiles, percentTats, iceCream, ])
    classifierResult = classify0((inArr - \
                                  minVals)/ranges, normMat, datingLabels, 3)
    print("You will probably like this person: %s" % resultList[classifierResult - 1])
classifyPerson()

執行結果:
在這裡插入圖片描述