機(jī)器學(xué)習(xí)實戰(zhàn)之python實現(xiàn)kNN算法

參考書籍《機(jī)器學(xué)習(xí)實戰(zhàn)》

圖片.png

舉例說明:

以二維數(shù)據(jù)簡單舉例:
已知數(shù)據(jù)集中含有 x1(1,1) x2(0,1)為A類,x3(1,0),x4(10,10) 為B類
判斷x5(2,2) 為哪一類。
方法:定k等于3,
分別計算x5與x1、x2、x3、x4的距離,可得出前k個離x5最近的點(diǎn)是x1,x2,x3。其中A類的有兩個,B類的有一個,因此判斷x5屬于A類

python中代碼實現(xiàn)

def classify0(x,dataSet,labels,k):#定義kNN算法
    dataSetSize = dataSet.shape[0] #獲取數(shù)據(jù)集的行數(shù),即有多少個數(shù)
    diffMat = np.tile(x,(dataSetSize,1))-dataSet #將要判斷類型的數(shù)據(jù)x,轉(zhuǎn)化成和數(shù)據(jù)集
    #同樣結(jié)構(gòu),并求出和數(shù)據(jù)集的差(想像坐標(biāo)系中兩個二維點(diǎn)的x、y之差)
    sqDiffMat = diffMat ** 2 #求x與數(shù)據(jù)集每個點(diǎn)差的平方(x差和y差的平方)
    sqDistances = sqDiffMat.sum(axis=1) #求出x與數(shù)據(jù)集每個點(diǎn)的差方和(x差的平方+y差的平方)
    distances = sqDistances ** 0.5 #求平方根(勾股定理),即為兩點(diǎn)之間的距離
    sorteDistIndicies = distances.argsort() #返回distances中數(shù)值從小到大對應(yīng)的索引值
    
    classCount = {} #統(tǒng)計類型,關(guān)鍵字為類型,值為類型的數(shù)量
    for i in range(k): #從前k個最相近的判斷類型
        voteIlabel = labels[sorteDistIndicies[i]] #取出類型
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),
                               reverse=True)
    #classCount.items()將字典轉(zhuǎn)為元組,并按照key指定的方式進(jìn)行排序,reverse為True,則為
    #倒序,operator.itemgetter(1)是指按照元組索引為1的值進(jìn)行排序
    return sortedClassCount[0][0] #取出排序后第一個元素的類型

以上即為kNN算法的python偽代碼

利用以上算法,完成書中的示例:

示例一:約會類型預(yù)測

首先來測試下錯誤率

file = 'datingTestSet2.txt'
def file2matrix(filename):#定義讀取文件函數(shù)
    f = open(filename) 
    filelist = []
    for i in f.readlines():
        a,b,c,d = i.strip().split('\t')
        filelist.append([a]+[b]+[c]+[d]) #將讀取到的信息以列表的形式存入列表
    f.close()
    filearray = np.array(filelist) #轉(zhuǎn)化為np.ndarry格式(向量格式)
    returnMat = filearray[:,:-1] #構(gòu)建出數(shù)據(jù)集
    classLabelVector = filearray[:,-1] #數(shù)據(jù)集對應(yīng)的類型
    return returnMat,classLabelVector

def autoNorm(dataSet):#定義歸一化函數(shù)
    ranges = dataSet.astype(float).max(axis=0)-dataSet.astype(float).min(axis=0)
    #這里需要留意,數(shù)據(jù)的類型必須是數(shù)值型的才能參與計算
    minVals = dataSet.astype(float).min(axis=0)
    normDataSet = (dataSet.astype(float)-minVals)/ranges
    return normDataSet,ranges,minVals

