scikit-learn K近鄰法類庫使用小結


    在K近鄰法(KNN)原理小結這篇文章,我們討論了KNN的原理和優缺點,這里我們就從實踐出發,對scikit-learn 中KNN相關的類庫使用做一個小結。主要關注於類庫調參時的一個經驗總結。

1. scikit-learn 中KNN相關的類庫概述

    在scikit-learn 中,與近鄰法這一大類相關的類庫都在sklearn.neighbors包之中。KNN分類樹的類是KNeighborsClassifier,KNN回歸樹的類是KNeighborsRegressor。除此之外,還有KNN的擴展,即限定半徑最近鄰分類樹的類RadiusNeighborsClassifier和限定半徑最近鄰回歸樹的類RadiusNeighborsRegressor, 以及最近質心分類算法NearestCentroid。

    在這些算法中,KNN分類和回歸的類參數完全一樣。限定半徑最近鄰法分類和回歸的類的主要參數也和KNN基本一樣。

    比較特別是的最近質心分類算法,由於它是直接選擇最近質心來分類,所以僅有兩個參數,距離度量和特征選擇距離閾值,比較簡單,因此后面就不再專門講述最近質心分類算法的參數。

    另外幾個在sklearn.neighbors包中但不是做分類回歸預測的類也值得關注。kneighbors_graph類返回用KNN時和每個樣本最近的K個訓練集樣本的位置。radius_neighbors_graph返回用限定半徑最近鄰法時和每個樣本在限定半徑內的訓練集樣本的位置。NearestNeighbors是個大雜燴,它即可以返回用KNN時和每個樣本最近的K個訓練集樣本的位置,也可以返回用限定半徑最近鄰法時和每個樣本最近的訓練集樣本的位置,常常用在聚類模型中。

2. K近鄰法和限定半徑最近鄰法類庫參數小結

    本節對K近鄰法和限定半徑最近鄰法類庫參數做一個總結。包括KNN分類樹的類KNeighborsClassifier,KNN回歸樹的類KNeighborsRegressor, 限定半徑最近鄰分類樹的類RadiusNeighborsClassifier和限定半徑最近鄰回歸樹的類RadiusNeighborsRegressor。這些類的重要參數基本相同,因此我們放到一起講。

參數 KNeighborsClassifier KNeighborsRegressor RadiusNeighborsClassifier RadiusNeighborsRegressor

KNN中的K值n_neighbors 

K值的選擇與樣本分布有關,一般選擇一個較小的K值,可以通過交叉驗證來選擇一個比較優的K值,默認值是5。如果數據是三維一下的,如果數據是三維或者三維以下的,可以通過可視化觀察來調參。 不適用於限定半徑最近鄰法

限定半徑最近鄰法中的半radius 

不適用於KNN 半徑的選擇與樣本分布有關,可以通過交叉驗證來選擇一個較小的半徑,盡量保證每類訓練樣本其他類別樣本的距離較遠,默認值是1.0。如果數據是三維或者三維以下的,可以通過可視化觀察來調參。

近鄰權weights 

主要用於標識每個樣本的近鄰樣本的權重,如果是KNN,就是K個近鄰樣本的權重,如果是限定半徑最近鄰,就是在距離在半徑以內的近鄰樣本的權重。可以選擇"uniform","distance" 或者自定義權重。選擇默認的"uniform",意味着所有最近鄰樣本權重都一樣,在做預測時一視同仁。如果是"distance",則權重和距離成反比例,即距離預測目標更近的近鄰具有更高的權重,這樣在預測類別或者做回歸時,更近的近鄰所占的影響因子會更加大。當然,我們也可以自定義權重,即自定義一個函數,輸入是距離值,輸出是權重值。這樣我們可以自己控制不同的距離所對應的權重。

一般來說,如果樣本的分布是比較成簇的,即各類樣本都在相對分開的簇中時,我們用默認的"uniform"就可以了,如果樣本的分布比較亂,規律不好尋找,選擇"distance"是一個比較好的選擇。如果用"distance"發現預測的效果的還是不好,可以考慮自定義距離權重來調優這個參數。

KNN和限定半徑最近鄰法使用的算法algorithm 

算法一共有三種,第一種是蠻力實現,第二種是KD樹實現,第三種是球樹實現。這三種方法在K近鄰法(KNN)原理小結中都有講述,如果不熟悉可以去復習下。對於這個參數,一共有4種可選輸入,‘brute’對應第一種蠻力實現,‘kd_tree’對應第二種KD樹實現,‘ball_tree’對應第三種的球樹實現, ‘auto’則會在上面三種算法中做權衡,選擇一個擬合最好的最優算法。需要注意的是,如果輸入樣本特征是稀疏的時候,無論我們選擇哪種算法,最后scikit-learn都會去用蠻力實現‘brute’。

個人的經驗,如果樣本少特征也少,使用默認的 ‘auto’就夠了。 如果數據量很大或者特征也很多,用"auto"建樹時間會很長,效率不高,建議選擇KD樹實現‘kd_tree’,此時如果發現‘kd_tree’速度比較慢或者已經知道樣本分布不是很均勻時,可以嘗試用‘ball_tree’。而如果輸入樣本是稀疏的,無論你選擇哪個算法最后實際運行的都是‘brute’。

