算法描述
給定一個訓練數據集,對新的輸入實例,在訓練數據集中找到與該實例最鄰近的k個實例,這k個實例的多數屬於某個類,就把該輸入實例分爲這個類。
三個基本要素
1.距離度量
兩個實例之間的距離可以用範數來定義,其中p可以選擇。範數的定義爲:
這裏面的和代表兩個實例,這兩個實例都有n個分量。
比較常用的是p=2,此時稱爲歐氏距離,即:
例如,,則這兩個實例之間的歐氏距離爲:
2.k值選擇
k選的小的話近似誤差會減小,但估計誤差會增大。
k選的大的話近似誤差會增大,估計誤差會減小。
比如k選1的話,對一個點進行分類的時候就只找到與它距離最近的1個點就行,所找到的點的類別就是這個點的類別。但在實際情況下會有噪聲點,這時k=1就很容易分錯了。如下圖所示,○是一類,×是另一類,此時放入一個△,直觀上覺得它屬於○這一類的概率大一些,但是由於噪聲的存在,如果k=1的話因爲離△最近的是一個×,這時就會把△分到×類,如果k=3的話就會把△分到○類。
另一個例子如下:
在這個例子中如果k=1或k=2的話是可以正確地把△分在○類裏面的,如果k取一個特別大的值的話△就會被錯誤地分到×中去。
3.分類決策規則
一般都是用多數表決,即離輸入實例最近的k個實例屬於哪個類別的實例數量最多那麼輸入實例就屬於哪個類別。
代碼
import numpy as np
import operator
class Knn:
def __init__(self, point, samples, labels, k):
self.point = point
self.samples = samples
self.labels = labels
self.k = k
def distance(self, lp):
"""計算要進行分類的點與樣本之間的距離(lp範數)"""
samples_len = len(self.samples)
subtract = np.tile(self.point, (samples_len, 1)) - self.samples
absolute_value = abs(subtract)
p_power = absolute_value ** lp
sum_value = p_power.sum(axis=1)
p_norm = sum_value ** (1/lp)
return p_norm
def classification(self, distances):
small_to_large_index = distances.argsort() # argsort函數返回的是數組值從小到大的索引值
class_count = {}
for i in range(self.k):
near_label = self.labels[small_to_large_index[i]]
# 統計前k箇中標籤的數目
# 也就是說最後這個字典中存的是A類的有多少個,B類的有多少個
# 字典(Dictionary) get() 函數返回指定鍵的值,如果值不在字典中返回默認值
class_count[near_label] = class_count.get(near_label, 0) + 1
# reverse=True代表逆序排列
# key=operator.itemgetter(1)定義函數key爲獲取對象的序號爲1的值,也就是比較value,如果括號裏爲0就是比較key
# sorted是個排序函數
# class_count.items()爲字典裏面的內容
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]
samples_out = [[1, 2], [3, 4], [5, 6], [7, 8]]
labels_out = ['A', 'A', 'B', 'B']
knn = Knn([0, 0], samples_out, labels_out, 3)
distance_out = knn.distance(2)
classification_result = knn.classification(distance_out)
print(classification_result)
結果爲:
A