【機器學習】K近鄰演算法
Knn演算法是一種簡單的監督學習演算法,雖然效能並不算非常出色,但是可解釋性非常強。理論上可以證明,Knn可以以任意精度擬合真實分類高維曲面。
一、Knn演算法分析
1、該演算法在處理樣本分佈不均勻的時候效果比較差。比如正類的樣本數量為1000,反類的樣本數量為100,即正反兩類的比例懸殊,當測試一個數據樣本的時候,很有可能它雖然在距離上靠近反類,但是由於相鄰的樣本反類太少,正類太多,導致預測不準確。解決這個問題的方法就是根據K近鄰得到的結果,每個類的數量分別再除以各自在訓練集中的樣本個數,這樣將各類樣本均衡化,效果更準確。
2、該演算法在處理稀疏資料時,效果很差,儘管這是一種懶惰學習演算法,但是仍然需要大量的,等密度分佈的資料。
3、在預測時,除了將類別均衡化之外,還需要密度均衡化,也就是說,希望所有的樣本點在屬性空間上的分佈非常均勻,這樣預測的結果就準確。密度分佈可以用K近鄰的半徑來衡量。即測試樣本和第k個樣本之間的距離的倒數定義為當前空間的樣本密度,如果密度比較大,則預測結果準確,如果密度小,那麼資料稀疏,預測的結果就不一定可靠。所以需要以概率來判定。
4、由於是懶惰學習,所以在做增量學習的時候,給每個新增樣本都做概率預測,預測更加新的進來的樣本的時候,也採用概率預測,會是更精確的做法。這種懶惰學習造成的結果就是只能找到區域性最小點,而很難找到全域性最小點。
5、KNN的處理一定是有一個分類邊界的,這個邊界可能不是特別具體,但是也不會大過KNN確定的判定超圓的直徑。也就是說,隨著資料越來越稠密,假設達到了絕對稠密,在一個樣本的極其微小的鄰域內找到了K個樣本,並判定成功樣本的分類,此時,鄰域幾乎不可見,在屬性空間上進行巨集觀觀察,每個分類都以一個超曲面將資料精準分割開來。資料之間沒有絲毫雜糅,這就是KNN的不準確性。
二、程式碼
該演算法並不算難,自己寫一個也不成問題。但是由於懶,且已經完全明白了該演算法的原理,所以就不想寫了。直接呼叫sklearn包。
KNeighborsClassifier()進行引數解釋。
(1)n_neighbors : 整數,預設取5。K近鄰的K值。
(2)weights : 字串格式或者自定義,預設是'uniform'。也就是每個屬性的權值分配。
- 'uniform' : 均勻分佈,即每個屬性具有的權重一致。
- 'distance' : 也就是說,距離樣本越近的樣本點對樣本的分類影響越大。
- [callable] : 使用者自定義函式,該函式的輸入是一列距離值,輸出是每個距離對應的權重值。
(3)algorithm : 取值包括'auto', 'ball_tree', 'kd_tree', 'brute'。指選擇哪種演算法來計算。
- 'ball_tree' 使用類class:`BallTree`
- 'kd_tree' 使用類class:`KDTree`
- 'brute' 使用brute-force search,在稀疏資料時使用該種方法
- 'auto' 自適應選擇一種最合適的。
(4)leaf_size : 整數,預設30。在使用BallTree 或 KDTree方法時,傳給演算法的葉子節點的數量,預設30個。具體這是什麼演算法,我也不清楚,沒有查詢資料。
(5)p : 整數,預設值是2。指選擇哪種距離度量,泛化來說,所有的向量距離都是Minkowski距離,p = 1時,稱為manhattan距離,p = 2時,稱為euclidean_distance。也可以使用其他的距離。
(6)metric : 字串型別,定義了使用什麼距離,預設是'minkowski'。DistanceMetric 類中定義各種可以使用的距離。
(7)metric_params : 如果選擇了某個metric,用dict來給對應的距離種類新增引數。一般不用。
(8)n_jobs : 整數,指的是計算機執行的作業數。一個cpu在一個時刻只能執行一個job作業。如果引數選擇為-1,那麼計算機中所有的CPU都參與了該演算法的訓練。如果取1,即只有1個CPU在執行,也就是單程序,並且Python直譯器是單執行緒的,也就是說單執行緒執行。如果引數小於-1,那麼(計算機中CPU的個數+1+n_jobs)即是計算機中執行的作業數。比如我的計算機是4核的,引數取值為-2,此時有3個CPU參與了此次訓練。
from sklearn.cluster import KMeans from sklearn import neighbors from sklearn import datasets import numpy as np import pylab as pl knn = neighbors.KNeighborsClassifier() iris = datasets.load_iris() knn.fit(iris.data, iris.target) predictedLabel = knn.predict([[0.1,0.2,0.3,0.4]]) print predictedLabel pl.scatter(iris.data[:, 1], # 樣本集的 x 軸資料 iris.data[:, 3], # 樣本集的 y 軸資料 c=iris.target, # 分類結果集 s=80, cmap=pl.cm.Paired) # cmap 確定顏色 pl.axis('tight') pl.show()
除此之外,sklearn還提供了
RadiusNeighborsClassifier
KNeighborsRegressor
RadiusNeighborsRegressor
NearestNeighbors