午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

刻意練習(xí):機(jī)器學(xué)習(xí)實(shí)戰(zhàn) -- Task01. K鄰近算法

 老馬的程序人生 2020-08-17

背景

這是我們?yōu)閾碛?Python 基礎(chǔ)的同學(xué)推出的精進(jìn)技能的“機(jī)器學(xué)習(xí)實(shí)戰(zhàn)” 刻意練習(xí)活動(dòng),這也是我們本學(xué)期推出的第三次活動(dòng)了。

我們準(zhǔn)備利用8周時(shí)間,夯實(shí)機(jī)器學(xué)習(xí)常用算法,完成以下任務(wù):

  • 分類問題:K鄰近算法

  • 分類問題:決策樹

  • 分類問題:樸素貝葉斯

  • 分類問題:邏輯回歸

  • 分類問題:支持向量機(jī)

  • 分類問題:AdaBoost

  • 回歸問題:線性回歸、嶺回歸、套索方法、逐步回歸等

  • 回歸問題:樹回歸

  • 聚類問題:K均值聚類

  • 相關(guān)問題:Apriori

  • 相關(guān)問題:FP-Growth

  • 簡化數(shù)據(jù):PCA主成分分析

  • 簡化數(shù)據(jù):SVD奇異值分解

本次任務(wù)的核心是熟悉K鄰近算法的原理,并實(shí)現(xiàn)《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》這本書給出的兩個(gè)案例。


算法原理

KNN 算法采用測量不同特征之間的距離方法進(jìn)行分類,通俗的講就是:給定一個(gè)樣本數(shù)據(jù)集,并且樣本集中每個(gè)數(shù)據(jù)都存在標(biāo)簽,即我們知道樣本集中每個(gè)數(shù)據(jù)與所屬分類的對(duì)應(yīng)關(guān)系。對(duì)新輸入沒有標(biāo)簽的實(shí)例,在訓(xùn)練數(shù)據(jù)集中找到與該實(shí)例最鄰近的 k 個(gè)實(shí)例,這 k 個(gè)實(shí)例的多數(shù)屬于某個(gè)類,就把該輸入實(shí)例分為這個(gè)類。

對(duì)于每一個(gè)在數(shù)據(jù)集中的數(shù)據(jù)點(diǎn):
    計(jì)算目標(biāo)的數(shù)據(jù)點(diǎn)(需要分類的數(shù)據(jù)點(diǎn))與該數(shù)據(jù)點(diǎn)的距離
    將距離排序:從小到大
    選取前 K 個(gè)最短距離
    選取這 K 個(gè)中最多的分類類別
    返回該類別來作為目標(biāo)數(shù)據(jù)點(diǎn)的預(yù)測值

項(xiàng)目案例1:優(yōu)化約會(huì)網(wǎng)站的配對(duì)效果

項(xiàng)目概述

海倫使用約會(huì)網(wǎng)站尋找約會(huì)對(duì)象。經(jīng)過一段時(shí)間之后,她發(fā)現(xiàn)曾交往過三種類型的人:

  • 1:不喜歡的人

  • 2:魅力一般的人

  • 3:極具魅力的人

她希望:

  • 不喜歡的人則直接排除掉

  • 工作日與魅力一般的人約會(huì)

  • 周末與極具魅力的人約會(huì)

現(xiàn)在她收集到了一些約會(huì)網(wǎng)站未曾記錄的數(shù)據(jù)信息,這更有助于匹配對(duì)象的歸類。

開發(fā)流程

Step1:收集數(shù)據(jù)

此案例書中提供了文本文件。

海倫把這些約會(huì)對(duì)象的數(shù)據(jù)存放在文本文件 datingTestSet2.txt 中,總共有 1000 行。海倫約會(huì)的對(duì)象主要包含以下 3 種特征:

  • Col1:每年獲得的飛行??屠锍虜?shù)

  • Col2:玩視頻游戲所耗時(shí)間百分比

  • Col3:每周消費(fèi)的冰淇淋公升數(shù)

文本文件數(shù)據(jù)格式如下:

40920    8.326976    0.953952    3
14488    7.153469    1.673904    2
26052    1.441871    0.805124    1
75136    13.147394   0.428964    1
38344    1.669788    0.134296    1

