本系列教程為《機(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算法的偽代碼流程:
計算測試樣本與所有訓(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ù)
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é)果如圖所示惭载。
上面的代碼為書中所寫旱函,其實用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ù)歸一化的計算诗鸭。
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)))
測試系統(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])
算法優(yōu)缺點
- 優(yōu)點:精度高甚亭,對異常值不敏感
- 缺點:計算復(fù)雜(想想每個測試樣本都要與訓(xùn)練樣本繼續(xù)距離計算)
寫在最后
剛開始看贷币,讀者可能有所不適,多將代碼敲幾遍即可桨昙。歡迎大家點贊和留言际度,可在微博(是羅羅攀肮屡臁)與我互動哦。