原文章為scikit-learn中"用戶指南"-->"監督學習的第六節:Nearest Neighbors"######
sklearn.neighbors
提供了一些在無監督和有監督學習中基于近鄰的學習方法。無監督近鄰是許多其他學習方法的基石,特別是在流學習和光譜聚類方面。有監督的基于近鄰的學習有兩個方面:對帶有離散標簽的數據進行分類 ,對帶有連續標簽的數據計算回歸。
最近鄰的原則上是先找出距離新點(預測點)最近的預定數量的訓練樣本,繼而預測其所屬的標簽。樣本數可以是用戶所定義的常數(此處即為K近鄰算法,KNN),或基于點的局部密度而變化的值(基于半徑的近鄰學習)。近鄰的距離通常是可以通過任何度量方式來測量:所以一般使用標準歐幾里得距離來判斷點與點的距離。近鄰方式同樣以非泛化機器學習方式被人所知,因為它會簡單的“記住”了所有的訓練數據(可能是被轉化成一種能夠快速索引的格式,例如 Ball Tree 或 KD Tree)。
盡管看起來他的實現原理看起來很簡單,但是近鄰已經成功的應用在一些大規模的分類和回歸問題上了,例如手寫文字識別和衛星圖像場景。因為它是一個無參數方法,所以通常能夠很成功地應用在一個有無規則的決策邊界的分類問題上。
sklearn.neighbors
能夠同時接受** Numpy 數組或 scipy.sparse **矩陣作為輸入。對于密集矩陣同樣也支持其超大的可能距離度量。而對于稀疏矩陣則支持搜索任意的 Minkowski 度量。
這里有許多學習事務使用近鄰作為他們的計算核心。一個例子是核密度估計,我們會在 密度估計 一節中來進行討論。
1.6.1. 無監督近鄰#
NearestNeighbors
實現了一個無監督近鄰學習。它作為一個統一的接口應用在了三種不同的近鄰算法中,分別是:BallTree
,KDTree
和 sklearn.metrics.pairwise
中一個基于事務的brute方法。可以通過關鍵字** algorithm 來選擇需要使用哪種近鄰搜索算法,可選值有: [‘auto’, 'ball_tree', 'kd_tree', 'brute'] 。在輸入默認值 'auto' **時,會自動從這些算法中試圖找到對訓練集最合適的算法。如果想要知道知道這些算法各自的長短處的話,可以查看這篇近鄰算法文章。
警告:關于近鄰算法,如果兩個鄰居,k + 1** 和 ** k 擁有著相同的距離,但卻屬于不同的標簽時,計算結果將根據訓練數據的排序來決定。
1.6.1.1. 尋找最近鄰##
對于在兩組數據之間尋找最近鄰的簡單任務, 可以使用 sklearn.neighbors
這一無監督算法來完成:
>>> from sklearn.neighbors import NearestNeighbors
>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> nbrs = NearestNeighbors(n_neighbors=2, algorithm='ball_tree').fit(X)
>>> distances, indices = nbrs.kneighbors(X)
>>> indices
array([[0, 1],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4]]...)
>>> distances
array([[ 0. , 1. ],
[ 0. , 1. ],
[ 0. , 1.41421356],
[ 0. , 1. ],
[ 0. , 1. ],
[ 0. , 1.41421356]])
所以查詢集跟訓練集一樣,因為最靠近的點就是他自身(距離為0)。
另外還可以使用它來有效地產生表示相鄰點之間關系的稀疏圖:
>>> nbrs.kneighbors_graph(X).toarray()
array([[ 1., 1., 0., 0., 0., 0.],
[ 1., 1., 0., 0., 0., 0.],
[ 0., 1., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 0.],
[ 0., 0., 0., 1., 1., 0.],
[ 0., 0., 0., 0., 1., 1.]])
因為我們的數據集是經過結構化了,所以使得數據點會順序排列在參數空間旁邊,得出K個鄰居的一個近似對角矩陣(也就是上方代碼塊所排列的矩陣,因為自己與自己必定"相鄰",所以對角線是1)。這樣的稀疏圖在各種情況下都是很有用的,能夠在無監督學習的情況下利用各樣本點的空間關系:尤其是 sklearn.manifold.Isomap
,sklearn.manifold.LocallyLinearEmbedding
和 sklearn.cluster.SpectralClustering
對這三個類來說。
1.6.1.2. KD樹和Ball樹類##
另外一種尋找最近鄰的可選方式是使用 KDTree
或 BallTree
類。這些類是 NearestNeighbors
經過包裝后生成的類。Ball樹和KD樹都擁有著相同的接口(即有著相同的使用方式),以下方的KD樹為例:
>>> 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')
>>> kdt.query(X, k=2, return_distance=False)
array([[0, 1],
[1, 0],
[2, 1],
[3, 4],
[4, 3],
[5, 4]]...)
可以在 KDTree
和 BallTree
的文檔里找到更多關于鄰居搜索的設置,包括如何規范化搜索策略,各種距離度量的規范等等。對于所有可用的矩陣列表,可用查看 DistanceMetric
類的文檔。
1.6.2. 近鄰分類#
基于鄰居的分類是基于實例的學習或非泛化學習的一種:它不需要試圖去構造一個通用的泛化模型,而是通過使用簡單的儲存訓練樣本的實例來進行分類。這種分類是遍歷每個樣本點,然后對其的"最近鄰居"進行簡單的多數表決來進行分類:查詢點通過與其最相鄰,最能代表它的點來分配它的所屬類。
scikit-learn 實現了兩種不同的近鄰分類器:
-
KNeighborsClassifier
實現了對每個查詢點的基于** K 近鄰算法,其中 K **為通過用戶輸入的整數。 -
RadiusNeighborsClassifier
實現了一個基于每個訓練點的固定半徑** r 內的"鄰居"的數量的學習,其中 r **是用戶輸入的浮點數。
KNeighborsClassifier
里的 **K 鄰分類是上述兩種技術中最常用的一個。K 的最優值是與數據高度依賴的:一般來說 K **值越大就越能夠降低噪音對模型的影響,但同樣也會使分類邊界變得不明顯。
當數據樣本不均勻時,使用 RadiusNeighborsClassifier
中基于半徑的鄰居分類也許是一個比較好的選擇。用戶要指定一個固定的半徑值** r **,這樣位于稀疏近鄰內的樣本點會使用對應的鄰居數量(應該是根據半徑來搜索)來進行分類。但是對高維參數空間來說,因為存在所謂的"維度災難"(過多的特征導致分類的誤差增大),所以使用這一方式有可能會變使分類得低效。
基于近鄰分類的實現類在默認情況下都有著一致的設置權重的方法:也就是說分配到查詢點的值是只通過計算其附近鄰居點的多數表決(統計)來得到的。在某些情況下,最好是通過對"鄰居"添加一個權重,使得越"近"的鄰居對擬合的貢獻更大。所以這一操作可以通過關鍵字** weight 來完成。一般情況下這個參數的默認值是 uniform ,此時會使得所有"鄰居"都有相同的權重;而當該參數設置為 distance **時,權重值以取反比的方式,距離查詢點越進的點權重越高。當然也可以通過用戶自定義的權重來對“鄰居”進行計算。
示例
- 近鄰分類: 一個使用近鄰算法來進行分類的例子。
1.6.3. 近鄰回歸#
近鄰回歸能夠用在數據標簽是連續的而不是離散變量的情況下。這種標簽的分配方式為其值是根據查詢點的“鄰居”標簽的平均數來決定的。
scikit-learn實現了兩種不同的近鄰回歸:
-
KNeighborsRegressor
實現了一個基于每個查詢點的** K 近鄰學習,其中 K **是通過用戶輸入的整數。 -
RadiusNeighborsRegressor
實現了一個基于查詢點在固定半徑** r 內的近鄰學習,其中 r **是一個用戶指定的浮點數。
基于近鄰回歸的實現類在默認情況下都有著一致的設置權重的方法:對查詢點來說,所有樣本點對他的貢獻度都是一致的。在某些情況下,最好是通過對"鄰居"添加一個權重,使得越"近"的鄰居對擬合的貢獻更大。所以這一操作可以通過關鍵字** weight 來完成。一般情況下這個參數的默認值是 uniform ,此時會使得所有"鄰居"都有相同的權重;而當該參數設置為 distance **時,權重值以取反比的方式,距離查詢點越進的點權重越高。當然也可以通過用戶自定義的權重來對“鄰居”進行計算。
有關多路輸出的近鄰回歸可以在 使用多路輸出估計器的臉部補全 這篇文章中找到其功能演示。在這個例子中,輸入** X 是包括臉部的上半部分,輸出 Y **則是臉部的下半部分。
例子
- 近鄰回歸: 一個使用近鄰回歸的例子。
- 使用多路輸出估計器的臉部補全: 一個使用多路輸出的近鄰回歸例子。
1.6.4. 近鄰算法#
1.6.4.1. 暴力算法(BF)##
在機器學習中,如何快速地計算近鄰一直都是一個很活躍的研究課題。最原始的近鄰搜索所涉及到的就是使用BF去計算數據集中的所有點對之間的距離:對于** D 維中的 N 個樣本,其規模有 O(D·N^2) 。高效的BF近鄰搜索對于小數量的數據樣本來說還是很具有競爭力的。但是隨著樣本數量 N 的贈面積,BF就會越來越快的變得不可行。在類 sklearn.neighbors
里,BF近鄰搜索可以通過設置關鍵字 algorithm='brute' **來實現,并且使用 sklearn.metrics.pairwise
中的事務來進行計算。
1.6.4.2. K-D 樹##
為了解決BF在大規模數據下的低效的計算能力,已經發明了各種基于樹的數據結構。一般來說,這些結構都通過其結構來有效地編碼樣本的聚合距離的信息來試圖減少需要計算的距離數量。其基本思想是,如果一個樣本點** A 對另一個樣本點 B 的距離很遙遠,但是樣本點 B 的又很靠近點 C ,因此我們可以知道點 A 同樣距離點 C 很遙遠,而這樣就不需要再額外計算他們的距離。所以使用這種方式后,近鄰的計算成本就減少為 O[D·N·log(N)] 或更好。這在大規模 N **的情況下比BF有著更顯著的效果。
KD樹(K維樹的簡稱)數據結構則是一種應用了這種綜合信息的早期方法,其使用生成二維的四叉樹和三維的八叉樹來匹配任意維度的數據。KD樹是一種二叉樹結構,其沿著數據的軸遞歸地分割參數空間,然后再將其分配到原來的區域內,最后再填充數據點。KD樹的構建過程是非常快的:因為只會沿著數據軸來進行分區,不需要計算** D 維的距離。一旦構建完成后,查詢點的近鄰只需要計算 O[Log(N)] 的距離就足夠了。因為KD樹在低維度( D < 20,但是這里的低維度相對于BF而言是高維度的)下的近鄰搜索非常快,但還是會因為 D 的增加而該搜索過程會變得不怎么有效率。造成這個原因的同樣也是因為"維度災難"的存在。在scikit-learn里,KD樹近鄰搜索可以通過關鍵字 algorithm 將其設置為 td_tree **來使用,這會使得計算過程是通過 KDTree
類來完成。
引用
- “Multidimensional binary search trees used for associative searching”, Bentley, J.L., Communications of the ACM (1975)
1.6.4.3. Ball樹##
同樣為了解決KD樹在高維度下的低效能,ball樹數據結構被發明了出來。相對于KD樹的分區是沿著笛卡爾軸來進行分割,Ball樹則是將數據分割成一系列的超球體。當然這會使得Ball樹的開銷比KD樹要打,但是卻獲得了一種對高度數據化的數據仍然具有高效的數據結構,即使是用于處理擁有高維的數據也不例外。
Ball樹的遞歸分割是通過定義一個質心** C (如果不知道什么是質心,可以查看該網址的Q1)和半徑 r ,使得節點中的每個點都位于由 r 和 C 定義的超球體內。然后使用三角不等式**來減少用于鄰居搜索的候選點的數量:
這樣測試點到質心的距離就足以用來決定該測試點與其近鄰距離的上下限。因為Ball樹的節點就是球形的幾何,所以它能夠在高維上執行KD樹,雖然實際性能是高度依賴于訓練數據的結構。在scikit-learn,可以通過使用設置關鍵字** algorithm 為 ball_tree **來使用基于Ball樹的近鄰搜索,且它是通過 sklearn.neighbors.BallTree
類來進行計算的。不過用戶也可以直接使用 BallTree
類來進行計算。
引用
- “Five balltree construction algorithms”, Omohundro, S.M., International Computer Science Institute Technical Report (1989)
1.6.4.4. 近鄰算法的選擇##
對給定的數據集選擇一個的最佳算法是一個很復雜的過程,要考慮的因素有多個:
- 樣本的數量** N (即 n_samples)和維度 D (即n_features **)
- BF查詢時間的增長為** O[D·N]**
- Ball樹查詢時間的增長近似為** O[D·log(N)] **
- KD樹查詢時間以一種難以表達的方式進行改變:
- D <= 20 左右 時,近似于 O[D·log(N)]
- D > 20時,可能接近于** O[D·N] **或者是更糟。
對小數據集(N <= 30 左右),**log(N) 與 N 相當,并且此時的BF比基于樹的搜索更具效率。為了應對這種情況,KDTree和BallTree都通過提供參數 葉子大小 **來解決這個問題:這個參數能夠控制在處理多少樣本數時切換算法到BF。這樣處理的話允許每一個算法都能夠在小數據集上獲得BF的高效率。
- 數據的結構:數據的內在維度與其稀疏性。內在維度是指數據的流形維度(d <= D),其可以以線性或者非線性的形式來嵌入參數空間中。稀疏性是指數據在參數空間的填充程度(這將與在“稀疏”矩陣中使用的概念不同。數據上的矩陣可能不是零,但是他在** 結構 **上也是有可能“稀疏”的)
- BF的查詢時間跟數據的結構無關。
- Ball樹和KD樹的查詢時間跟數據的結構有很大的關系。一般來說,有較小的內在維度的稀疏數據能夠使用很少的處理時間,因為KD樹的內部是與參數軸對其的,他一般不會在對有任意結構的數據上,像Ball樹那樣有著太多的性能提升。
因為用于機器學習的數據集一般是高度結構化的,所以很適合使用基于樹的算法來進行查詢搜索。
- 查詢點所需要的近鄰數量** K**:
- **K **的值不會影響BF的查詢時間。
- 當** K 值增加時,Ball樹和KD樹的查詢時間會變得越來越慢。這是因為兩方面的原因:第一,越大的 K 值會導致需要在參數空間搜索的部分變大。第二,對K > 1**的情況下,需要對結果遍歷排序成樹。
當** K 變得比 N **還要大時,修建基于查詢結果所生成的樹的能力會降低。在這種情況下,BF查詢可能會更有效。
- 查詢點的數量。Ball樹和KD樹同樣需要一個構造階段。但是在面對分攤查詢所消耗的時間上,在構造時所消耗的時間對此相比也不多了。如果只是進行少量的查詢的話,那么構造的時間就會在總體時間內占據很大的比例了。如果只需要查詢少量的幾個點的話(即查詢點旁邊的點的數量確實不怎么多),此時BF比所有基于樹的算法要好。
基于這些情況,在** algorithm='auto' 的情況下,如果 K < N / 2 且 'effective_metric_' 存在于 'kd_tree' 中的 'VALID_METRICS' 列表,則會自動設置成 kd_tree 。如果 K < N / 2 且 'effective_metric_' 不存在于 'kd_tree' 中的 'VALID_METRICS' 列表,則會自動設置成 ball_tree。如果 K >= N / 2 且查詢的點數量至少與訓練點的數量相同,并且 leaf_size 接近默認值 30 時,則會設置為 'brute' **。
1.6.4.5 **leaf_size **的影響##
綜上所述,對于小的樣本數來說,BF比其他基于樹的算法要更有效率。基于這個現狀可以通過在Ball樹或KD樹的葉子節點數量來從內部切換搜索算法到BF。可以通過設置** leaf_size **參數來切換的標準。這個參數的取值會導致以下幾種影響:
- 構造時間
越大的** leaf_size **會有更快的構造時間,因為這樣只需要創建更少的節點。 - 查詢時間
對很大或很小的** leaf_size 都會獲得一個次優的查詢成本。對于 leaf_size 接近1的情況,遍歷所有節點所需的開銷會顯著的減慢查詢所需的時間。對 leaf_size 接近訓練集的數目時,就基本上是直接使用BF了。一個比較好的妥協方法是將其設置為 30,并且這也是 leaf_size **的默認值。 - 內存
隨著** leaf_size 增加,需要用來儲存樹結構的內存也會下降。這一點對Ball樹來說尤其重要,因為Ball樹的每一個節點都是存放有一個 D 維的質心球體。BallTree
所需要的內存近似為訓練集大小的 1 / leaf_size **倍。
**leaf_size **不會在BF查詢里使用。
1.6.5. 最近鄰質心分類器#
NearestCentroid
分類器是一個用其成員的質心來代表每一類的簡單的算法的實現。但是在實際上,這個操作類似于** sklearn.KMeans **算法的標簽更新階段。同樣這個算法因為不需要選擇參數這一點,使得它同樣也是一個良好的基準分類器。當類之間有著太大的方差就好收到非凸類的影響,因為在假設的情況下,在所有維度中的方差都是相等的。對于沒有做這個假設的更復雜的方法,可以查看 線性判別法 和 二次判別分析法
。以下是使用默認的 NearestCentroid
例子:
>>> from sklearn.neighbors.nearest_centroid import NearestCentroid
>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> y = np.array([1, 1, 1, 2, 2, 2])
>>> clf = NearestCentroid()
>>> clf.fit(X, y)
NearestCentroid(metric='euclidean', shrink_threshold=None)
>>> print(clf.predict([[-0.8, -1]]))
[1]
1.6.5.1. 最近收縮質心##
NearestCentroid
分類器擁有一個** shrink_threshold 參數,其實現了一個最近收縮質心分類器。實際上每個質心的每個特征值被其類內的特征方差所劃分。然后特征值就會根據 shrink_threshold **的值來減少。最顯著的是如果一個特定的特征值越過0值,那么其值會被設置為0。實際上這操作直接消除了毫無作用的特征。因此這可以用來去除無用的噪音特征。
在線的路子,使用一個較小的收縮閾值將模型的準確度從0.81增加到0.82.
示例
- 近鄰質心分類: 一個使用了擁有不同收縮閾值的近鄰質分類的例子。
1.6.6. 近似最近鄰#
在處理低維度** d (值近似50)的問題上,有許多高效且精確的近鄰搜索算法可以使用。但是這些算法都存在當 d **增加時,相對的占用空間和查詢時間都會增加。在高維空間中,這些算法跟遍歷數據集中查詢點旁的所有點的算法(也就是 BF了)并沒有什么優越的地方。造成這一點的原因自然是“維度災難”這一現象了。
對一些應用來說其并不需要獲得有多精確的近鄰,相反他只需要做出一個“合格的猜測”就足夠了。當預測結果不需要太過于精確時,LSHForest
類實現了一個近似近鄰搜索。近似近鄰搜索是設計來試圖加速在高維數據中的查詢速度。這項技術在表現"鄰里關系",而不是需要精確的結果(例如K近鄰分類與回歸)時十分有用。一些受歡迎的近似近鄰搜索技術都是局部敏感哈希,即一種基于best bin first(BBF)和Balanced box-decomposition tree的搜索技術。
1.6.6.1. 局部敏感哈希樹##
局部敏感哈希的Vanilla實現擁有一個在實踐中難以調整的超參數,因此scikit-learn實現了一種叫 LSHForest
的變體算法,其擁有較多的合理超參數。這兩種方式都是用了內部隨機超平面去把樣本索引成"桶",并且只計算樣本的實際的余弦相似性,以此來對查詢結果進行碰撞以實現一個子線性的對樣本縮放(詳細情況可以查看局部敏感哈希的數學描述)。
LSHForest
有兩個主要的超參數:**n_estimators 和 n_candidates **。可以通過下圖來證明這些參數能夠用來控制查詢的準確度:
根據經驗來看,一個用戶可以通過設置** n_estimators 為一個足夠大的值(例如10到50之間),然后在查詢時間來調整 n_candidates **的值以平衡準確度。
對小數據集來說,BF仍舊要比LSH樹要快。但是LSH樹可以通過索引的大小來擁有一個可收縮的子線性的查詢時間。LSH樹與BF的性能平衡點取決于數據集的維度結構,所需的精度,運行環境的差別,例如BLAS優化的可用性,CPU的性能及其緩存。
在固定的 LSHForest
參數下,隨著數據集的增加,查詢結果的準確度傾向于緩慢下降。上述圖表中的錯誤條代表在不同查詢情況下的標準差。
示例
- 近似最近鄰的超參數: 一個使用LSH樹的近似最近鄰搜索的超參數的行為例子。
- 近似最近鄰的可擴展性: 一個使用LSH數的近似最近鄰的可伸縮性的例子。
1.6.6.2. 局部敏感哈希的數學描述##
局部敏感哈希(LSH)技術能夠使用在很多領域上,其中最多的是用在高維中來執行近鄰搜索。LSH背后的主要概念是使用多個(通常是簡單的)哈希函數來哈希數據集中的每個數據點,將其形成一個索引列表。對于哈希碰撞的可能性,當兩個對象有相似的索引時,彼此距離相近的兩個節點比起其他點而言產生碰撞的概率要高得多。散列函數族對局部敏感的要求如下。
從一個域** S 到另一個范圍 U 的一系列函數族 H 被稱為(r, e, p1, p2)-敏感,其中 r, e > 0, p1 > p2 > 0 ,如果對任意 p, q ∈ S ,都滿足以下條件(D **是距離函數):
- 如果** D(p, q) <= r ,且 P[h(p) = h(q)] >= p1**。
- 如果** D(p, q) < r(1 + e) ,且 P[h(p) = h(q)] >= p1**。
跟定義的一樣,距離為** r 之內的點很容易以 p1 的概率發生碰撞。相反,距離大于 r(1 + e) 的點則是會以以 p2 的小概率發生碰撞。
假設這里有一個LSH的函數族 H**。LSH索引的建立如下:
- 從** H 中隨機均勻選擇出 k 個函數(h1, h2, ..., hk)。對任意的 p ∈ S ,使用標簽 g(p) = (h1(p), h2(p), ..., hk(p)) 來替換掉原來的 p。如果每個 hi 輸出一位數字,可以觀察到每個桶都會有 k **位數字的標簽。
- 然后再獨立執行步驟1,ι次去構造出ι個分別具有** g1, g2, ..., gl **哈希函數的估量器。
在步驟1中使用連續的哈希函數的原因是盡可能地減少于遠處節點的碰撞概率。然后碰撞的概率從** p2 降低到 p2^k,并且是對于 k 來說是可以忽略的小數。k 值的選擇強烈取決于數據集的大小和結構,因此在數據集中很難以對 k 調參。對較大的 k **值來說還有一個副作用就是:它有可能會降低臨近點發生碰撞的幾率。為了解決這個問題,所以就在步驟2中構造了多個估量器。
因為需要對給定的數據集的** k **進行調參,所以在實踐中很難應用經典的LSH算法。所以就有一種設計來緩解這個問題的LSH樹的變種,其通過自動地調整哈希樣本所需的位數來解決這個問題。
LSH樹是由前綴樹形成的,樹的每個葉子節點代表著數據庫中實際的數據點。使用** ι 個這樣樹組成樹林,然后再使用從 H 中隨機抽取的哈希函數來獨立地構造他們。在這個實例中使用了隨機投影**作為LSH的技術,其為余弦距離的近似值。哈希函數序列的長度被固定為32。此外還使用了已排序的數組和折半搜索實現了一個前綴樹。
為了找出查詢點** q 的 m 個臨近點,需要使用樹的兩個遍歷階段。首先,從一個自頂向下的遍歷來用折半搜索找出經過哈希函數處理過后的 q 標簽的最長前綴(最大深度)葉子。然后從森林中提取出M 遠大于 m的節點(候選集),然后再自底向上的遍歷中同步地將找到的節點向根部移動。其中 M 是設置為 c·l,其中 c 是從樹中提取出的候選集的常數數量。最后這些 M 個點各自對 q 點的相似度,然后返回前 m 個最相似的點作為 q 點的近鄰。由于在查詢近鄰的過程中,大部分的時間都是花費在計算點之間的距離,所以這個方法比起BF搜索要快 N / M 左右,其中 N **是數據集中的數量。
引用
- “Near-Optimal Hashing Algorithms for Approximate Nearest Neighbor in High Dimensions”, Alexandr, A., Indyk, P., Foundations of Computer Science, 2006. FOCS ‘06. 47th Annual IEEE Symposium
- “LSH Forest: Self-Tuning Indexes for Similarity Search”, Bawa, M., Condie, T., Ganesan, P., WWW ‘05 Proceedings of the 14th international conference on World Wide Web Pages 651-660
(在嘗試翻譯這篇文檔的時候難免會因為各種問題而出現錯翻,如果發現的話,煩請指出,謝謝> <)