Step2:準(zhǔn)備數(shù)據(jù)

使用 Python 解析文本文件。將文本記錄轉(zhuǎn)換為 NumPy 的解析程序如下所示:

import numpy as np

def file2matrix(filename):
    """
    Desc:
        導(dǎo)入訓(xùn)練數(shù)據(jù)
    parameters:
        filename: 數(shù)據(jù)文件路徑
    return:
        數(shù)據(jù)矩陣 returnMat 和對(duì)應(yīng)的類別 classLabelVector
    """

    fr = open(filename)
    # 獲得文件中的數(shù)據(jù)行的行數(shù)
    lines = fr.readlines()
    numberOfLines = len(lines)  # type: int
    # 生成對(duì)應(yīng)的空矩陣
    # 例如:zeros(2,3)就是生成一個(gè) 2*3的矩陣,各個(gè)位置上全是 0
    returnMat = np.zeros((numberOfLines, 3))  # prepare matrix to return
    classLabelVector = []  # prepare labels return
    index = 0
    for line in lines:
        # str.strip([chars]) --返回已移除字符串頭尾指定字符所生成的新字符串
        line = line.strip()
        # 以 '\t' 切割字符串
        listFromLine = line.split('\t')
        # 每列的屬性數(shù)據(jù)
        returnMat[index, :] = listFromLine[0:3]
        # 每列的類別數(shù)據(jù),就是 label 標(biāo)簽數(shù)據(jù)
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    # 返回?cái)?shù)據(jù)矩陣returnMat和對(duì)應(yīng)的類別classLabelVector
    return returnMat, classLabelVector

Step3:分析數(shù)據(jù)

使用 Matplotlib 畫二維散點(diǎn)圖。

import matplotlib.pyplot as plt

if __name__ == '__main__':
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    color = ['r''g''b']
    fig = plt.figure()
    ax = fig.add_subplot(311)
    for i in range(14):
        index = np.where(np.array(datingLabels) == i)
        ax.scatter(datingDataMat[index, 0], datingDataMat[index, 1], c=color[i - 1], label=i)
    plt.xlabel('Col.0')
    plt.ylabel('Col.1')
    plt.legend()
    bx = fig.add_subplot(312)
    for i in range(14):
        index = np.where(np.array(datingLabels) == i)
        bx.scatter(datingDataMat[index, 0], datingDataMat[index, 2], c=color[i - 1], label=i)
    plt.xlabel('Col.0')
    plt.ylabel('Col.2')
    plt.legend()
    cx = fig.add_subplot(313)
    for i in range(14):
        index = np.where(np.array(datingLabels) == i)
        cx.scatter(datingDataMat[index, 1], datingDataMat[index, 2], c=color[i - 1], label=i)
    plt.xlabel('Col.1')
    plt.ylabel('Col.2')
    plt.legend()
    plt.show()

圖中清晰地標(biāo)識(shí)了三個(gè)不同的樣本分類區(qū)域,具有不同愛好的人其類別區(qū)域也不同。

歸一化特征值,消除特征之間量級(jí)不同導(dǎo)致的影響。

def autoNorm(dataSet):
    """
    Desc:
        歸一化特征值,消除特征之間量級(jí)不同導(dǎo)致的影響
    parameter:
        dataSet: 數(shù)據(jù)集
    return:
        歸一化后的數(shù)據(jù)集 normDataSet.ranges和minVals即最小值與范圍,并沒有用到

    歸一化公式:
        Y = (X-Xmin)/(Xmax-Xmin)
        其中的 min 和 max 分別是數(shù)據(jù)集中的最小特征值和最大特征值。該函數(shù)可以自動(dòng)將數(shù)字特征值轉(zhuǎn)化為0到1的區(qū)間。
    """

    # 計(jì)算每種屬性的最大值、最小值、范圍
    minVals = np.min(dataSet, axis=0)
    maxVals = np.max(dataSet, axis=0)
    # 極差
    ranges = maxVals - minVals
    m = dataSet.shape[0]
    # 生成與最小值之差組成的矩陣
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    # 將最小值之差除以范圍組成矩陣
    normDataSet = normDataSet / np.tile(ranges, (m, 1))  # element wise divide
    return normDataSet, ranges, minVals

