最近鄰算法

最近鄰算法

常見距離準則:算法

 

 

Jaccard類似度常使用的場景:數據中有較多的0和1的斷定,此時適合使用Jaccard類似度。數據結構

簡介

NearestNeighbors (最近鄰)實現了 unsupervised nearest neighbors learning(無監督的最近鄰學習)。 它爲三種不一樣的最近鄰算法提供統一的接口:BallTree, KDTree, 還有基於 sklearn.metrics.pairwise 的 brute-force 算法。算法的選擇可經過關鍵字 'algorithm' 來控制, 並必須是 ['auto', 'ball_tree', 'kd_tree', 'brute'] 其中的一個。當默認值設置爲 'auto' 時,算法會嘗試從訓練數據中肯定最佳方法。ide

暴力計算

最簡單的近鄰搜索的實現涉及數據集中全部成對點之間距離的暴力計算: 對於 D 維度中的 N 個樣原本說, 這個方法的複雜度是 O[D N^2]。 對於小數據樣本,高效的暴力近鄰搜索是很是有競爭力的。 然而,隨着樣本數 N 的增加,暴力方法很快變得不切實際了。性能

 

在 sklearn.neighbors 類中, 暴力近鄰搜索經過關鍵字 algorithm = 'brute' 來指定,並經過 sklearn.metrics.pairwise 中的例程來進行計算。學習

K-D 樹

爲了解決效率低下的暴力計算方法,已經發明瞭大量的基於樹的數據結構。總的來講, 這些結構試圖經過有效地編碼樣本的 aggregate distance (聚合距離) 信息來減小所需的距離計算量。 基本思想是,若 A 點距離 B 點很是遠,B 點距離 C 點很是近, 可知 A 點與 C 點很遙遠,不須要明確計算它們的距離。 經過這樣的方式,近鄰搜索的計算成本能夠下降爲 O[D N log(N)] 或更低。 這是對於暴力搜索在大樣本數 N 中表現的顯著改善。測試

 

利用這種聚合信息的早期方法是 KD tree 數據結構(* K-dimensional tree* 的簡寫), 它將二維 Quad-trees 和三維 Oct-trees 推廣到任意數量的維度. KD 樹是一個二叉樹結構,它沿着數據軸遞歸地劃分參數空間,將其劃分爲嵌入數據點的嵌套的各向異性區域。 KD 樹的構造很是快:由於只需沿數據軸執行分區, 無需計算 D-dimensional 距離。 一旦構建完成, 查詢點的最近鄰距離計算複雜度僅爲 O[log(N)] 。 雖然 KD 樹的方法對於低維度 (D < 20) 近鄰搜索很是快, 當 D 增加到很大時, 效率變低: 這就是所謂的 「維度災難」 的一種體現。 在 scikit-learn 中, KD 樹近鄰搜索可使用關鍵字 algorithm = 'kd_tree' 來指定, 而且使用類 KDTree 來計算。編碼

Ball 樹

爲了解決 KD 樹在高維上效率低下的問題, ball 樹 數據結構就被研發出來了. 其中 KD 樹沿卡迪爾軸(即座標軸)分割數據, ball 樹在沿着一系列的 hyper-spheres 來分割數據. 經過這種方法構建的樹要比 KD 樹消耗更多的時間, 可是這種數據結構對於高結構化的數據是很是有效的, 即便在高維度上也是同樣.idea

 

ball 樹將數據遞歸地劃分爲由質心 C 和半徑 r 定義的節點,spa

使得節點中的每一個點位於由 r 和 C 定義的 hyper-sphere 內. 經過使用 triangle inequality(三角不等式) 減小近鄰搜索的候選點數:rest

|x+y| <= |x| + |y|

經過這種設置, 測試點和質心之間的單一距離計算足以肯定距節點內全部點的距離的下限和上限. 因爲 ball 樹節點的球形幾何, 它在高維度上的性能超出 KD-tree, 儘管實際的性能高度依賴於訓練數據的結構. 在 scikit-learn 中, 基於 ball 樹的近鄰搜索可使用關鍵字 algorithm = 'ball_tree' 來指定, 而且使用類 sklearn.neighbors.BallTree 來計算. 或者, 用戶能夠直接使用 BallTree 類.

使用

from sklearn.neighbors import NearestNeighbors

import numpy as np

X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

 

# n_neighbors默認5,algorithm默認‘auto’

nbrs = NearestNeighbors(n_neighbors=3, algorithm='ball_tree').fit(X) 

 

# indices獲得k個最近鄰的索引,distances獲得與k個最近鄰的距離

distances, indices = nbrs.kneighbors(X)

indices

>>> array([[0, 1, 2],

       [1, 0, 2],

       [2, 1, 0],

       [3, 4, 5],

       [4, 3, 5],

       [5, 4, 3]], dtype=int64)

Distances

>>>  array([[ 0.        ,  1.        ,  2.23606798],

       [ 0.        ,  1.        ,  1.41421356],

       [ 0.        ,  1.41421356,  2.23606798],

       [ 0.        ,  1.        ,  2.23606798],

       [ 0.        ,  1.        ,  1.41421356],

       [ 0.        ,  1.41421356,  2.23606798]])

 

也能夠直接使用:

from sklearn.neighbors import KDTree

import numpy as np

X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

kdt = KDTree(X, leaf_size=30, metric='euclidean')

 

#獲得k個最近鄰的索引

kdt.query(X, k=2, return_distance=False)  

相關文章
相關標籤/搜索