機器學習~KNN算法

概述

KNN鄰近算法,或者說K最近鄰(kNN,k-NearestNeighbor)分類算法是數據挖掘分類技術中最簡單的方法之一。所謂K最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。
它是一個有監督的機器學習算法,但是卻沒有訓練過程,屬於懶惰學習(lazy learning),即數據集事先已經有了分類和特徵值,待收到新樣本後直接進行處理。

原理

借用百度百科的KNN圖來解釋:需要判斷X是什麼顏色的,於是找到X的5個最近的鄰居,發現4個都是紅的,1個是綠的,所以我們判斷X是紅色的。
在這裏插入圖片描述
即對於給定測試樣本,基於距離度量找出訓練集中最靠近測試樣本的K個訓練樣本,然後基於這K個“鄰居”的信息來進行預測。
在分類任務中可使用投票法,選擇這K個樣本中出現最多的類別標記作爲預測結果。

算法描述

1)計算測試數據與各個訓練數據之間的距離;
2)按照距離的遞增關係進行排序;
3)選取距離最小的K個點;
4)確定前K個點所在類別的出現頻率;
5)返回前K個點中出現頻率最高的類別作爲測試數據的預測分類。

實踐

Python實現KNN算法
首先準備一組數據

import matplotlib.pyplot as plt
import numpy as np
"""初始化訓練集:raw_data_X爲特徵,raw_data_y爲標籤"""
raw_data_X = [[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]]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

"""將數據可視化"""
X_train = np.array(raw_data_X)
y_train = np.array(raw_data_y)
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1])
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1])
plt.xlabel('Tumor Size')
plt.ylabel('Time')
plt.show()

數據可視化後生成的圖片如下圖所示。其中橫軸是腫塊大小,縱軸是發現時間。每個病人的腫塊大小和發病時間構成了二維平面特徵中的一個點。對於每個點,我們通過label明確是惡性腫瘤(橙色)、良性腫瘤(藍色)。
在這裏插入圖片描述
現在有測試樣本:x[8.90933607318, 3.365731514],需要判斷是良性腫瘤還是惡性腫瘤。

我們可以先將測試樣本加入上圖中

plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1])
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1])
plt.scatter(x[0],x[1])
plt.show()

從下圖可以看出,綠色的測試樣本,距離橙色(惡性腫瘤)更近,所以可以推測測試樣本是惡性腫瘤。
在這裏插入圖片描述

下來我們再用代碼來推測一下:

根據KNN算法的流程,我們需要計算該測試樣本距離每個點的距離,兩點之間的距離公式採用歐式距離:
在這裏插入圖片描述
此處,取n等於2。

from math import sqrt
distances = []
for x_train in X_train:
    d = sqrt(np.sum((x_train-x)**2))
    distances.append(d)

此處還Get了另外一種簡潔寫法

distances = [sqrt(np.sum((x_train - x)**2)) for x_train in X_train]
distances
輸出: 
[4.812566907609877,
5.229270827235305,
6.749798999160064,
4.6986266144110695,
5.83460014556857,
1.4900114024329525,
2.354574897431513,
1.3761132675144652,
0.3064319992975,
2.5786840957478887]

求出距離後,根據流程,需要將其按照從小到大排序

#np.argsort 函數排序返回排序結果的索引
nearest = np.argsort(distances)
nearest
#輸出:array([8, 7, 5, 6, 9, 3, 0, 1, 4, 2], dtype=int64)

選擇K值,暫時選定6個點,並記錄他們的標籤值

k = 6
topK_y = [y_train[i] for i in nearest[:k]]
topK_y
#輸出: [1, 1, 1, 1, 1, 0]

接下來投票選擇,找到與測試樣本點最近的6個訓練樣本點的標籤y是什麼。可以查不同類別的點有多少個。

from collections import Counter
votes = Counter(topK_y)
#結果:Counter({1: 5, 0: 1}),統計每個類別出現的次數,1出現了5次,0出現了1次

predict_y = votes.most_common(1)[0][0]
#函數most_common(n) 找出票數最多的n個元素,most_common(1)返回: [(1, 5)]

predict_y
#輸出預測值:1

所以我們對X的預測結果是1,即惡性腫瘤

Sk-learn中調用KNN算法

機器學習的一般流程爲:

擬合fit
預測predict
輸入訓練集
機器學習算法
模型
輸出結果
輸入樣例

首先讓機器學習算法學習我們的訓練集,生成模型,然後輸入我們想要預測的值,根據模型會得到結果。我們後面可以看到Sk-learn中算法都是基於這個流程。

由於KNN算法並沒有訓練過程,所以爲了統一,我們可以認爲訓練集就是模型本身。
我們可以使用sk-learn中的調用方法,會發現其實KNN算法很簡單。

from sklearn.neighbors import KNeighborsClassifier
#指定K值
kNN_classifier = KNeighborsClassifier(n_neighbors = 6)
#數據擬合算法生成模型
kNN_classifier.fit(X_train,y_train)
#輸出模型對象:KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',metric_params=None, n_jobs=1, n_neighbors=6, p=2,weights='uniform')
#將一維數組變爲二維矩陣,批量預測
X_predict = x.reshape(1,-1)
#預測值
y_predict = kNN_classifier.predict(X_predict)
y_predict[0]
#輸出預測值:1

參考

餅乾大神的KNN入門教程
波波老師的慕課網視頻

最後再次感謝木東居士大神組織機器學習小組!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章