def datingClassTest(file): #定義檢驗函數(shù)
    p = 0.1
    datingDataMat,datingLabels = file2matrix(file)#讀取數(shù)據(jù)集
    norMat,ranges,minVals = autoNorm(datingDataMat)#對數(shù)據(jù)集進(jìn)行歸一化
    numTestVecs = int(len(norMat)*p) #取10%的作為測試集
    errorCount = 0
    for i in range(numTestVecs):
        result = classify0(norMat[i,:],norMat[numTestVecs:,:],
                           datingLabels[numTestVecs:],3) #norMat從0到numTestVecs
        #的為測試數(shù)據(jù),后面的為樣本集
        print('the result is {},real answer is :{}'.format(result,datingLabels[i]))#輸出判斷過程
        if result != datingLabels[i]:
            errorCount += 1
    print('the total error tate is {}'.format(errorCount/numTestVecs))#輸出最終錯誤率
print(datingClassTest(file))

錯誤率很低,可以用來進(jìn)行預(yù)判

def classifyPerson(file):#定義用戶使用函數(shù)
    resultList = ['not at all','in small doses','in large doses'] #類型列表
    ffMiles = float(input('輸入每年獲取的飛行??屠锍虜?shù):'))
    percentTats = float(input('輸入玩視頻游戲所耗時間百分比:'))
    iceCream = float(input('輸入每周消費(fèi)的冰淇淋公升數(shù):'))
    inArr = np.array([ffMiles,percentTats,iceCream]) #將輸入的新數(shù)據(jù)轉(zhuǎn)化為向量格式
    #注意順序要和數(shù)據(jù)集中的順序一致,即特征要對應(yīng)上
    datingDataMat,datingLabels = file2matrix(file)
    norMat,ranges,minVals = autoNorm(datingDataMat)
    norinArr = (inArr-minVals)/ranges #將新數(shù)據(jù)進(jìn)行歸一化
    result = classify0(norinArr,norMat,datingLabels,3)
    print('該對象的類別是:{}'.format(resultList[result-1]))#-1是因為這里使用索引匹配

classifyPerson(file)

示例二:手寫識別系統(tǒng)

filepath1 = 'digits/trainingDigits/' #這個為數(shù)據(jù)集目錄
filepath2 = '/digits/testDigits/' #這個為測試數(shù)據(jù)目錄

def img2vector(file): #讀取文檔,并轉(zhuǎn)化為向量
    returnVect = np.zeros((1,1024))#確保每一行是一個完整的數(shù)據(jù),因此將原維度32*32的數(shù)據(jù)改為維度是1*1024
    num = 0
    f = open(file)
    for i in f.readlines():
        ilen = int(len(i.strip()))
        returnVect[:,num:num+ilen] = list(i.strip())#以切片方式寫入數(shù)據(jù)
        num += ilen
    f.close()
    return returnVect

def readfile(path):#創(chuàng)建數(shù)據(jù)集及類別
    filelist = os.listdir(path)
    trainingMat = np.zeros((len(filelist),1024))#創(chuàng)建數(shù)據(jù)集的維度
    hwLabels = []
    num = 0
    for i in filelist:
        Vect = img2vector(path+i)
        classNumstr = int(i.strip().split('_')[0])
        trainingMat[num,:] = Vect #按行循環(huán)寫入數(shù)據(jù)
        hwLabels.append(classNumstr)#將類別添加進(jìn)列表
        num += 1
    return trainingMat,hwLabels
        
def handwritingClassTest(file1,file2):
    trainingMat,hwLabels = readfile(filepath1)#創(chuàng)建數(shù)據(jù)集
    errorCount = 0
    for i in os.listdir(filepath2):
        vectorTest = img2vector(filepath2+i)#讀取測試數(shù)據(jù)
        classNumstr = int(i.strip().split('_')[0])
        result = classify0(vectorTest,trainingMat,hwLabels,3)
        print('the result is {},real answer is :{}'.format(result,classNumstr))
        if int(result) != classNumstr:
            errorCount += 1
    print('the total error tate is {}'.format(errorCount/len(os.listdir(filepath2))))      
 
handwritingClassTest(filepath1,filepath2)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容