簡介
在所有機器學習算法中,k近鄰(K-Nearest Neighbors,KNN)相對是比較簡單的。 盡管它很簡單,但事實證明它在某些任務中非常有效,甚至更好。它可以用於分類和回歸問題! 然而,它更常用於分類問題。 在本文中,我們將首先了解KNN算法背后的原理,研究計算點之間距離的不同方法,然后最終用Python實現該算法。
目錄
- 一個簡單的例子來理解KNN背后的原理
- KNN算法如何工作
- 計算點之間距離的方法
- 如何選擇k因子
- KNN聚類實例(python)
1.一個簡單的例子來理解KNN背后的原理
讓我們從一個簡單的例子開始。請考慮下圖,,我們有兩類數據,分別是藍色方塊和紅色三角形,他們分布在一個上圖的二維中間中。那么假如我們有一個綠色圓圈這個數據,需要判斷這個數據是屬於藍色方塊這一類,還是與紅色三角形同類呢?
我們先把離這個綠色圓圈最近的幾個點找到,根據相似性,離綠色圓圈最近的才對它的類別有判斷的幫助。那到底要用多少個來判斷呢?這個個數就是k了。
- 如果k=3,就表示我們選擇離綠色圓圈最近的3個點來判斷,由於紅色三角形所占比例為2/3,所以我們認為綠色圓是和紅色三角形同類。
- 如果k=5,由於藍色四方形比例為3/5,因此綠色圓被賦予藍色四方形類。
它的思想很簡單:如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。
2.KNN算法如何工作
算法流程:
- 計算已知類別數據集中的點與當前點之間的距離;
- 按照距離遞增次序排序;
- 選取與當前點距離最小的k個點;
- 確定前k個點所在類別的出現頻率;
- 返回前k個點出現頻率最高的類別作為當前點的預測分類
3.計算點之間距離的方法
第一步是計算新點和每個訓練點之間的距離。 有多種計算這種距離的方法,其中最常見的方法是 - 歐幾里德,曼哈頓(對連續變量)和漢明距離(對分類變量)。
- 歐幾里德距離:歐幾里德距離計算為新點(x)和現有點(y)之間的平方差之和的平方根。
- 曼哈頓距離:這是實際向量之間的距離,使用它們的絕對差值之和。
- 漢明距離:用於分類變量。 如果值(x)和值(y)相同,則距離D將等於0。 否則D = 1。
一旦測量了新觀測距離訓練集中各點的距離,下一步就是選擇最近的點。 要考慮的點數由k的值定義。
4.如何選擇k因子
首先讓我們試着了解K在算法中的確切影響。 如果我們看到最后一個例子,假設所有訓練觀察值保持不變,給定K值我們可以為每個類創建邊界。 這些邊界將兩個別別分開。 讓我們試着看看“K”值對類邊界的影響。 以下是用不同的K值分隔兩個類的不同邊界:
仔細觀察,可以發現:隨着K值的增加,邊界變得更加平滑。隨着K增加到無窮大,它最終變成全藍色或全紅色。我們可以根據我們的訓練和驗證集的誤差計算來決定它(畢竟,我們的最終目標是最小化誤差)。
以下是具有不同k值的訓練誤差和驗證誤差:
對於非常低的k值(假設k = 1),模型過度擬合訓練數據,這導致驗證集上的高錯誤率。 另一方面,對於較大的k值,該模型在訓練和驗證集上都表現不佳。 如果仔細觀察,會發現驗證誤差曲線在k = 9的值處達到最小值。該k值是模型的最佳值(對於不同的數據集,它將有所不同)。 該曲線稱為“肘形曲線”,通常用於確定k值。
我們還可以使用網格搜索技術來查找最佳k值。 我們將在下一節中實現這一點。
5.KNN聚類實例
可以在這里下載數據集。
1.導入數據:
import numpy as np import pandas as pd import matplotlib.pyplot as plt
#查看數據 data.head()
2.變量的處理
由於類別變量為非數值型,我們需要進行處理。
name_list=data['Name'].unique() for i in name_list: data.loc[data['Name']==i,'Name']=list(name_list).index(i)+1 data.head()
3.分割訓練集和測試集
我們可以把數據70%用於訓練,30%用於測試。
#create trainset and testset from sklearn.model_selection import train_test_split train , test = train_test_split(data, test_size = 0.3) x_train = train.drop('Name', axis=1) y_train = train['Name'] x_test = test.drop('Name', axis = 1) y_test = test['Name']
4.預處理 - 縮放功能
我們需要對數據進行歸一化處理,即均值為0,方差為1。
好處:消除特征之間量級不同導致的影響。
#Preprocessing – Scaling the features from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler(feature_range=(0, 1)) x_train_scaled = scaler.fit_transform(x_train) x_train = pd.DataFrame(x_train_scaled) x_test_scaled = scaler.fit_transform(x_test) x_test = pd.DataFrame(x_test_scaled)
5.查看不同k值下的分類錯誤率
我們用均方誤差的平方根來衡量。
#import required packages from sklearn import neighbors from sklearn.metrics import mean_squared_error from math import sqrt rmse_val = [] #to store rmse values for different k for K in range(20): K = K+1 model = neighbors.KNeighborsRegressor(n_neighbors = K) model.fit(x_train, y_train) #fit the model pred=model.predict(x_test) #make prediction on test set error = sqrt(mean_squared_error(y_test,pred)) #calculate rmse rmse_val.append(error) #store rmse values print('RMSE value for k= ' , K , 'is:', error)
畫出分類錯誤曲線:
#plotting the rmse values against k values curve = pd.DataFrame(rmse_val) #elbow curve curve.plot()
正如我們所討論的,當我們取k = 1時,我們得到一個非常高的RMSE值。 隨着我們增加k值,RMSE值減小。 在k = 7時,RMSE約為0.2266,並且在進一步增加k值時上升。 在這種情況下,我們可以判斷,k = 7會給我們帶來最好的結果。
這些是使用我們的訓練數據集的預測。 現在讓我們預測測試數據集的值。
6.應用Gridsearch
為了確定k的值,每次繪制‘”肘曲線”是一個麻煩且繁瑣的過程。 您只需使用gridsearch即可找到最佳值。
from sklearn.model_selection import GridSearchCV params = {'n_neighbors':[2,3,4,5,6,7,8,9]} knn = neighbors.KNeighborsRegressor() model = GridSearchCV(knn, params, cv=5) model.fit(x_train,y_train) model.best_params_
可以看出,k=4確實是最佳選擇。
小結
KNN算法是最簡單的分類算法之一。 即使如此簡單,它也可以提供極具競爭力的結果。 KNN算法也可用於回歸問題。 與討論的方法的唯一區別將是使用最近鄰居的平均值而不是從最近鄰居投票。
優點
- 簡單好用,容易理解,既可以用來做分類也可以用來做回歸;
- 可用於數值型數據和離散型數據;
- 訓練時間復雜度為O(n);無數據輸入假定;
- 對異常值不敏感。
缺點:
- 計算復雜性高;空間復雜性高;
- 樣本不平衡問題(即有些類別的樣本數量很多,而其它樣本的數量很少);
- 一般數值很大的時候不用這個,計算量太大。但是單個樣本又不能太少,否則容易發生誤分。
- 最大的缺點是無法給出數據的內在含義。
以上對KNN的簡單總結與應用,希望對您有所幫助!