机器学习:k近邻算法(KNN)介绍
k近鄰算法是一種最簡(jiǎn)單最經(jīng)典的機(jī)器學(xué)習(xí)算法之一。該算法的原理為:當(dāng)對(duì)測(cè)試樣本進(jìn)行分類時(shí),首先通過(guò)掃描訓(xùn)練樣本集,找到與該測(cè)試樣本最相似的k個(gè)訓(xùn)練樣本,根據(jù)這個(gè)樣本的類別進(jìn)行投票確定測(cè)試樣本的類別。也可以通過(guò)個(gè)樣本與測(cè)試樣本的相似程度進(jìn)行加權(quán)投票。如果需要以測(cè)試樣本對(duì)應(yīng)每類的概率的形式輸出,可以通過(guò)個(gè)樣本中不同類別的樣本數(shù)量分布來(lái)進(jìn)行估計(jì)。
以下通過(guò)一個(gè)例子了解k近鄰算法。
?利用k近鄰算法確認(rèn)紫圓為哪個(gè)類別。若k=1,則找到離圖中紫圓最近的1個(gè)樣本,這個(gè)樣本為紅色正方形,故紫圓屬于紅色正方形類別;若k=7,則找到離紫圓最近的7個(gè)樣本,這7個(gè)樣本中有5個(gè)綠色三角形和兩個(gè)紅色正方形,其中類數(shù)三角形數(shù)量比紅色正方形多,故紫圓屬于綠色三角形。由以上例子可知k近鄰算法對(duì)樣本的分類及其依賴于k的取值。
?當(dāng)然k近鄰算法對(duì)距離的計(jì)算方式有多種,其中以Manhattan 距離與Euclidean 距離為主。
我們一般采用Euclidean 距離。
?
在上述介紹中我們得知k近鄰算法對(duì)樣本的分類及其依賴于k的取值。k值不可取過(guò)大或過(guò)小。
- k值越大,模型的偏差越大,對(duì)噪聲數(shù)據(jù)越不敏感,當(dāng)k值很大時(shí),可能造成欠擬合;
- k值越小,模型的方差就會(huì)越大,當(dāng)k值太小,就會(huì)造成過(guò)擬合。?
以下為k值取值過(guò)大或過(guò)小時(shí)的例子。
?如圖當(dāng)k=1時(shí)在圖中紫色圖層中夾雜了參差不齊的綠色圖層,該訓(xùn)練結(jié)果并非很好的劃分了紅綠紫三個(gè)區(qū)域,造成了過(guò)擬合現(xiàn)象。
如圖當(dāng)k=150時(shí)由于無(wú)論取圖上哪個(gè)點(diǎn)都是紫色點(diǎn)投票最多,故該點(diǎn)必被分類為紫色一類,造成了欠擬合現(xiàn)象。
因此k的取值因滿足以下兩個(gè)條件:
1.近鄰點(diǎn)要有相同/相近的類別
2.特征維度的尺度(范圍)要具備一致性
接下來(lái)看一例子:
?如上圖,若我們用傳統(tǒng)的Euclidean 距離作為k近鄰算法判斷距離的標(biāo)準(zhǔn),我們會(huì)驚訝的發(fā)現(xiàn)每年獲得的飛行??屠锍虜?shù)將占到距離的絕大部分比重,也就是說(shuō)樣本的分類基本上只與每年獲得的飛行??屠锍虜?shù)相關(guān)聯(lián)了。所以我們要進(jìn)行數(shù)值歸一化的處理,使得上圖中三個(gè)特征的權(quán)重相等。
數(shù)據(jù)歸一化的處理方法有很多種,比如0-1標(biāo)準(zhǔn)化、Z-score標(biāo)準(zhǔn)化、Sigmoid壓縮法等等,在這里我們使用最簡(jiǎn)單的0-1標(biāo)準(zhǔn)化,公式如下:?
?
?接下來(lái)調(diào)用鳶尾花Iris數(shù)據(jù)集,利用k近鄰算法訓(xùn)練該數(shù)據(jù)集并評(píng)估模型準(zhǔn)確率。
1.鳶尾花Iris數(shù)據(jù)集介紹
· Iris (/?a?r?s/) 數(shù)據(jù)集是機(jī)器學(xué)習(xí)任務(wù)中常用的分類實(shí)驗(yàn)數(shù)據(jù)集,由Fisher在1936年整理。
· Iris :Anderson’s Iris data set, 中文名稱:安德森鳶尾花數(shù)據(jù)集
· Iris 數(shù)據(jù)集一共包含150個(gè)樣本,分3類,每類50個(gè)數(shù)據(jù),每個(gè)數(shù)據(jù)包含4個(gè)特征。4個(gè)特征分別為: Sepal.Length(花萼長(zhǎng)度)、Sepal.Width(花萼寬度)、Petal.Length(花瓣長(zhǎng)度)、Petal.Width(花瓣寬度),特征值都為正浮點(diǎn)數(shù),單位為厘米。根據(jù)4個(gè)特征預(yù)測(cè)鳶尾花屬于 Iris Setosa(山鳶尾)、Iris Versicolour(雜色鳶尾),Iris Virginica(維吉尼亞鳶尾)
數(shù)據(jù)集結(jié)構(gòu)與數(shù)據(jù)大致如下:
?
?其中前部分為特征: Sepal.Length(花萼長(zhǎng)度)、Sepal.Width(花萼寬度)、Petal.Length(花瓣長(zhǎng)度)、Petal.Width(花瓣寬度)后部分為標(biāo)簽:Iris Setosa(山鳶尾)、Iris Versicolour(雜色鳶尾),Iris Virginica(維吉尼亞鳶尾)(分別利用0,1,2代替原有標(biāo)簽名)。
2.sklearn中 neighbors.KNeighborsClassifier參數(shù)說(shuō)明
在sklearn庫(kù)中,KNeighborsClassifier是實(shí)現(xiàn)K近鄰算法的一個(gè)類,一般都使用歐式距離進(jìn)行測(cè)量。
KNeighborsClassifier(n_neighbors=5,weights=’uniform’,algorithm=’auto’,leaf_size=30,p=2,metric=’minkowski’,metric_params=None,n_jobs=1,**kwargs)
n_neighbors: int, 可選參數(shù)(默認(rèn)為 5)用于kneighbors查詢的默認(rèn)鄰居的數(shù)量;
weights(權(quán)重): str or callable(自定義類型), 可選參數(shù)(默認(rèn)為 ‘uniform’)用于預(yù)測(cè)的權(quán)重函數(shù);
algorithm(算法): {‘a(chǎn)uto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可選參數(shù)(默認(rèn)為 ‘a(chǎn)uto’)計(jì)算最近鄰居用的算法;
leaf_size(葉子數(shù)量): int, 可選參數(shù)(默認(rèn)為 30),傳入BallTree或者KDTree算法的葉子數(shù)量;
p: integer, 可選參數(shù)(默認(rèn)為 2)用于Minkowski metric(閔可夫斯基空間)的超參數(shù)。p = 1, 相當(dāng)于使用曼哈頓距離 (l1),p = 2, 相當(dāng)于使用歐幾里得距離(l2);
metric(矩陣): string or callable, 默認(rèn)為 ‘minkowski’用于樹(shù)的距離矩陣。默認(rèn)為閔可夫斯基空間,如果和p=2一塊使用相當(dāng)于使用標(biāo)準(zhǔn)歐幾里得矩陣;
metric_params(矩陣參數(shù)): dict, 可選參數(shù)(默認(rèn)為 None),給矩陣方法使用的其他的關(guān)鍵詞參數(shù);
n_jobs: int, 可選參數(shù)(默認(rèn)為 1)用于搜索鄰居的,可并行運(yùn)行的任務(wù)數(shù)量。如果為-1, 任務(wù)數(shù)量設(shè)置為CPU核的數(shù)量。不會(huì)影響fit方法.
- 方法:
?
3.?編寫(xiě)代碼,實(shí)現(xiàn)對(duì)iris數(shù)據(jù)集的k近鄰算法分類及預(yù)測(cè)
一:引入庫(kù)
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier import numpy as np二:加載數(shù)據(jù)集,定義區(qū)分特征與標(biāo)記
iris = load_iris() #date為特征數(shù)據(jù)集 data = iris.get("data") #target為標(biāo)記數(shù)據(jù)集 target = iris.get("target")三:劃分測(cè)試集與訓(xùn)練集
#劃分測(cè)試集占20% x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0)四:定義k值
#定義k值 KNN = KNeighborsClassifier(n_neighbors=5)五:評(píng)價(jià)模型的準(zhǔn)確率
test_score = KNN.score(x_test, y_test) print("模型的準(zhǔn)確率:", test_score)
六:使用模型預(yù)測(cè)未知種類樣本
#定義三個(gè)測(cè)試數(shù)據(jù)
X1 = np.array([[1.9, 2.8, 4.7, 1.1], [5.8, 2.7, 4.1, 1.5], [3.6, 2.5, 3.1, 2.1]])
prediction = KNN.predict(X1)
#根據(jù)預(yù)測(cè)值找出對(duì)應(yīng)花名
a = iris.get("target_names")[prediction]
print("第一朵花的種類為:", a[0])
print("第二朵花的種類為:", a[1])
print("第三朵花的種類為:", a[2])
?完整代碼
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier import numpy as np if __name__ == '__main__':iris = load_iris()#date為特征數(shù)據(jù)集data = iris.get("data")#target為標(biāo)記數(shù)據(jù)集target = iris.get("target")#劃分測(cè)試集占20%x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0)#定義k值KNN = KNeighborsClassifier(n_neighbors=5)KNN.fit(x_train, y_train)train_score = KNN.score(x_train, y_train)test_score = KNN.score(x_test, y_test)print("模型的準(zhǔn)確率:", test_score)#定義三個(gè)測(cè)試數(shù)據(jù)X1 = np.array([[1.9, 2.8, 4.7, 1.1], [5.8, 2.7, 4.1, 1.5], [3.6, 2.5, 3.1, 2.1]])prediction = KNN.predict(X1)#根據(jù)預(yù)測(cè)值找出對(duì)應(yīng)花名a = iris.get("target_names")[prediction]print("第一朵花的種類為:", a[0])print("第二朵花的種類為:", a[1])print("第三朵花的種類為:", a[2])結(jié)果
?接下來(lái)改變k值觀察模型準(zhǔn)確率。
當(dāng)k=100時(shí):
當(dāng) k=50時(shí):
當(dāng)k=120時(shí):
?
可以看出當(dāng)k值越來(lái)越高至接近樣本總數(shù)150時(shí)它的準(zhǔn)確率越來(lái)越低,這吻合了上文介紹的k值過(guò)大造成的欠擬合現(xiàn)象。?
?k近鄰算法優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1.?簡(jiǎn)單有效
2.重新訓(xùn)練的代價(jià)低(沒(méi)有構(gòu)建模型)
3.適合類域交叉樣本:KNN方法主要靠周?chē)邢薜泥徑臉颖?而不是靠判別類域的方法來(lái)確定所屬類別的,因此對(duì)于類域的交叉或重疊較多的待分樣本集來(lái)說(shuō),KNN方法較其他方法更為適合。
4.適合大樣本自動(dòng)分類:該算法比較適用于樣本容量比較大的類域的自動(dòng)分類,而那些樣本容量較小的類域采用這種算法比較容易產(chǎn)生誤分。
?
缺點(diǎn):
1.惰性學(xué)習(xí):KNN算法是懶散學(xué)習(xí)方法(lazy learning,基本上不學(xué)習(xí)),一些積極學(xué)習(xí)的算法要快很多
2.類別評(píng)分不是規(guī)格化:不像一些通過(guò)概率評(píng)分的分類
3.輸出可解釋性不強(qiáng):例如決策樹(shù)的輸出可解釋性就較強(qiáng)
4.對(duì)不均衡的樣本不擅長(zhǎng):當(dāng)樣本不平衡時(shí),如一個(gè)類的樣本容量很大,而其他類樣本容量很小時(shí),有可能導(dǎo)致當(dāng)輸入一個(gè)新樣本時(shí),該樣本的K個(gè)鄰居中大容量類的樣本占多數(shù)。該算法只計(jì)算“最近的”鄰居樣本,某一類的樣本數(shù)量很大,那么或者這類樣本并不接近目標(biāo)樣本,或者這類樣本很靠近目標(biāo)樣本。無(wú)論怎樣,數(shù)量并不能影響運(yùn)行結(jié)果。可以采用權(quán)值的方法(和該樣本距離小的鄰居權(quán)值大)來(lái)改進(jìn)。
5.計(jì)算量較大:目前常用的解決方法是事先對(duì)已知樣本點(diǎn)進(jìn)行剪輯,事先去除對(duì)分類作用不大的樣本。
總結(jié)
以上是生活随笔為你收集整理的机器学习:k近邻算法(KNN)介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux != Windows( Li
- 下一篇: BUUCTF Misc 隐藏的钥匙