KNN 原理及參數總結

前言:針對一個完整的機器學習框架目前還沒有總結出來,所以目前只能總結每一個單獨的算法。由於現在研究的重點是算法,所以對於數據的處理,數據的分析和可視化呈現,在現階段並不進行展示(這樣容易陷入糾結和浪費過多時間)。但是,當理解算法的基本原理和實現方法之後,再回過頭來從頭開始,實現一個完整的機器學習流程。

1. KNN 原理

KNN是一種即可用於分類又可用於迴歸的機器學習算法。對於給定測試樣本,基於距離度量找出訓練集中與其最靠近的K個訓練樣本,然後基於這K個“鄰居”的信息來進行預測。
在分類任務中可使用投票法,選擇這K個樣本中出現最多的類別標記作爲預測結果;在迴歸任務中可使用平均法,將這K個樣本的實值輸出標記的平均值作爲預測結果。當然還可以基於距離遠近程度進行加權平均等方法。

2. KNN 優缺點

KNN 優點

  1. 理論成熟,思想簡單,既可以用來做分類也可以用來做迴歸
  2. 可用於非線性分類
  3. 訓練時間複雜度比支持向量機之類的算法低,僅爲O(n)
  4. 和樸素貝葉斯之類的算法比,對數據沒有假設,準確度高,對異常點不敏感
  5. 由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更爲適合
  6. 該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域採用這種算法比較容易產生誤分

KNN 缺點

  1. 計算量大,尤其是特徵數非常多的時候
  2. 樣本不平衡的時候,對稀有類別的預測準確率低
  3. KD樹,球樹之類的模型建立需要大量的內存
  4. 使用懶散學習方法,基本上不學習,導致預測時速度比起邏輯迴歸之類的算法慢
  5. 相比決策樹模型,KNN模型可解釋性不強

3. KNN 算法三要素

距離度量

閔可夫斯基距離(minkowski):

D(x,y)=(x1y1)p+(x2y2)p+...+(xnyn)pp=i=1n(xiyi)pp D(x,y) =\sqrt[p]{(|x_1-y_1|)^p + (|x_2-y_2|)^p + ... + (|x_n-y_n|)^p} =\sqrt[p]{\sum\limits_{i=1}^{n}(|x_i-y_i|)^p}

歐氏距離(euclidean,p=2):

D(x,y)=(x1y1)2+(x2y2)2+...+(xnyn)2=i=1n(xiyi)2 D(x,y) = \sqrt{(x_1-y_1)^2 + (x_2-y_2)^2 + ... + (x_n-y_n)^2} = \sqrt{\sum\limits_{i=1}^{n}(x_i-y_i)^2}

曼哈頓距離(manhattan,p=1):

D(x,y)=x1y1+x2y2+...+xnyn=i=1nxiyi D(x,y) =|x_1-y_1| + |x_2-y_2| + ... + |x_n-y_n| =\sum\limits_{i=1}^{n}|x_i-y_i|

切比雪夫距離(chebyshev,p= \infty):

D(x,y)=maxxiyi(i=1,2,...n) D(x,y) =max|x_i-y_i| (i = 1,2,...n)
……常用的主要有這些。

K 值的選擇

下面分析k值過大和過小造成的影響:

  1. k值較小,就相當於用較小的領域中的訓練實例進行預測,訓練誤差近似誤差小(偏差小),泛化誤差會增大(方差大),換句話說,K值較小就意味着整體模型變得複雜,容易發生過擬合;

  2. k值較大,就相當於用較大領域中的訓練實例進行預測,泛化誤差小(方差小),但缺點是近似誤差大(偏差大),換句話說,K值較大就意味着整體模型變得簡單,容易發生欠擬合;一個極端是k等於樣本數m,則完全沒有分類,此時無論輸入實例是什麼,都只是簡單的預測它屬於在訓練實例中最多的類,模型過於簡單。

對於k值的選擇,沒有一個固定的經驗(sklearn默認爲5),一般根據樣本的分佈,選擇一個較小的值,可以通過交叉驗證選擇一個合適的k值。

分類決策規則

KNN 算法一般是用多數表決方法,即由輸入實例的K個鄰近的多數類決定輸入實例的類。這也是經驗風險最小化的結果。

我們定義訓練誤差率是K近鄰訓練樣本標記與輸入標記不一致的比例,誤差率表示爲:
1/KxiNk(x)I(yicj)=11/KxiNk(x)I(yi=cj) 1/K\sum\limits_{x_i\in N_k(x)}I(y_i\neq c_j)=1-1/K\sum\limits_{x_i\in N_k(x)}I(y_i= c_j)
目的是K近鄰的標記值儘可能的與輸入標記一致,所以最小化1/KxiNk(x)I(yicj)1/K\sum\limits_{x_i\in N_k(x)}I(y_i\neq c_j)最大化1/KxiNk(x)I(yi=cj)1/K\sum\limits_{x_i\in N_k(x)}I(y_i= c_j)

4 KNN 算法實現

線性掃描

線性掃描也叫“暴力搜索”,是計算輸入實例與每一個訓練實例的距離,並選擇前k個最近鄰的樣本來多數表決。這種實現方法簡單,但是當訓練集或特徵維度很大時(我們經常碰到樣本的特徵數有上千以上,樣本量有幾十萬以上),如果我們這要去預測少量的測試集樣本,算法的時間效率很成問題,計算非常耗時,故這種暴力實現原理是不可行的 。

kd 樹實現

kd 樹是一種對k維空間中的實例點進行存儲以便對其進行快速檢索的樹形數據結構,構造kd樹相當於不斷用垂直於座標軸的超平面將k維空間進行劃分,構成一系列的k維超矩形區域,kd樹省去了對大部分數據的搜索,大大的較少了計算量。

注意這裏的k和KNN中的k的意思不同。KNN中的k代表最近的k個樣本,kd樹中的k代表樣本特徵的維數。

KD樹算法包括三步,第一步是建樹,第二部是搜索最近鄰,最後一步是預測。

  1. kd 樹的建立。kd樹實質是二叉樹,其劃分思想與CART樹一致,切分使樣本複雜度降低最多的特徵。kd樹分別計算k個特徵的方差,認爲特徵方差越大,則該特徵的複雜度亦越大,優先對該特徵進行切分 ,切分點是所有實例在該特徵的中位數。重複該切分步驟,直到切分後無樣本則終止切分,終止時的樣本爲葉節點,形成kd樹。

  2. kd樹搜索最近鄰。生成kd樹以後,對於一個目標點以目標點爲圓心,以目標點到葉子節點樣本實例的距離爲半徑,得到一個超球體,最近鄰的點一定在這個超球體內部。然後返回葉子節點的父節點,檢查另一個子節點包含的超矩形體是否和超球體相交,如果相交就到這個子節點尋找是否有更加近的近鄰,有的話就更新最近鄰。如果不相交直接返回父節點的父節點,在另一個子樹繼續搜索最近鄰。依次下去,當回溯到根節點時,算法結束,此時保存的最近鄰節點就是最終的最近鄰。

    對於kd樹來說,劃分後可以大大減少無效的最近鄰搜索,很多樣本點由於所在的超矩形體和超球體不相交,根本不需要計算距離。大大節省了計算時間。

  3. kd樹預測。

    分類:每一次搜尋與輸入樣本最近的樣本節點,然後忽略該節點,重複同樣步驟K次,找到與輸入樣本最近鄰的K個樣本 ,投票法確定輸出結果。

    迴歸:用K個最近樣本的輸出的平均值作爲迴歸預測值。

球樹實現

kd樹算法雖然提高了KNN搜索的效率,但是在某些時候效率並不高,比如當處理不均勻分佈的數據集時,不管是近似方形,還是矩形,甚至正方形,都不是最好的使用形狀,因爲他們都有角。爲了優化超矩形體導致的搜索效率的問題,從而提出了球樹實現的方法。其基本思想和kd樹類似,就是每個分割塊都是超球體,而不是KD樹裏面的超矩形體。

5 sklearn實現KNN算法

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

在這些算法中,KNN分類和迴歸的類參數完全一樣。具體參數如下:

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=’uniform’, 
algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, 
n_jobs=None, **kwargs)
  • n_neighbors:KNN中的k值,默認爲5(對於k值的選擇,前面已經給出解釋);

  • weights:用於標識每個樣本的近鄰樣本的權重,可選擇"uniform",“distance” 或自定義權重。默認"uniform",所有最近鄰樣本權重都一樣。如果是"distance",則權重和距離成反比例;如果樣本的分佈是比較成簇的,即各類樣本都在相對分開的簇中時,我們用默認的"uniform"就可以了,如果樣本的分佈比較亂,規律不好尋找,選擇"distance"是一個比較好的選擇;

  • algorithm:限定半徑最近鄰法使用的算法,可選‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’。
    ‘brute’對應第一種線性掃描;
    ‘kd_tree’對應第二種kd樹實現;
    ‘ball_tree’對應第三種的球樹實現;
    ‘auto’則會在上面三種算法中做權衡,選擇一個擬合最好的最優算法。

  • leaf_size:這個值控制了使用kd樹或者球樹時, 停止建子樹的葉子節點數量的閾值。這個值越小,則生成的kc樹或者球樹就越大,層數越深,建樹時間越長,反之,則生成的kd樹或者球樹會小,層數較淺,建樹時間較短。默認是30。

    這個值一般依賴於樣本的數量,隨着樣本數量的增加,這個值必須要增加,否則不光建樹預測的時間長,還容易過擬合。可以通過交叉驗證來選擇一個適中的值。當然,如果使用的算法是蠻力實現,則這個參數可以忽略;

  • metric,p:距離度量(前面介紹過),默認閔可夫斯基距離 “minkowski”(p=1爲曼哈頓距離, p=2爲歐式距離);

  • metric_params:距離度量其他附屬參數(具體我也不知道,一般用得少);

  • n_jobs:並行處理任務數,主要用於多核CPU時的並行處理,加快建立KNN樹和預測搜索的速度。n_jobs= -1,即所有的CPU核都參與計算。

限定半徑最近鄰法分類和迴歸的類的主要參數也和KNN基本一樣。具體參數如下:

sklearn.neighbors.RadiusNeighborsClassifier(radius=1.0, weights=’uniform’, 
algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, outlier_label=None, 
metric_params=None, n_jobs=None, **kwargs)
  • radius:限定半徑,默認爲1。半徑的選擇與樣本分佈有關,可以通過交叉驗證來選擇一個較小的半徑,儘量保證每類訓練樣本其他類別樣本的距離較遠;
  • outlier_labe:int類型,主要用於預測時,如果目標點半徑內沒有任何訓練集的樣本點時,應該標記的類別,不建議選擇默認值 None,因爲這樣遇到異常點會報錯。一般設置爲訓練集裏最多樣本的類別。

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章