機(jī)器學(xué)習(xí)實(shí)戰(zhàn)---KNN算法的應(yīng)用小例

ok,今天花了一天時(shí)間看了小人書(機(jī)器學(xué)習(xí)實(shí)戰(zhàn)),并且擼到了KNN算法,并完成了一個(gè)KNN算法的應(yīng)用

真的!!!小人書是本特別不錯(cuò)的適合入門ML的書!!!!!

沒有繁雜的數(shù)學(xué)推導(dǎo)過(guò)程,先給出概念和實(shí)戰(zhàn)應(yīng)用,等對(duì)ML有個(gè)大致了解后再去啃那些理論書,大量的代碼真的很對(duì)胃口啊啊啊啊

關(guān)與機(jī)器學(xué)習(xí)的這里不廢話太多,直接進(jìn)入正題

KNN算法
那么什么是KNN呢?

K近鄰算法(KNN), 首先KNN屬于機(jī)器學(xué)習(xí)中監(jiān)督學(xué)習(xí)中的一個(gè)算法,這里先不說(shuō)什么是監(jiān)督學(xué)習(xí),很直接的理解,KNN就是一個(gè)算法,大家按普通算法的路子學(xué)就行了

KNN的用途:

KNN是一個(gè)分類算法,當(dāng)然主要用于各種各樣的分類了啊,比如給你一大堆的狗,讓你給他們一個(gè)個(gè)分類(泰迪啊,金毛啊,西伯利亞雪橇犬啊......),這時(shí)候就可以用到KNN了

KNN的工作原理:

首先給出官方介紹: 存在一個(gè)樣本數(shù)據(jù)集合 ,也稱作訓(xùn)練樣本集, 并且樣本集中每個(gè)數(shù)據(jù)都存在標(biāo)簽,即我們知道樣本集中每一數(shù)據(jù)與所屬分類的對(duì)應(yīng)關(guān)系。 輸人沒有標(biāo)簽的新數(shù)據(jù)后, 將新數(shù)據(jù)的每個(gè)特征與樣本集中數(shù)據(jù)對(duì)應(yīng)的特征進(jìn)行比較,然后算法提取樣本集中特征最相似數(shù)據(jù)(最 近 鄰 )的分類標(biāo)簽。一般來(lái)說(shuō),我們只選擇樣本數(shù)據(jù)集中前 K個(gè)最相似的數(shù)據(jù),這就是 K- 近鄰算法中 K 的出處 , 通常 K 是不大于 20 的整數(shù).最后 ,選擇 & 個(gè)最相似數(shù)據(jù)中出現(xiàn)次數(shù)最多的分類,作為新數(shù)據(jù)的分類

太繁雜了吧,這里給出通俗的理解:
首先拿出剛剛分類的狗,首先我們要先知道各種各樣的狗(樣本集)是長(zhǎng)什么樣子(標(biāo)簽)的,現(xiàn)在從外面跑來(lái)一只小野狗,我們 想知道這個(gè)小野狗是屬于什么狗,然后我們就開始拿這個(gè)狗給分好類的狗進(jìn)行對(duì)比,首先先比比身材,比比眼睛,耳朵....(樣本特征),最后我們找出了一個(gè)跟這個(gè)小野狗(k個(gè)特征)最像(最近鄰)的狗,那么就可以判斷出這個(gè)小野狗屬于什么狗

上面的狗也很麻煩?
再來(lái)一個(gè)不是很嚴(yán)謹(jǐn)?shù)牡歉菀桌斫獾?
給出一個(gè)三維坐標(biāo),我們給出一堆水果,x軸代表大小,y軸代表顏色,z軸代表形狀(0為圓,1為橢圓....)
然后我們分別把蘋果,梨,葡萄按特征放在這個(gè)三維坐標(biāo)里,當(dāng)然這三種水果應(yīng)該是分成三部分,現(xiàn)在拿出一個(gè)不知道是什么的水果,按照它的特征找出它在三維坐標(biāo)里的位置,然后一個(gè)個(gè)計(jì)算這個(gè)未知水果距離每個(gè)已知水果的距離,當(dāng)它與K個(gè)最近距離中哪個(gè)水果多,那么就判斷這個(gè)水果是什么水果,
比如: 在離這個(gè)水果最近的10個(gè)水果中有5個(gè)蘋果,3個(gè)梨,2個(gè)葡萄,那么就說(shuō)這個(gè)水果是個(gè)蘋果

廢話太多,重新進(jìn)入正題:

用到KNN的一般流程

(1) 收集數(shù)據(jù):可以使用任何方法。
(2) 準(zhǔn)備數(shù)據(jù):距離計(jì)算所需要的數(shù)值,最好是結(jié)構(gòu)化的數(shù)據(jù)格式。
(3) 分析數(shù)據(jù):可以使用任何方法。
(4) 訓(xùn)練算法:此步驟不適用于 K近鄰算法。
(5) 測(cè)試算法:計(jì)算錯(cuò)誤率。
(6) 使 用 算法 :首先需要輸入樣本數(shù)據(jù)和結(jié)構(gòu)化的輸出結(jié)果,然后運(yùn)行女-近鄰算法判定輸入數(shù)據(jù)分別屬于哪個(gè)分類,最后應(yīng)用對(duì)計(jì)算出的分類執(zhí)行后續(xù)的處理

因此看出,KNN主要在用在整個(gè)程序的最后的結(jié)果處理


那么,KNN的算法的算法流程是什么?

對(duì)未知類別屬性的數(shù)據(jù)集中的每個(gè)點(diǎn)依次執(zhí)行以下操作:
(1) 計(jì)算已知類別數(shù)據(jù)集中的點(diǎn)與當(dāng)前點(diǎn)之間的距離;
(2) 按照距離遞增次序排序;
(3) 選取與當(dāng)前點(diǎn)距離最小的K個(gè)點(diǎn);
(4) 確定前K個(gè)點(diǎn)所在類別的出現(xiàn)頻率;
(5) 返回前K個(gè)點(diǎn)出現(xiàn)頻率最高的類別作為當(dāng)前點(diǎn)的預(yù)測(cè)分類。

代碼實(shí)現(xiàn)就是:

def classify(inx, dataset, labels, k):# inx: 用于分類的輸入向量   dataset: 訓(xùn)練樣本集  labels: 標(biāo)簽向量  k : k值
    datasetsize = dataset.shape[0]   #: shape用于讀取矩陣長(zhǎng)度,[參數(shù)]為維數(shù)
    diffmat = tile(inx, (datasetsize , 1)) - dataset    # 此處使用inx構(gòu)造一個(gè)和樣本集一樣的矩陣,從而使未知量可以和每一個(gè)已知樣本進(jìn)行對(duì)比,并且注意,一下進(jìn)行的運(yùn)算結(jié)果,其運(yùn)算是單獨(dú)對(duì)每一行進(jìn)行運(yùn)算
    sqdiffmat = diffmat**2
    sqdistances = sqdiffmat.sum(axis= 1)
    distances = sqdistances**0.5   # 以上為求距離,即輸入向量與樣本的距離
    sorteddistindicies = distances.argsort()  # 將距離從小到大排序
    classcount = {}
    for i in range(k):
        voteiabel = labels[sorteddistindicies[i]]
        classcount[voteiabel] = classcount.get(voteiabel, 0) + 1  #統(tǒng)計(jì)離各標(biāo)簽最近K個(gè)的個(gè)數(shù)
    sortedclasscount = sorted(classcount.items(), key = operator.itemgetter(1), reverse = True)   # iteritems()返回一個(gè)迭代器
    # sorted()用于進(jìn)行排序,items()將字典以列表的形式返回,key為用于比較的維度,reverse為排序方式,默認(rèn)false從小到大
    return sortedclasscount[0][0]

解讀一下: 注:一下在非具體實(shí)例分析時(shí)皆以找狗為例

跟宇哥學(xué)的

首先:要進(jìn)行對(duì)未知狗的分類,需要拉過(guò)來(lái)一個(gè)未知狗(輸入向量),到你的狗圈(樣本集),以及定義出什么樣的是什么狗(每個(gè)狗有每個(gè)狗的狗樣),以及跟幾個(gè)狗(K)對(duì)比