Step4:訓(xùn)練算法

此步驟不適用于 k-近鄰算法。因?yàn)闇y試數(shù)據(jù)每一次都要與全部的訓(xùn)練數(shù)據(jù)進(jìn)行比較,所以這個(gè)過程是沒有必要的。

import operator

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    # 距離度量 度量公式為歐氏距離
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = np.sum(sqDiffMat, axis=1)
    distances = sqDistances ** 0.5
    # 將距離排序:從小到大
    sortedDistIndicies = distances.argsort()
    # 選取前K個(gè)最短距離, 選取這K個(gè)中最多的分類類別
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

Step5:測試算法

計(jì)算錯(cuò)誤率,使用海倫提供的部分?jǐn)?shù)據(jù)作為測試樣本。如果預(yù)測分類與實(shí)際類別不同,則標(biāo)記為一個(gè)錯(cuò)誤。

def datingClassTest():
    """
    Desc:
        對(duì)約會(huì)網(wǎng)站的測試方法
    parameters:
        none
    return:
        錯(cuò)誤數(shù)
    """

    # 設(shè)置測試數(shù)據(jù)的的一個(gè)比例
    hoRatio = 0.1  # 測試范圍,一部分測試一部分作為樣本
    # 從文件中加載數(shù)據(jù)
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')  # load data setfrom file
    # 歸一化數(shù)據(jù)
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # m 表示數(shù)據(jù)的行數(shù),即矩陣的第一維
    m = normMat.shape[0]
    # 設(shè)置測試的樣本數(shù)量, numTestVecs:m表示訓(xùn)練樣本的數(shù)量
    numTestVecs = int(m * hoRatio)
    print('numTestVecs=', numTestVecs)
    errorCount = 0.0
    for i in range(numTestVecs):
        # 對(duì)數(shù)據(jù)測試
        classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        print("分類器返回結(jié)果: %d, 實(shí)際結(jié)果: %d" % (classifierResult, datingLabels[i]))
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print("錯(cuò)誤率: %f" % (errorCount / float(numTestVecs)))
    print(errorCount)

Step6:使用算法

產(chǎn)生簡單的命令行程序,然后海倫可以輸入一些特征數(shù)據(jù)以判斷對(duì)方是否為自己喜歡的類型。

約會(huì)網(wǎng)站預(yù)測函數(shù)如下:

def classifyPerson():
    resultList = ['不喜歡的人''魅力一般的人''極具魅力的人']
    ffMiles = float(input("每年獲得的飛行常客里程數(shù)?"))
    percentTats = float(input("玩視頻游戲所耗時(shí)間百分比?"))
    iceCream = float(input("每周消費(fèi)的冰淇淋公升數(shù)?"))
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = np.array([ffMiles, percentTats, iceCream])
    intX = (inArr - minVals) / ranges
    classifierResult = classify0(intX, normMat, datingLabels, 3)
    print("這個(gè)人屬于: ", resultList[classifierResult - 1])

實(shí)際運(yùn)行效果如下:

if __name__ == '__main__':
    classifyPerson()

'''
每年獲得的飛行??屠锍虜?shù)? 10000
玩視頻游戲所耗時(shí)間百分比? 10
每周消費(fèi)的冰淇淋公升數(shù)? 0.5
這個(gè)人屬于:  魅力一般的人
'''

項(xiàng)目案例2:手寫識(shí)別系統(tǒng)

項(xiàng)目概述

構(gòu)造一個(gè)能識(shí)別數(shù)字 0 到 9 的基于 KNN 分類器的手寫數(shù)字識(shí)別系統(tǒng)。

需要識(shí)別的數(shù)字是存儲(chǔ)在文本文件中的具有相同的色彩和大?。簩捀呤?32 像素 * 32 像素的黑白圖像。

開發(fā)流程

Step1:收集數(shù)據(jù)

本案例書中提供了文本文件。

目錄 trainingDigits 中包含了大約 2000 個(gè)例子,每個(gè)例子內(nèi)容如下圖所示,每個(gè)數(shù)字大約有 200 個(gè)樣本;目錄 testDigits 中包含了大約 900 個(gè)測試數(shù)據(jù)。

