k近鄰算法的Python實現


k近鄰算法的Python實現

0. 寫在前面

這篇小教程適合對Python與NumPy有一定了解的朋友閱讀,如果在閱讀本文的源代碼時感到吃力,請及時參照相關的教程或者文檔。

1. 算法原理

k近鄰算法(k Nearest Neighbor)可以簡稱為kNN。kNN是一個簡單直觀的算法,也是機器學習從業者入門首選的算法。先看一個簡單的應用場景。

小例子

設有下表,命名為為表1

電影名稱 打斗鏡頭數量 接吻鏡頭數量 電影類型
foo1 3 104 愛情片
foo2 2 100 愛情片
foo3 1 81 愛情片
foo4 101 10 動作片
foo5 99 5 動作片
foo6 98 2 動作片

一個朴素的願望是,能夠根據打斗鏡頭與接吻鏡頭的數量來推測一部電影是屬於愛情片還是動作片。具體而言,如果有一部電影的相關信息如下,命名為表2:

電影名稱 打斗鏡頭數量 接吻鏡頭數量
foo7 18 90

我們能否給出這部電影的類型?

解決方案

表1可以抽象為一個矩陣A與一個列向量x如下:

矩陣A

foo1	3	104
foo2	2	100
foo3	1	81
foo4	101	10
foo5	99	5
foo6	98	2

列向量x

愛情片
愛情片
愛情片
動作片
動作片
動作片

表2可以抽象為一個行向量a如下:

行向量a

foo7 18 90

顯然,可以求矩陣A中每一個行向量與行向量a歐式距離(本例中計算歐式距離時只考慮打斗鏡頭數量與接吻鏡頭數量兩個分量),並按照距離由小到大排序,結果如下表,命名為表3:

電影名稱 與未知電影之的距離
foo2 18.7
foo3 19.2
foo1 20.5
foo4 115.3
foo5 117.4
foo6 118.9

此時選擇前k個距離最小的電影及其所屬的類型,結果如下表,命名為表4:

電影名稱 類型
foo2 愛情片
foo3 愛情片
foo4 愛情片

找出表4中出現次數最多的類型——“愛情片”,即kNN認為行向量a所屬的類型為愛情片。

2. Python實現

代碼的核心部分是如下函數,將其保存在文件中mykNN.py中。

import numpy as np
import operator as op
from collections import defaultdict

def classify(vec, dataSet, labels, k):
    """
    要求dataSet為NumPy的array類型
    vec: 參照行向量a
    dataSet: 參照矩陣A
    labels: 參照列向量x
    k: kNN中選擇前k小的行
    """

    size = dataSet.shape[0]
    assert size == len(labels) #斷言,確保輸入正確
    tmp = (dataSet - vec)**2 #使用了NumPy的廣播機制
    tmp = tmp.sum(axis=1)
    tmp = tmp.argsort()

    tmpDict = defaultdict(int) #簡化用於分組的代碼
    for i in range(k):
        tmpDict[labels[tmp[i]]] += 1

    return max(tmpDict.items(),key=op.itemgetter(1))[0]

3. 練手案例

我們使用第2小節的代碼解決第1小節的問題。下面的代碼文件保存為test.py,請確保test.py與mykNN.py文件位於同一個路徑下。

import numpy as np
import mykNN as knn

if __name__ == "__main__":
    dataSet = np.array([
        [3, 104],
        [2, 100],
        [1, 81],
        [101, 10],
        [99, 5],
        [98, 2]
    ])
    labels = ["愛情片", "愛情片", "愛情片",
              "動作片", "動作片", "動作片"]
    k = 3
    vec = [18, 90]
    res = knn.classify(vec,dataSet,labels,k)
    print(res)

4. 補充說明

真實的分類任務不會像我們的案例那樣簡單。

  • 一般來說,第3小節中的dataSet與labels都會放在文件或者數據庫中,並且未必是NumPy可以處理的數據類型。這時需要增加讀文件或者讀數據庫並解析轉換數據的一系列代碼。

  • 有時需要考慮對表格的不同字段歸一化的問題。

  • 以數據驅動的應用的開發需要關注kNN算法的正確率,這時需要增加判斷正確率或者錯誤率的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM