本系列教程為《機器學習實戰》的讀書筆記。首先,講講寫本系列教程的原因:第一,《機器學習實戰》的代碼由Python2編寫,有些代碼在Python3上運作已會報錯,本教程基于Python3進行代碼的修訂;第二:之前看了一些機器學習的書籍,沒有進行記錄,很快就忘記掉了,通過編寫教程也是一種複習的過程;第三,機器學習相對于爬蟲和資料分析而言,學習難度更大,希望通過本系列文字教程,讓讀者在學習機器學習的路上少走彎路。
本系列教程特點:
- 基于《機器學習實戰》
- 盡量避免講太多數學公式,通過簡單直白的方式講解各算法的原理
- 對于算法實作的代碼進行詳細講解
哪些讀者可以食用:
- 了解機器學習的基本術語
- 會Python語言
- 會numpy和pandas庫的使用
k-近鄰算法(KNN)原理
KNN算法為分類算法。一句老話來描述KNN算法:“近朱者赤,近墨者黑”。
算法原理:計算測試樣本與每個訓練樣本的距離(距離計算方法見下文),取前k個距離最小的訓練樣本,最後選擇這k個樣本中出現最多的分類,作為測試樣本的分類。
如圖所示,綠色的為測試樣本,當k取3時,該樣本就屬于紅色類;當k取5時,就屬于藍色類了。是以k值的選擇很大程度影響着該算法的結果,通常k的取值不大于20。

KNN算法原理
介紹完原理後,看看KNN算法的僞代碼流程:
計算測試樣本與所有訓練樣本的距離
對距離進行升序排序,取前k個
計算k個樣本中最多的分類
KNN之約會對象分類
問題描述與資料情況
海倫使用約會網站尋找約會對象。經過一段時間之後,她發現曾交往過三種類型的人:
- 不喜歡的人
- 魅力一般的人
- 極具魅力的人
這裡海倫收集了1000行資料,有三個特征:每年獲得的飛行常客裡程數;玩視訊遊戲所耗時間百分比;每周消費的冰淇淋公升數。以及對象的類型标簽,如圖所示。
資料情況
解析資料
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
定義解析資料的函數:4-9行:讀取檔案,并擷取檔案行數,建立一個檔案行數(1000行)和3列的Numpy全0數組,建立用于存放類标簽的classLabelVector清單。
10-17行:對檔案進行循環周遊,對前三列資料存放到returnMat數組中,最後一列存放到classLabelVector清單中。結果如圖所示。
上面的代碼為書中所寫,其實用pandas讀取資料後再出來是很友善了,代碼如下:
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
歸一化
由于特征間的數值差别太大,在計算距離時,數值大的屬性會對結果産生更大的影響,這裡需要對資料進行歸一化: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
傳入的參數為測試資料(就是returnMat);首先按0軸(也就是按列)進行min和max的計算,如圖所示進行簡單的示例;然後構造和資料(normDataSet)一樣大小的0矩陣;
tile函數的用法讀者可以自行百度,這裡看下使用後的案例,作用就是讓一維數組重複m行,如圖所示,這樣就可以進行資料歸一化的計算。
示例
結果
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為訓練資料;dataSet為測試資料,labels為類别标簽;k為取值;
2-6行:計算歐式距離
7-最後:對計算的距離進行索引排序(argsort),然後對字典進行排序,擷取值最多的分類。
對分類器進行測試
這裡選擇前10%資料做為測試樣本,進行分類器的測試。
def test():
r = 0.1
X, y = file2matrix('資料/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('分類結果: %d, 真實資料: %d' %(result, y[i]))
if (result != y[i]):
error = error + 1.0
print('錯誤率: %f' % (error/float(numTestVecs)))
測試系統
最後,編寫一個簡單的測試系統,該代碼通過人為的輸入三個屬性特征,可以自動得到該約會對象的分類标簽。
def system():
style = ['不喜歡', '一般', '喜歡']
ffmile = float(input('飛行裡程'))
game = float(input('遊戲'))
ice = float(input('冰淇淋'))
X, y = file2matrix('資料/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])
算法優缺點
- 優點:精度高,對異常值不敏感
- 缺點:計算複雜(想想每個測試樣本都要與訓練樣本繼續距離計算)
寫在最後
剛開始看,讀者可能有所不适,多将代碼敲幾遍即可。歡迎大家點贊和留言,可在微網誌(是羅羅攀啊)與我互動哦。