然后使用歐式距離公式,求出未知狗和狗圈里每個(gè)狗的距離,找出最像的K個(gè)狗,看哪種狗的數(shù)量最高就是屬于哪個(gè)狗了

歐式距離公式:

就是三角形求第三那邊那個(gè)公式了啊

1.下面是一個(gè)實(shí)例:找女朋友
大致了解一下就是在一個(gè)交友網(wǎng)站上,根據(jù)對(duì)方幾個(gè)特征而預(yù)測(cè)到底適不適合做女朋友
數(shù)據(jù)的話之后會(huì)上傳到給github上

給出找女朋友的策略

(1) 收集數(shù)據(jù):提供文本文件。
(2)_ 準(zhǔn)備數(shù)據(jù) : 使用python解析文本文件。
( 3 ) 分 析 數(shù) 據(jù) :使用matplotlib畫二維擴(kuò)散圖。
(4) 訓(xùn)練算法:此步驟不適用于K近鄰算法。
(5) 測(cè)試算法:使用部分?jǐn)?shù)據(jù)作為測(cè)試樣本。 測(cè)試樣本和非測(cè)試樣本的區(qū)別在于:測(cè)試樣本是已經(jīng)完成分類的數(shù)據(jù),如果預(yù)測(cè)分類與實(shí)際類別不同,則標(biāo)記為一個(gè)錯(cuò)誤。
(6) 使用 算 法 :產(chǎn)生簡(jiǎn)單的命令行程序,然后輸入一些特征數(shù)據(jù)以判斷對(duì)方是否為自己喜歡的類型。

首先我們分析一下數(shù)據(jù)

def file2matrix(filename):
    fr = open(filename)
    arrayolines = fr.readlines() #讀取到文件行數(shù)
    numberoflines = len(arrayolines)  #得到文件行數(shù)
    returnmat = zeros((numberoflines, 3))  # 創(chuàng)建返回的numpy矩陣,以0填充
    classlabelvector = []
    index = 0
    for line in arrayolines:
        line = line.strip() # 去除回車字符
        listfromline = line.split('\t')  # 進(jìn)行切片 ,切片中是\t,生成一個(gè)元素列表
        returnmat[index, : ]= listfromline[0:3]  # 選取3個(gè)元素存儲(chǔ)到特征矩陣中
        classlabelvector.append(int(listfromline[-1])) # 將最后一列存貯到向量中
        index += 1
    return returnmat, classlabelvector

代碼解讀: 首先傳過(guò)來(lái)一個(gè)文件,打開文件得到文件數(shù)量,然后創(chuàng)建一個(gè)等大小的0矩陣,由于文件中每個(gè)樣本數(shù)據(jù)包含三個(gè)特征和一個(gè)標(biāo)簽,因此將特征值和標(biāo)簽分開

歸一化數(shù)值

這里的歸一化解釋一下,還記得我們計(jì)算KNN的時(shí)候是按每個(gè)樣本的特征值差平方和求根的嗎?這里的每個(gè)特征應(yīng)該是等價(jià)的(以后會(huì)有對(duì)每個(gè)特征的側(cè)重),就拿等價(jià)來(lái)說(shuō)的時(shí)候,雖然在計(jì)劃上是等價(jià)的,但是由于每個(gè)特征值取值范圍不同,那么很有可能就不能等價(jià)(例如:a特征的值基本都是10000左右,而b特征值都是10左右,如果直接計(jì)算的話連個(gè)特征就是不平等的,導(dǎo)致出現(xiàn)錯(cuò)誤),因此這里要對(duì)數(shù)據(jù)做歸一化處理,使數(shù)據(jù)特征值轉(zhuǎn)化為0到1區(qū)間內(nèi)(如果這里再有特征側(cè)重可添加權(quán)重,但應(yīng)先做歸一化處理)
處理方法:


歸一化方法

也就是將原數(shù)值減去最小值然后除以最大值和最小值的差

上代碼:

def autonorm(dataset):
    minvals = dataset.min(0)  # min(0)和max(0)可從數(shù)據(jù)集中選出最小值和最大值
    maxvals = dataset.max(0)
    ranges = maxvals - minvals
    normdataset = zeros(shape(dataset))  #讀取一個(gè)和數(shù)據(jù)集一樣的0矩陣
    m = dataset.shape[0]
    normdataset = dataset - tile(minvals, (m, 1))   # 元數(shù)據(jù)集每行將去一個(gè)最小值
    normdataset = normdataset/tile(ranges, (m, 1))
    return normdataset, ranges, minvals

