天天看點

機器學習實戰之KNN算法

本系列教程為《機器學習實戰》的讀書筆記。首先,講講寫本系列教程的原因:第一,《機器學習實戰》的代碼由Python2編寫,有些代碼在Python3上運作已會報錯,本教程基于Python3進行代碼的修訂;第二:之前看了一些機器學習的書籍,沒有進行記錄,很快就忘記掉了,通過編寫教程也是一種複習的過程;第三,機器學習相對于爬蟲和資料分析而言,學習難度更大,希望通過本系列文字教程,讓讀者在學習機器學習的路上少走彎路。

本系列教程特點:

  • 基于《機器學習實戰》
  • 盡量避免講太多數學公式,通過簡單直白的方式講解各算法的原理
  • 對于算法實作的代碼進行詳細講解

哪些讀者可以食用:

  • 了解機器學習的基本術語
  • 會Python語言
  • 會numpy和pandas庫的使用

k-近鄰算法(KNN)原理

KNN算法為分類算法。一句老話來描述KNN算法:“近朱者赤,近墨者黑”。

算法原理:計算測試樣本與每個訓練樣本的距離(距離計算方法見下文),取前k個距離最小的訓練樣本,最後選擇這k個樣本中出現最多的分類,作為測試樣本的分類。

如圖所示,綠色的為測試樣本,當k取3時,該樣本就屬于紅色類;當k取5時,就屬于藍色類了。是以k值的選擇很大程度影響着該算法的結果,通常k的取值不大于20。

機器學習實戰之KNN算法

KNN算法原理

介紹完原理後,看看KNN算法的僞代碼流程:

計算測試樣本與所有訓練樣本的距離
對距離進行升序排序,取前k個
計算k個樣本中最多的分類
           

KNN之約會對象分類

問題描述與資料情況

海倫使用約會網站尋找約會對象。經過一段時間之後,她發現曾交往過三種類型的人:

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

這裡海倫收集了1000行資料,有三個特征:每年獲得的飛行常客裡程數;玩視訊遊戲所耗時間百分比;每周消費的冰淇淋公升數。以及對象的類型标簽,如圖所示。

機器學習實戰之KNN算法

資料情況

解析資料
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清單中。結果如圖所示。

機器學習實戰之KNN算法

上面的代碼為書中所寫,其實用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算法

示例

機器學習實戰之KNN算法
機器學習實戰之KNN算法

結果

KNN算法

這裡使用的距離為歐式距離,公式為:

機器學習實戰之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)))
           
機器學習實戰之KNN算法
測試系統

最後,編寫一個簡單的測試系統,該代碼通過人為的輸入三個屬性特征,可以自動得到該約會對象的分類标簽。

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])
           
機器學習實戰之KNN算法

算法優缺點

  • 優點:精度高,對異常值不敏感
  • 缺點:計算複雜(想想每個測試樣本都要與訓練樣本繼續距離計算)

寫在最後

剛開始看,讀者可能有所不适,多将代碼敲幾遍即可。歡迎大家點贊和留言,可在微網誌(是羅羅攀啊)與我互動哦。