1. 程式人生 > >【機器學習】K近鄰演算法

【機器學習】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