很容易理解,就是按照上面的數(shù)學(xué)公式對(duì)數(shù)據(jù)進(jìn)行處理,因?yàn)槭亲鼍仃囘\(yùn)算,所以要引用同等零型矩陣

測(cè)試算法:

經(jīng)過(guò)KNN處理后的數(shù)據(jù)結(jié)果,我們想知道他的處理結(jié)果怎么樣,這里就要進(jìn)行測(cè)試,也就是評(píng)估算法正確率,
通常我們只提供已有數(shù)據(jù)的 90 %作為訓(xùn)練樣本來(lái)訓(xùn)練分類器 ,而使用其余的 10% 數(shù)據(jù)去測(cè)試分類器(測(cè)試數(shù)據(jù)占總數(shù)據(jù)比例不同也會(huì)影響到算法的測(cè)試結(jié)果),且數(shù)據(jù)劃分是隨機(jī)的
這里我們測(cè)試的方法就是對(duì)數(shù)據(jù)進(jìn)行一系列操作后(讀取,歸一,分類)然后與標(biāo)簽進(jìn)行對(duì)比算出正確率
上代碼:

def datingclasstest():
    horatio = 0.10
    datingdatamat, datinglabels = file2matrix('datingTestSet2.txt')  # 獲取數(shù)據(jù)
    normmat, ranges, minvals = autonorm(datingdatamat)  # 將數(shù)據(jù)的樣本集進(jìn)行歸一化
    m = normmat.shape[0]    # 數(shù)據(jù)集0維維數(shù)
    numtestvecs = int(m*horatio)  # 采取10%做為測(cè)試集
    errorcount = 0.0
    for i in range(numtestvecs):
        classifierresult = classify(normmat[i, : ], normmat[numtestvecs:m, :],  # knn分類器
                                    datinglabels[numtestvecs:m], 4)
        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 right rate is : %f" % (1-errorcount/float(numtestvecs)))

最后我們到了最后一步---使用算法:

def classifyperson():
    resultlist = ['not at all', 'in small doses', 'in large deses']
    percenttats = float(input("percentage of time spent playing vider games?\n\t"))
    ffmiles = float(input("frequent flier miles earned per year?\n\t"))
    icecream = float(input("liters of ice cream consumed per year?\n\t"))
    datingdatamat, datinglabels = file2matrix('datingTestSet2.txt')
    normmat, ranges, minvals = autonorm(datingdatamat)
    inarr = np.array([ffmiles, percenttats, icecream])
    classifierresult = classify((inarr- minvals)/ranges, normmat, datinglabels, 3)
    print("you will probably like this person: ", resultlist[classifierresult -1])

這里用到了input()函數(shù)進(jìn)行數(shù)值輸入從而當(dāng)做未知數(shù)據(jù)進(jìn)行運(yùn)算,最后得出結(jié)果

程序運(yùn)行截圖


image.png

3-NN時(shí)


image.png

4-NN時(shí)
image.png

5-NN時(shí):



正確率還是不錯(cuò)的


到這里一個(gè)應(yīng)用KNN算法的找女朋友應(yīng)用就結(jié)束了,由于本人為ML初學(xué)者,因此很多內(nèi)容是參考機(jī)器學(xué)習(xí)實(shí)戰(zhàn)這本書,因此這篇文章也算是學(xué)習(xí)的一個(gè)筆記
學(xué)習(xí)ML已經(jīng)快有兩個(gè)月了,這是第一次真正的去接觸ML算法,之前一開始都有在為ML打基礎(chǔ)(微積分,線性代數(shù),概率統(tǒng)計(jì),ps,這些只是入門基礎(chǔ),而且真正的學(xué)會(huì)這些才只是入門基礎(chǔ),畢竟只是學(xué)了一遍這些書后的我對(duì)很多算法的數(shù)學(xué)推導(dǎo)還是力不從心的啊),不過(guò),加油就是了!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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