動手實現簡單的KNN python

2021-08-26 09:33:36 字數 3193 閱讀 8999

先舉乙個可能不是很恰當的例子:「近朱者赤近墨者黑」,想象一下,假如你是乙個女孩紙,新認識乙個男性朋友,如果你了解到他周圍的朋友大部分是性格開朗,陽關帥氣的,你潛意識會覺得這個大概也是這樣的人,那如果他周圍大部分是那些「臭名昭著」,名聲不是很好的朋友,你潛意識的會覺得,emmmmm這個人可能不是很靠譜,有待考量…這麼說來你的潛意識就是乙個典型的knn分類器。(hhhh,扯得有點遠,朋友用心交,情誼比天高,祝各位開心!)

讓我們回歸正題,knn(k-nearestneighbor)也可以叫做k-近鄰,首先它屬於有監督學習,將**集的每個特徵與樣本集對應的特徵進行比較,然後演算法提取「若干個」樣本集中特徵最相似資料(最近鄰)的分類標籤,其中出現次數最多的標籤即作為最終**的結果。上述描述中的「若干個」就是我們knn中的「k」要定義的事情,至於如何取值我會在後續的部落格中說明,現在我們只需要知道k是我們根據經驗取得的正整數值,一般不大於20。那如何對對應的特徵進行比較呢?這就是我們knn中「neighbor」要做的事了,這裡用的是一種距離公式------歐氏距離

當然還可以推廣到閔可夫斯基距離(了解即可,本文用的歐式距離)

我們可以看到閔可夫斯基距離公式中,當p=2時,即為歐氏距離;當p=1時,即為曼哈頓距離;當p趨於無窮時,即為切比雪夫距離。

優點:精度高,對異常值不敏感,無資料輸入假定

缺點:計算複雜度高、空間複雜度高

適用資料範圍:數值型

knn(k-nearestneighbor):

1.計算已知類別資料集中的點與帶**點之間的距離(歐氏距離)(neighbor)

2.按照距離遞增次序排序

3.選取當前距離最小的k個點(k)

4.確定前k個點所在類別的出現頻率

5.返回前k個點出現頻率最高的類別作為當前待**點的分類(nearest)

在了解knn的基本思想和步驟之後,我們話不多說,直接擼**!

def knn_classifier(x_in, x_train, y_train, k):

# 使用歐氏距離公式求距離

distances = [(np.sum((x_train - x_in)**2))**0.5

for x_train in x_train]

#取最近的k個距離,argsort函式拿到前k個值的下標,對應到y_train中,將對應的標籤存到topk_y中

nearest = np.argsort(distances)

topk_y = [y_train[neighbor] for neighbor in nearest[:k]]

# 選出前k個標籤中票數最多的乙個標籤作為最終的**值

votes = counter(topk_y)

predict_y = votes.most_common(1)[0][0]

return predict_y

x_in:待**的資料集;x_train:訓練資料集;y_train:訓練資料對應的標籤;k:根據經驗取乙個正整數

隨後我們取一些資料來測試一下我們寫的knn分類器:

data:[ [3.393533211, 2.331273381], [3.110073483, 1.781539638],[1.343808831, 3.368360954],[3.582294042,4.679179110],[2.280362439, 2.866990263],[7.423436942, 4.696522875],[5.745051997, 3.533989803],[9.172168622, 2.511101045],[7.792783481, 3.424088941],[7.939820817, 0.791637231] ]

label:[0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

predict:[8.093607318, 3.365731514]

我們先來分析下資料,這樣光看這些數字好像並沒有什麼概念,不妨試試將上述資料繪製成散點圖:

這樣子一看就清晰了很多,直觀上好像我們的待**點(綠點)離標籤為1(藍點)的資料更近些,那我們就可以猜測該點的標籤大概率也是『1』。接下來呼叫一下我們之前寫好knn分類器來驗證一下:

predict_y = knn.knn_classifier(x, x_train, y_train, 6)

print(predict_y)

最終的**結果為『1』:

1.實驗資料:為了方便最初理解knn,並簡單實現資料視覺化,所以上述data格式非常簡單,只有兩個特徵,在實際應用場景中data維度可能非常龐大,具有很多個特徵;待**的資料量也可能非常龐大,當然同時也會增加knn的計算量,這也是knn的乙個不可避免的缺點。

2.引數設定:開篇提到k是由經驗取得的乙個正整數,那麼問題來了,我就是乙個機器學習小白,沒有什麼經驗,你讓我設定k的值,我一臉懵*,到底該如何設定k的值?然後再試想一下,會不會有這樣的情況:

按照knn來說,當k=3時,綠點應該判定為藍點的類,但是我們從視覺化的資料中能看到綠點離紅點更近些,理應判定為紅點的類,這個時候距離的權重該如何取捨呢 ?

3.實驗結果:我們寫的knn分類將待**的資料類別**出來了,但如何知道**的結果是否可信呢,這就涉及到在訓練資料時要有個較高的準確率,這樣才能使得我們**的結果可信度高!

綜上,這些就是我下篇部落格要解決的問題請參照:knn優化之調參

動手實現簡單的執行緒池

廢話不多說,直接開始。一 屬性變數 執行緒的屬性變數如下 執行緒池是否關閉 private boolean isclosed false 任務佇列 private linkedlistworkqueue 執行緒池id private static int threadpoolid 執行緒id pri...

自己動手簡單實現CountDownLatch

在使用執行緒池的過程中,如何判斷所有提交的任務都已經執行完畢了呢?使用jdk自帶的countdownlatch,可以輕鬆實現這一需求 public class countdownlatchtest catch interruptedexception e executorservice.shutdo...

自己動手實現乙個簡單的React

為了更好的理解react,我決定讀preact的原始碼,preact是乙個非常小的框架,同時也和react的實現原理以及api一樣,幾乎可以很好代替react。雖然還是有一些差異的。但是使用的時候幾乎不會有什麼違和感。看原始碼總是不夠過癮,於是做了乙個偉大的決定就是自己親手去寫乙個react,畢竟p...