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

本系列教程為《機(jī)器學(xué)習(xí)實戰(zhàn)》的讀書筆記。首先,講講寫本系列教程的原因:第一歹茶,《機(jī)器學(xué)習(xí)實戰(zhàn)》的代碼由Python2編寫先匪,有些代碼在Python3上運行已會報錯种吸,本教程基于Python3進(jìn)行代碼的修訂;第二:之前看了一些機(jī)器學(xué)習(xí)的書籍呀非,沒有進(jìn)行記錄坚俗,很快就忘記掉了,通過編寫教程也是一種復(fù)習(xí)的過程岸裙;第三猖败,機(jī)器學(xué)習(xí)相對于爬蟲和數(shù)據(jù)分析而言,學(xué)習(xí)難度更大降允,希望通過本系列文字教程辙浑,讓讀者在學(xué)習(xí)機(jī)器學(xué)習(xí)的路上少走彎路。

本系列教程特點:

  • 基于《機(jī)器學(xué)習(xí)實戰(zhàn)》
  • 盡量避免講太多數(shù)學(xué)公式拟糕,通過簡單直白的方式講解各算法的原理
  • 對于算法實現(xiàn)的代碼進(jìn)行詳細(xì)講解

哪些讀者可以食用:

  • 了解機(jī)器學(xué)習(xí)的基本術(shù)語
  • 會Python語言
  • 會numpy和pandas庫的使用

k-近鄰算法(KNN)原理

KNN算法為分類算法判呕。一句老話來描述KNN算法:“近朱者赤,近墨者黑”送滞。
算法原理:計算測試樣本與每個訓(xùn)練樣本的距離(距離計算方法見下文)侠草,取前k個距離最小的訓(xùn)練樣本,最后選擇這k個樣本中出現(xiàn)最多的分類犁嗅,作為測試樣本的分類边涕。
如圖所示,綠色的為測試樣本褂微,當(dāng)k取3時功蜓,該樣本就屬于紅色類;當(dāng)k取5時宠蚂,就屬于藍(lán)色類了式撼。所以k值的選擇很大程度影響著該算法的結(jié)果,通常k的取值不大于20求厕。


KNN算法原理

介紹完原理后著隆,看看KNN算法的偽代碼流程:

計算測試樣本與所有訓(xùn)練樣本的距離
對距離進(jìn)行升序排序扰楼,取前k個
計算k個樣本中最多的分類

KNN之約會對象分類

問題描述與數(shù)據(jù)情況

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

  • 不喜歡的人
  • 魅力一般的人
  • 極具魅力的人

這里海倫收集了1000行數(shù)據(jù)弦赖,有三個特征:每年獲得的飛行常客里程數(shù)浦辨;玩視頻游戲所耗時間百分比蹬竖;每周消費的冰淇淋公升數(shù)。以及對象的類型標(biāo)簽流酬,如圖所示案腺。


數(shù)據(jù)情況
解析數(shù)據(jù)
import numpy as np
import operator

def file2matrix(filename):
    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')
        returnMat[index, :] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index = index + 1
    return returnMat, classLabelVector

定義解析數(shù)據(jù)的函數(shù):4-9行:讀取文件,并獲取文件行數(shù)康吵,創(chuàng)建一個文件行數(shù)(1000行)和3列的Numpy全0數(shù)組劈榨,創(chuàng)建用于存放類標(biāo)簽的classLabelVector列表。
10-17行:對文件進(jìn)行循環(huán)遍歷晦嵌,對前三列數(shù)據(jù)存放到returnMat數(shù)組中同辣,最后一列存放到classLabelVector列表中。結(jié)果如圖所示惭载。


解析數(shù)據(jù)

上面的代碼為書中所寫旱函,其實用pandas讀取數(shù)據(jù)后再出來是很方便了,代碼如下:

import numpy as np
import operator
import pandas as pd

def file2matrix(filename):
    data = pd.read_table(open(filename), sep='\t', header=None)
    returnMat = data[[0,1,2]].values
    classLabelVector = data[3].values
    return returnMat, classLabelVector
歸一化

由于特征間的數(shù)值差別太大描滔,在計算距離時棒妨,數(shù)值大的屬性會對結(jié)果產(chǎn)生更大的影響,這里需要對數(shù)據(jù)進(jìn)行歸一化:new = (old-min)/(max-min)含长。代碼如下:

def autoNorm(dataSet):
    minval = dataSet.min(0)
    maxval = dataSet.max(0)
    ranges = maxval - minval
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minval, (m,1))
    normDataSet = normDataSet/np.tile(ranges, (m,1))
    return normDataSet, ranges, minval