Step2:準(zhǔn)備數(shù)據(jù)

編寫函數(shù) img2vector(), 將圖像文本數(shù)據(jù)轉(zhuǎn)換為分類器使用的向量。

def img2vector(filename):
    returnVect = np.zeros((11024))
    fr = open(filename)
    for i in range(32):  # 32行
        lineStr = fr.readline()
        for j in range(32):  # 32列
            returnVect[032 * i + j] = int(lineStr[j])
    return returnVect

Step3:分析數(shù)據(jù)

在 Python 命令提示符中檢查數(shù)據(jù),確保它符合要求。

testVector = img2vector(r'./digits/trainingDigits/0_13.txt')
print(testVector[00:32])
# [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  1.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
print(testVector[032:64])
# [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  1.  1.  1.  1.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]

Step4:訓(xùn)練算法

此步驟不適用于 k-近鄰算法。因?yàn)闇y試數(shù)據(jù)每一次都要與全部的訓(xùn)練數(shù)據(jù)進(jìn)行比較,所以這個(gè)過程是沒有必要的。

Step5:測試算法

計(jì)算錯(cuò)誤率,編寫函數(shù)使用提供的部分?jǐn)?shù)據(jù)集作為測試樣本,如果預(yù)測分類與實(shí)際類別不同,則標(biāo)記為一個(gè)錯(cuò)誤。

import os

def handwritingClassTest():
    # 1. 導(dǎo)入訓(xùn)練數(shù)據(jù)
    hwLabels = []
    trainingFileList = os.listdir(r'./digits/trainingDigits')  # load the training set
    m = len(trainingFileList)
    trainingMat = np.zeros((m, 1024))
    # hwLabels存儲(chǔ)0~9對(duì)應(yīng)的index位置, trainingMat存放的每個(gè)位置對(duì)應(yīng)的圖片向量
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]  # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        # 將 32*32的矩陣->1*1024的矩陣
        trainingMat[i, :] = img2vector(r'./digits/trainingDigits/%s' % fileNameStr)

    # 2. 導(dǎo)入測試數(shù)據(jù)
    testFileList = os.listdir(r'./digits/testDigits')  # iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]  # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector(r'./digits/testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print("分類器返回結(jié)果: %d, 實(shí)際結(jié)果: %d" % (classifierResult, classNumStr))
        if classifierResult != classNumStr:
            errorCount += 1.0
    print("分類錯(cuò)誤數(shù)量: %d" % errorCount)
    print("分類錯(cuò)誤率: %f" % (errorCount / float(mTest)))

Step6:使用算法

可以構(gòu)造一個(gè)小的軟件系統(tǒng),從圖像中提取數(shù)字,并完成數(shù)字識(shí)別,我們現(xiàn)實(shí)中使用的OCR,以及車牌識(shí)別都類似于這樣的系統(tǒng)。


總結(jié)

到此為止 KNN 算法的兩個(gè)案例就全部搞定了,這個(gè)算法看起來很簡單,但參數(shù) K 的選擇,距離的選擇都需要不斷的配置和測試才能得到滿意的效果。當(dāng)然,KNN 算法的主要缺點(diǎn)是不提取訓(xùn)練數(shù)據(jù)的特征,測試實(shí)例需要與每個(gè)訓(xùn)練實(shí)例計(jì)算距離導(dǎo)致算法的執(zhí)行速度很慢。為了提升搜索 K 個(gè)最鄰近實(shí)例的速度,后面有了K-D Tree的結(jié)構(gòu),這些都不是這本書的重點(diǎn)了,我們主要是先掌握基本算法,有個(gè)武器能處理數(shù)據(jù)再說,等后面實(shí)際應(yīng)用的時(shí)候再來考慮效率問題。好了,就這樣吧!See You!


參考文獻(xiàn)

  • https://github.com/apachecn/AiLearning/tree/master/docs/ml

  • https://blog.csdn.net/c406495762/column/info/16415

  • https://www.bilibili.com/video/av36993857

  • https://space.bilibili.com/97678687/channel/detail?cid=22486

  • https://space.bilibili.com/97678687/channel/detail?cid=13045


    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多