1. 程式人生 > >《機器學習實戰》讀書筆記2:K-近鄰(kNN)演算法 & 原始碼分析

《機器學習實戰》讀書筆記2:K-近鄰(kNN)演算法 & 原始碼分析

宣告:文章是讀書筆記,所以必然有大部分內容出自《機器學習實戰》。外加個人的理解,另外修改了部分程式碼,並添加了註釋

1、什麼是K-近鄰演算法?

簡單地說,k-近鄰演算法採用測量不同特徵值之間距離的方法進行分類。不恰當但是形象地可以表述為近朱者赤,近墨者黑。它有如下特點:

  • 優點:精度高、對異常值不敏感、無資料輸入假定
  • 缺點:計算複雜度高、空間複雜度高
  • 適用資料範圍:數值型和標稱型

2、K-近鄰演算法的工作原理:

存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中的每個資料都存在標籤,即我們知道樣本集中每一資料與所屬分類的對應關係。輸入沒有標籤的資料後,將這個沒有標籤的資料的每個特徵與樣本集中的資料對應的特徵進行比較,然後演算法提取樣本中特徵最相似的資料(最鄰近)的分類標籤。一般來說,我們只選擇樣本資料集中前 k

個最相似的資料,這就是 k-近鄰演算法中 k 的出處,通常 k 是不大於 20 的整數。最後,選擇 k 個最相似資料中出現次數最多的類別,作為新資料的分類。

2.1 一個例子

例子出自《機器學習實戰》,中文版第16頁,英文版第19頁

下面舉一個書本上的例子來說明 k-近鄰演算法大概的工作原理:
我們想使用 K-近鄰演算法來分來愛情片和動作片。有人曾統計過很多電影的打鬥鏡頭和接吻鏡頭,下圖顯示了 6 部電影的打鬥鏡頭和接吻鏡頭數。假如有一部未看過的電影,如何確定它是愛情片還是動作片呢?(當然了,我們這裡不考慮愛情動作片。邪惡的笑容)我們可以使用 kNN(k-nearest neighbors algorithm) 來解決這個問題。

這裡寫圖片描述

首先我們需要知道這個未知電影中存在多少個打鬥鏡頭和接吻鏡頭,上圖中問號的位置是該位置電影出現的鏡頭數的圖形化展示,具體數字如下表所示:
電影名稱 打鬥鏡頭 接吻鏡頭 電影型別
California Man 3 104 愛情片
He’s Not Really into Dudes 2 100 愛情片
Beautiful Woman 1 81 愛情片
Kevin Longblade 101 10 動作片
Robo Slayer 3000 99 5 動作片
Amped II 98 2 動作片
? 18 90 未知


即使不知道未知電影屬於哪種型別,我們也可以通過某種方法計算出來。首先要計算未知電影與樣本集中其他電影的距離,計算方法很簡單,即歐式空間距離(Euclidean Distance),結果如下表所示。

電影名稱 與未知電影的距離
California Man 20.5
He’s Not Really into Dudes 18.7
Beautiful Woman 19.2
Kevin Longblade 115.3
Robo Slayer 3000 117.4
Amped II 118.9


現在我們得到了樣本集中所有電影與未知電影的距離,按照距離遞增排序,可以找到 k 個距離最近的電影,例如 k=3,則三個最靠近的電影是 He’s Not Really into Dudes、Beautiful Woman 和 California Man。K-近鄰演算法按照距離最近的三部電影的型別,決定未知電影的型別,而這三部電影全是愛情片,因此我們判定未知電影是愛情片。

2.2 K-近鄰演算法的一般流程

k-近鄰演算法的一般流程分為如下 6 個步驟:

  1. 蒐集資料:可以使用任何方法。
  2. 準備資料:距離計算所需要的值,最好是結構化的資料。
  3. 分析資料:可以使用任何方法。
  4. 訓練演算法:此步驟不適用於k-近鄰演算法。
  5. 測試演算法:計算錯誤率。
  6. 使用演算法:首先需要輸入樣本資料和待分類資料,然後執行k-近鄰演算法判定待分類資料分別屬於哪個分類,最後應用計算出的分類執行後續的處理。

3、使用python實現kNN演算法

我們主要用的程式語言是python,以及一些python增強包。選用python使我們不許要考慮太多的程式設計細節,能夠把重心都放在程式邏輯上。