傳入的參數(shù)為測試數(shù)據(jù)(就是returnMat)券腔;首先按0軸(也就是按列)進(jìn)行min和max的計算,如圖所示進(jìn)行簡單的示例拘泞;然后構(gòu)造和數(shù)據(jù)(normDataSet)一樣大小的0矩陣纷纫;
tile函數(shù)的用法讀者可以自行百度,這里看下使用后的案例陪腌,作用就是讓一維數(shù)組重復(fù)m行辱魁,如圖所示,這樣就可以進(jìn)行數(shù)據(jù)歸一化的計算诗鸭。

示例

示例

結(jié)果
KNN算法

這里使用的距離為歐式距離染簇,公式為:


歐式距離
def classify(inX, dataSet, labels, k):
    dataSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSize,1)) -dataSet
    sqdiffMat = diffMat ** 2
    sqDistance = sqdiffMat.sum(axis = 1)
    distances = sqDistance ** 0.5
    sortedDist = distances.argsort()
    classCount ={}
    for i in range(k):
        voteIlable = labels[sortedDist[i]]
        classCount[voteIlable] = classCount.get(voteIlable, 0) + 1
    sortedClassCount = sorted(classCount.items(),
                             key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

inX為訓(xùn)練數(shù)據(jù);dataSet為測試數(shù)據(jù)强岸,labels為類別標(biāo)簽锻弓;k為取值;
2-6行:計算歐式距離
7-最后:對計算的距離進(jìn)行索引排序(argsort)请唱,然后對字典進(jìn)行排序弥咪,獲取值最多的分類。

對分類器進(jìn)行測試

這里選擇前10%數(shù)據(jù)做為測試樣本十绑,進(jìn)行分類器的測試聚至。

def test():
    r = 0.1
    X, y = file2matrix('數(shù)據(jù)/datingTestSet2.txt')
    new_X, ranges, minval = autoNorm(X)
    m = new_X.shape[0]
    numTestVecs = int(m*r)
    error = 0.0
    for i in range(numTestVecs):
        result = classify(new_X[i, :],new_X[numTestVecs:m, :], y[numTestVecs:m], 3)
        print('分類結(jié)果: %d, 真實數(shù)據(jù): %d' %(result, y[i]))
        if (result != y[i]):
            error = error + 1.0
    print('錯誤率: %f' % (error/float(numTestVecs)))
結(jié)果
測試系統(tǒng)

最后,編寫一個簡單的測試系統(tǒng)本橙,該代碼通過人為的輸入三個屬性特征扳躬,可以自動得到該約會對象的分類標(biāo)簽。

def system():
    style = ['不喜歡', '一般', '喜歡']
    ffmile = float(input('飛行里程'))
    game = float(input('游戲'))
    ice = float(input('冰淇淋'))
    X, y = file2matrix('數(shù)據(jù)/datingTestSet2.txt')
    new_X, ranges, minval = autoNorm(X)
    inArr = np.array([ffmile, game, ice])
    result = classify((inArr - minval)/ranges, new_X, y, 3)
    print('這個人', style[result - 1])
結(jié)果

算法優(yōu)缺點

  • 優(yōu)點:精度高甚亭,對異常值不敏感
  • 缺點:計算復(fù)雜(想想每個測試樣本都要與訓(xùn)練樣本繼續(xù)距離計算)

寫在最后

剛開始看贷币,讀者可能有所不適,多將代碼敲幾遍即可桨昙。歡迎大家點贊和留言际度,可在微博(是羅羅攀肮屡臁)與我互動哦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末促脉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子策州,更是在濱河造成了極大的恐慌瘸味,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件够挂,死亡現(xiàn)場離奇詭異旁仿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)孽糖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門枯冈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人办悟,你說我怎么就攤上這事霜幼。” “怎么了誉尖?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵罪既,是天一觀的道長。 經(jīng)常有香客問我铡恕,道長琢感,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任探熔,我火速辦了婚禮驹针,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诀艰。我一直安慰自己柬甥,他們只是感情好饮六,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苛蒲,像睡著了一般卤橄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上臂外,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天窟扑,我揣著相機(jī)與錄音,去河邊找鬼漏健。 笑死嚎货,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔫浆。 我是一名探鬼主播殖属,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瓦盛!你這毒婦竟也來了忱辅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谭溉,失蹤者是張志新(化名)和其女友劉穎墙懂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扮念,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡损搬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了柜与。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巧勤。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弄匕,靈堂內(nèi)的尸體忽然破棺而出颅悉,到底是詐尸還是另有隱情,我是刑警寧澤迁匠,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布剩瓶,位于F島的核電站,受9級特大地震影響城丧,放射性物質(zhì)發(fā)生泄漏延曙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一亡哄、第九天 我趴在偏房一處隱蔽的房頂上張望枝缔。 院中可真熱鬧,春花似錦蚊惯、人聲如沸愿卸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趴荸。三九已至儒溉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赊舶,已是汗流浹背睁搭。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工赶诊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留笼平,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓舔痪,卻偏偏與公主長得像寓调,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锄码,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容