停止建子樹的葉子節點閾值leaf_size

這個值控制了使用KD樹或者球樹時, 停止建子樹的葉子節點數量的閾值。這個值越小,則生成的KD樹或者球樹就越大,層數越深,建樹時間越長,反之,則生成的KD樹或者球樹會小,層數較淺,建樹時間較短。默認是30. 這個值一般依賴於樣本的數量,隨着樣本數量的增加,這個值必須要增加,否則不光建樹預測的時間長,還容易過擬合。可以通過交叉驗證來選擇一個適中的值。

如果使用的算法是蠻力實現,則這個參數可以忽略。

距離度量metric 

 K近鄰法和限定半徑最近鄰法類可以使用的距離度量較多,一般來說默認的歐式距離(即p=2的閔可夫斯基距離)就可以滿足我們的需求。可以使用的距離度量參數有:

a) 歐式距離 “euclidean”: $ \sqrt{\sum\limits_{i=1}^{n}(x_i-y_i)^2} $

b) 曼哈頓距離 “manhattan”: $ \sum\limits_{i=1}^{n}|x_i-y_i| $

c) 切比雪夫距離“chebyshev”: $ max|x_i-y_i|  (i = 1,2,...n)$

d) 閔可夫斯基距離 “minkowski”(默認參數): $ \sqrt[p]{\sum\limits_{i=1}^{n}(|x_i-y_i|)^p} $ p=1為曼哈頓距離, p=2為歐式距離。

e) 帶權重閔可夫斯基距離 “wminkowski”: $ \sqrt[p]{\sum\limits_{i=1}^{n}(w*|x_i-y_i|)^p} $ 其中w為特征權重

f) 標准化歐式距離 “seuclidean”: 即對於各特征維度做了歸一化以后的歐式距離。此時各樣本特征維度的均值為0,方差為1.

g) 馬氏距離“mahalanobis”:$\sqrt{(x-y)^TS^{-1}(x-y)}$ 其中,$S^{-1}$為樣本協方差矩陣的逆矩陣。當樣本分布獨立時, S為單位矩陣,此時馬氏距離等同於歐式距離

還有一些其他不是實數的距離度量,一般在KNN之類的算法用不上,這里也就不列了。

距離度量附屬參數p

p是使用距離度量參數 metric 附屬參數,只用於閔可夫斯基距離和帶權重閔可夫斯基距離中p值的選擇,p=1為曼哈頓距離, p=2為歐式距離。默認為2

距離度量其他附屬參數metric_params

 一般都用不上,主要是用於帶權重閔可夫斯基距離的權重,以及其他一些比較復雜的距離度量的參數。

並行處理任務數n_jobs

主要用於多核CPU時的並行處理,加快建立KNN樹和預測搜索的速度。一般用默認的-1就可以了,即所有的CPU核都參與計算。   不適用於限定半徑最近鄰法
異常點類別選擇outlier_label 不適用於KNN  主要用於預測時,如果目標點半徑內沒有任何訓練集的樣本點時,應該標記的類別,不建議選擇默認值 none,因為這樣遇到異常點會報錯。一般設置為訓練集里最多樣本的類別。   不適用於限定半徑最近鄰回歸

 

3. 使用KNeighborsClassifier做分類的實例

    完整代碼見我的github: https://github.com/ljpzzz/machinelearning/blob/master/classic-machine-learning/knn_classifier.ipynb

3.1 生成隨機數據

    首先,我們生成我們分類的數據,代碼如下:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets.samples_generator import make_classification
# X為樣本特征,Y為樣本類別輸出, 共1000個樣本,每個樣本2個特征,輸出有3個類別,沒有冗余特征,每個類別一個簇
X, Y = make_classification(n_samples=1000, n_features=2, n_redundant=0,
                             n_clusters_per_class=1, n_classes=3)
plt.scatter(X[:, 0], X[:, 1], marker='o', c=Y)
plt.show()

    先看看我們生成的數據圖如下。由於是隨機生成,如果你也跑這段代碼,生成的隨機數據分布會不一樣。下面是我某次跑出的原始數據圖。

    接着我們用KNN來擬合模型,我們選擇K=15,權重為距離遠近。代碼如下:

from sklearn import neighbors
clf = neighbors.KNeighborsClassifier(n_neighbors = 15 , weights='distance')
clf.fit(X, Y)

    最后,我們可視化一下看看我們預測的效果如何,代碼如下:

from matplotlib.colors import ListedColormap
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

#確認訓練集的邊界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
#生成隨機數據來做測試集,然后作預測
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                         np.arange(y_min, y_max, 0.02))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

# 畫出測試集數據
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

# 也畫出所有的訓練集數據
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=cmap_bold)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("3-Class classification (k = 15, weights = 'distance')" )

    生成的圖如下,可以看到大多數數據擬合不錯,僅有少量的異常點不在范圍內。

    以上就是使用scikit-learn的KNN相關類庫的一個總結,希望可以幫到朋友們。

 

(歡迎轉載,轉載請注明出處。歡迎溝通交流: liujianping-ok@163.com) 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM