k-近鄰算法概述
k-近鄰算法就是采用測量不同的特征值之間的距離進行分類
它的工作原理是:存在一個樣本資料集合,也稱作訓練樣本集,并且樣本集中每個資料都存在标簽,即我們知道樣本集中每一資料與所分類類别的對應關系。輸入沒有标簽的新資料後,将新資料的每個特征最相似資料(最鄰近)的分類标簽。一般來說,我們隻選擇樣本資料集中的前k個最相似的資料,這就是k-近鄰算法中的k的出處,通常k<=20(整數)。最後我們選擇k個最相似資料中出現次數最多的分類,最為新資料的分類。
優缺點
優點:精度高、對異常不敏感、無資料就輸入假定
缺點:計算複雜度高、空間複雜度高
适用資料範圍:數值型和标稱型
k-近鄰算法的一般流程
(1)、收集資料:可以使用任何方法
(2)、準備資料:距離計算所需要的資料,最好是結構化的資料格式
(3)、分析資料:可以使用任何方法
(4)、測試算法:計算錯誤率
(5)、使用算法:首先輸入樣本資料和結構化的輸出結果,然後運作k-近鄰算法判定輸入資料分别屬于哪個類,最後應用對計算 出的分類執行後續的處理
電影分類的例子
使用k-近鄰算法分類愛情片和動作片。有人曾經統計過很多電影的打鬥鏡頭和接吻鏡頭。假如有一部看過的電影,如何确定它是愛情片還是動作片?我們可以使用KNN來 解決這個問題。
電影名稱 | 打鬥鏡頭 | 接吻鏡頭 | 電影類型 |
---|---|---|---|
Colifornia 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 | 未知 |
即使不知道未知電影的類型,我們也可以通過某種方法計算出來。首先計算出未知電影與樣本集中其他電影的距離。
現在我們得到了樣本中所有與未知電影的距離,按照遞增排序,可以找到k個距離最近的電影。假定k=3,則三個最靠近的電影依次是 He’s Not Really into Dudes 、Beautiful Woman 、 Colifornia Man。k-近鄰算法按照距離最近的三部電影的類型,決定未知電影的類型。而這三部電影全是愛情片,是以我們判定未知電影屬于愛情片。
假設這裡有五組資料,五個對應的标簽以及一組未知标簽的資料如下,我們要來預測未知标簽的資料屬于哪一類
已知資料:
A 1.0,1.1
A 1.0,1.0
B 0.0,0.0
B 0.0,0.1
B 0.0,0.1
未知資料
1.0,1.0
代碼實作
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
@Time : 2018/8/13 16:15
@Author :
@Site :
@File : KNN.py
@Software: PyCharm
'''
from numpy import *
import operator
def createDataSet():
"""
準備資料集
A 1.0,1.1
A 1.0,1.0
B 0.0,0.0
B 0.0,0.1
B 0.0,0.1
:return: group,labels
"""
group = array([[1.0, 1.1], [1.0, 1.0], [0.0, 0.0], [0.0, 0.1], [0.0, 0.1]])
labels = ['A', 'A', 'B', 'B', 'B']
return group, labels
def classify(inX, dataSet, labels, k):
"""
K-近鄰算法
:param inX:用于分類的輸入向量
:param dataSet: 輸入的訓練樣本
:param labels: 向量的标簽
:param k:用于選擇最近鄰居的數目
:return:
"""
dataSetSize = dataSet.shape[0] #擷取訓練樣本的個數
diffMat = tile(inX,(dataSetSize, 1)) - dataSet #tile(A,n) 将A重複n次構成一個新的數組
sqDiffMat = diffMat**2 #将兩向量之間的內插補點分别平方
sqDistance = sqDiffMat.sum(axis=1) #axis=1表述行,axis=0表述列
distances = sqDistance**0.5 #開方算出歐氏距離
sortedDistancesIndex = distances.argsort() #将距離從小到大排序并将其下表存入sortedDistanceIndex
classCount = {}
for i in range(k):
voteLabel = labels[sortedDistancesIndex[i]]
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1 #統計各個标簽出現的次數
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
#----------------測試------------------
group, labels = createDataSet()
print(classify([1,1], group, labels, 3))
"""
結果輸出:A
"""