3.1 使用python匯入資料

機器學習最重要的就是資料,首先我們來捏造一些樣本資料。將下面的程式碼儲存到名為 kNN.py 的文字檔案中:

from numpy import *

def createDataSet():
    dataSet = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) # 建立一個2x2的陣列
    labels = ['A', 'A', 'B', 'B'] # 建立一個長度為4的列表
    return dataSet, labels

在上面的程式碼中,我們匯入了科學計算包 NumPy,如果你還沒有安裝 NumPy,請參考我的另外一篇文章《機器學習實戰》讀書筆記1:NumPy的安裝及簡單用法

在上面的程式碼中,我們建立了一個大小為 2x2 的 NumPy 陣列 dataSet,dataSet 的每一行是一個數據項。我們還建立了一個長度為 4 的列表 labels,labels 的每一項對應於 dataSet 的每一行,其對應關係如下表所示:

dataSet[i],即樣本 特徵0 特徵1 labels[i],即樣本對應的類別
dataSet[0] 1.0 1.1 A
dataSet[1] 1.0 1.0 A
dataSet[2] 0 0 B
dataSet[3] 0 0.1 B


現在我們開啟命令提示符(我使用的是 Ubuntu),檢查程式碼是否能夠正常工作:
1. 在程式碼檔案 kNN.py 所在目錄下開啟命令提示符(終端)
2. 在終端中輸入python開啟python(我使用的是python2.7)
3. 匯入我們剛才寫的程式碼 kNN.py:import kNN
4. 輸入如下命令獲得由函式 createDataSet() 捏造的資料樣本並儲存到變數 gropu 和 labels 中:
>>> group, labels = kNN.createDataSet()
5. 輸入 group 和 labels 產看資料內容是否正確:
結果應該如下所示:

>>> group
array([[ 1. ,  1.1],
       [ 1. ,  1. ],
       [ 0. ,  0. ],
       [ 0. ,  0.1]])`
>>> labels
['A', 'A', 'B', 'B']

上述步驟的執行截圖:

這裡寫圖片描述

上面的四組資料和其對應的標籤可以表示在如下的二維座標系中:
這裡寫圖片描述

現在我們已經知道 python 如何解析資料,如何載入資料,以及 kNN 演算法的工作原理,接下來我們將使用這些方法完成分類任務。

3.2 實施 kNN 演算法

首先給出 kNN 演算法的虛擬碼。對未知類別屬性的資料集中的每個點一次執行以下操作:

  1. 計算已知類別資料集中的每個點與未知點的距離;
  2. 按照距離遞增次序排序;
  3. 選取與未知點距離最小的 k 個點;
  4. 確定前 k 個點所在類別的出現頻率;
  5. 返回前 k 個點出現頻率最高的類別作為未知點的預測分類。

下面我們寫一個函式 classify0() 來實現上面的步驟:

from operator import itemgetter
# inVec為待分類向量,dataSet和labels為資料集,k是最近點的個數
def classify0(inVec, dataSet, labels, k):
    numberOfLines = dataSet.shape[0] # 獲得資料集樣本數量

    diffMat = tile(inVec, (numberOfLines, 1)) - dataSet # 將資料集中每個點都與待分類點相減,即各個特徵相減
    squareDiffMat = diffMat**2 # 求差的平方
    squareDistance = squareDiffMat.sum(axis=1) # 求差的平方的和
    distances = squareDistance**0.5 # 對平方和開方得到距離

    # 對距離進行排序,argsort()函式預設按升序排列,但只返回下標,不對原陣列排序
    sortedDistIndicies = distances.argsort()
    classCount = {} # 用於儲存各個類別出現的次數

    for i in range(k): # 統計最近的 k 個點的類別出現的次數
        label = labels[sortedDistIndicies[i]]
        classCount[label] = classCount.get(label, 0) + 1

    # 對類別出現的次數進行排序,sorted()函式預設升序
    sortedClassCount = sorted(classCount.iteritems(), key=itemgetter(1), reverse=True)
    return sortedClassCount[0][0] # 返回類別出現次數最多的分類名稱

相信上面程式碼的註釋已經把程式碼解釋的很清楚了。只需要注意以下幾個函式和 numpy 語法的用法:
1、shape()函式:返回陣列的尺寸資訊,例如:

>>> x = tile((1,2),(3,2))
>>> x.shape[0] # 返回第0維的大小,行數
3
>>> x.shape[1] # 返回第1維的大小,列數
4
>>> shape(x) # 返回尺寸
(3, 4)

2、tile()函式:將陣列、列表或元組平鋪,返回平鋪後的陣列,例如 tile([1,2],(3,2)) 將返回如下陣列:

>>> tile([1,2],(3,2)) 
array([[1, 2, 1, 2],
       [1, 2, 1, 2],
       [1, 2, 1, 2]])

3、sum()函式,示例:

>>> x = tile((1,2),(3,2))
>>> x
array([[1, 2, 1, 2],
       [1, 2, 1, 2],
       [1, 2, 1, 2]])
>>> x.sum(axis=0)
array([3, 6, 3, 6])
>>> x.sum(axis=1)
array([6, 6, 6])

4、argsort()函式,返回排序後的原來位置的索引。示例:

>>> v = [1, 4, 2, 3]
>>> argsort(v)
array([0, 2, 3, 1])

5、sorted()函式,按引數 key 排序,示例(按字典的鍵的值降序排列):

>>> d = {'a':2,'b':1,'c':6,'d':-2}
>>> d
{'a': 2, 'c': 6, 'b': 1, 'd': -2}
>>> from operator import itemgetter
>>> sorted(d.iteritems(),key=itemgetter(1),reverse=True)
[('c', 6), ('a', 2), ('b', 1), ('d', -2)]

具體用法,請參考文件,或百度。

另外,我們在前面提到過,距離計算使用的是歐式距離,其公式如下:

d=(x0x1)2+(y0y1)2
更高維度的歐式距離也是如此計算。即對分量相減後差的平方求和再開方。例如點(0,0)和點(1,2)之間的距離為:
d=(01)2+(02)2
又例如有四個特徵值的點(1,0,0,1)(7,6,9,4)的距離為:
d=(17)2+(06)2+(09)2+(14)2

好了,現在我們來試一試 k-近鄰(kNN)演算法。
1、首先回到剛才的 python 視窗,輸入reload(kNN)重新載入我們的程式碼。
2、輸入kNN.classify([0,0], group, labels, 3)來對未知資料點(0,0)進行分類,其中 group 和 labels 是我們用函式 createDataSet() 得到的樣本資料集,3 是 k 的值,結果應該為B:

這裡寫圖片描述

3.3 測試分類器

分類器也有可能出錯,即把屬於某一類的分到另一類。

=
我們將在下面的例項中來測試分類器。

4、示例:使用 K-近鄰法改進約會網站的配對效果

此示例出自《機器學習實戰》,中文版第20頁,英文版第24頁

下面是問題的原文:

我的朋友海倫一直使用線上約會網站尋找合適自己的約會物件。儘管約會網站會推薦不同的人選,但她並不是喜歡每一個人。經過一番總結,她發現曾交往過三種類型的人:
(1)不喜歡的人;
(2)魅力一般的人;
(3)極具魅力的人;
儘管發現了上述規律,但海倫依然無法將約會網站推薦的匹配物件歸入恰當的分類,她覺得可以在週一到週五約會那些魅力一般的人,而週末則更喜歡與那些極具魅力的人為伴。海倫希望我們的分類軟體可以更好地幫助她將匹配物件劃分到確切的分類中。此外,海倫還收集了一些約會網站未曾記錄的資料資訊,她認為這些資料更助於匹配物件的歸類。

在約會網站上使用 k-近鄰演算法的步驟如下:

  1. 收集資料:提供文字檔案;
  2. 準備資料:使用 Python 解析文字檔案;
  3. 分析資料:使用 Matplotlib 畫二維擴散圖;
  4. 訓練演算法:此步驟不適用於K-近鄰演算法;
  5. 測試演算法:使用海倫提供的部分資料作為測試樣本,
    測試樣本和非測試樣本的區別在於:測試樣本是已經完成分類的資料,如果預測分類與實際類別不同,則標記為一個錯誤。
  6. 使用演算法:產生簡單的命令列程式,然後海倫可以輸入一些特徵資料以判斷對方是否為自己喜歡的型別。

4.1 準備資料:從文字檔案中解析資料

海倫收集約會資料已經有了一段時間,她把這些資料存放在文字檔案datingTestSet2.txt中,每個樣本資料佔據一行,總共有1000行。海倫的樣本主要包括以下3種特徵:

  1. 每年獲得的飛行常客里程數;
  2. 玩視訊遊戲所耗時間百分比;
  3. 每週消費的冰淇淋公升數;

部分資料截圖如下(第一列為飛行里程,第二列為遊戲時間百分比,第三列為冰淇淋公升數):

這裡寫圖片描述

在將上述特徵資料輸入到分類器之前,必須將待處理資料的格式改變為分類器可以接受的格式。在 kNN.py 中建立名為 file2matrix 的函式,以此來處理輸入格式問題。該函式的輸入為文字檔名字串,輸出為訓練樣本矩陣和類標籤向量。

將下面的程式碼增加到kNN.py中:


            
           

相關推薦

機器學習實戰讀書筆記2K-近鄰(kNN)演算法 & 原始碼分析

宣告:文章是讀書筆記,所以必然有大部分內容出自《機器學習實戰》。外加個人的理解,另外修改了部分程式碼,並添加了註釋 1、什麼是K-近鄰演算法? 簡單地說,k-近鄰演算法採用測量不同特徵值之間距離的方法進行分類。不恰當但是形象地可以表述為近朱者赤,近墨者黑

機器學習實戰讀書筆記(2)--決策樹

決策樹 決策樹的一個重要任務是為了資料中所蘊含的知識資訊,因此決策樹可以使用一系列不熟悉的資料集合,並從中提取系列規則,在這些機器根據資料集建立規則時,就是機器學習的過程.專家系統中經常使用決策樹 決策樹的構造 優點:計算複雜度不高,輸出結果易於理解,對中間值缺失不敏

機器學習實戰》第二章k-近鄰演算法2)約會物件分類

這是KNN的一個新例子。 在一個約會網站裡,每個約會物件有三個特徵: (1)每年獲得的飛行常客里程數(額...這個用來判斷你是不是成功人士?) (2)玩視訊遊戲所耗時間百分比(額...這個用來判斷你是不是肥宅?) (3)每週消費的冰激凌公升數(額...這個是何用意我真不知道

機器學習實戰】第2K-近鄰演算法(k-NearestNeighbor,KNN)

第2章 k-近鄰演算法 <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

機器學習實戰》第二章k-近鄰演算法(3)手寫數字識別

這是k-近鄰演算法的最後一個例子——手寫數字識別! 怎樣?是不是聽起來很高大上? 呵呵。然而這跟影象識別沒有半毛錢的關係 因為每個資料樣本並不是手寫數字的圖片,而是有由0和1組成的文字檔案,就像這樣:         嗯,這個資料集中的每一個樣本用圖形軟體處理過,變成了寬高

機器學習實戰》第二章k-近鄰演算法(1)簡單KNN

收拾下心情,繼續上路。 最近開始看Peter Harrington的《Machine Learning in Action》... 的中文版《機器學習實戰》。準備在部落格裡面記錄些筆記。 這本書附帶的程式碼和資料及可以在這裡找到。 這本書裡程式碼基本是用python寫的

機器學習實戰---讀書筆記 第10章 利用K均值聚類演算法對未標註資料分組---1

#!/usr/bin/env python # encoding: utf-8 import os from matplotlib import pyplot as plt from numpy import * ''' 讀書筆記之--<<機器學習實戰>>--第10章_

機器學習實戰讀書筆記(1)--k鄰近演算法

kNN演算法 kNN演算法概述 kNN演算法和kmeans演算法的比較 knn工作原理: 存在一個樣本資料集合(訓練樣本集),並且每個樣本都具有標籤,輸入新的樣本後,我們將樣本的特徵與訓練樣本集中的資料特徵比較,演算法提取特徵最相似的k個樣本的標籤,採用少數服從多數的

機器學習實戰讀書筆記(四)樸素貝葉斯演算法

樸素貝葉斯 優點: 在資料較少的情況下仍然有效 可以處理多類別問題 缺點:對輸入的資料的準備方式較為敏感 適用資料型別:標稱型資料 p1(x,y)>p2(x,y) 那麼類別是1 p2(x,y)>p1(x,y) 那麼類別是2 貝葉斯決策的核心是選擇具有最高概率的決策

機器學習實戰讀書筆記(4)--logistic迴歸

Logistic迴歸 假設我們有一些資料點,用一條直線對這些點進行擬合,這個擬合的過程成為迴歸.在計量經濟學中我們大量的使用過線性迴歸,線性迴歸的模型試圖得到一個通過屬性的線性組合來進行預測的函式,即 f(x)=WTX+b

機器學習實戰讀書筆記(3)--樸素貝葉斯

基於貝葉斯決策理論的分類方法 優點:在資料較少的情況下仍然有效,可以處理多類別問題 缺點:對輸入資料的準備方式比較敏感,需要標稱資料.確定貝葉斯最優假設的計算代價較大 樸素貝葉斯是貝葉斯決策理論的一部分.貝葉斯決策理論的核心思想:一個數據集包括2類(或兩類以上

機器學習公開課筆記(8)k-means聚類和PCA降維

K-Means演算法 非監督式學習對一組無標籤的資料試圖發現其內在的結構,主要用途包括: 市場劃分(Market Segmentation) 社交網路分析(Social Network Analysis) 管理計算機叢集(Organize Computer Clusters) 天文學資料分析(A

機器學習公開課筆記(2)多元線性迴歸

多元線性迴歸 一元線性迴歸只有一個特徵$x$,而多元線性迴歸可以有多個特徵$x_1, x_2, \ldots, x_n$ 假設 (Hypothesis):$h_\theta(x)=\theta^Tx=\theta_0x_0+\theta_1x_1+\ldots+\theta_nx_n$ 引數 (Para

機器學習實戰(第二篇)-k-近鄰演算法開發手寫識別系統

   上一篇文章中,我們學習了使用k近鄰演算法改進約會網站,實現了通過一些資料的輸入判斷人員屬於哪一個分類。但是上篇文章基於的資料都是我們能夠簡單理解的數字資訊,本篇文章我們在人不太容易看懂的資料上使用分類器。這篇文章中我們將一步步構造使用k-近鄰分類器的手寫識別系統。為了

機器學習實戰(第二篇)-k-近鄰演算法改進約會網站配對結果

    前面幾篇中,我們學習了機器學習演算法中k-近鄰演算法,本章我們將使用該演算法進行改進約會網站配對結果的工作。首先我們先進入背景介紹:      我的朋友海倫一直使用線上約會網站尋找適合自己的約會物件。儘管約會網站會推薦不同的人選,但她沒有從中找到喜歡的人。經過一番總

機器學習實戰(第二篇)-k-近鄰演算法Python實現

      上一篇幅中,我們介紹了k-近鄰演算法的基本概念、具體的分析步驟和分析方法,本篇中我們將介紹如何通過Python工具實現一個k-近鄰演算法。 1. 準備-使用Python匯入資料     首

機器學習實戰筆記之十一——使用Apriori演算法進行關聯分析

第十一章 使用Apriori演算法進行關聯分析 Apriori演算法頻繁項集生成關聯規則生成 從大規模資料集中尋找物品間的隱含關係被稱作為關聯分析(association analysis)和關聯規則學習(association rule learning)。 11.

機器學習實戰》第2章閱讀筆記3 使用K近鄰演算法改進約會網站的配對效果—分步驟詳細講解1——資料準備從文字檔案中解析資料(附詳細程式碼及註釋)

 本篇使用的資料存放在文字檔案datingTestSet2.txt中,每個樣本資料佔據一行,總共有1000行。 樣本主要包含以下3中特徵: (1)每年獲得飛行常客里程數 (2)玩視訊遊戲所耗時間百分比 (3)每週消費的冰淇淋公升數 在使用分類器之前,需要將處理的檔案格式

機器學習實戰筆記K-近鄰演算法在約會網站上的應用

K-近鄰演算法概述 簡單的說,K-近鄰演算法採用不同特徵值之間的距離方法進行分類  K-近鄰演算法 優點:精度高、對異常值不敏感、無資料輸入假定。 缺點:計算複雜度高、空間複雜度高。 適用範圍:數值型和標稱型。   k-近鄰演算法的一般流程 收集資料:可使用任何方法

機器學習實戰筆記(一)K-近鄰演算法

一、K-近鄰演算法 1.1 k-近鄰演算法簡介 簡單的說,K-近鄰演算法採用測量不同特徵值之間的距離的方法進行分類。 1.2 原理 存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每一資料 與所屬分類的對應關係。輸入沒有標籤的新資料