[英]How does sklearn's standard DBSCAN run so fast?
我一直在研究 DBSCAN 的替代實現來聚類雷達數據(如基於網格的 DBSCAN)。 到目前為止,我一直在使用 sklearn 的標准歐幾里得 DBSCAN,它可以在不到一秒的時間內在 26,000 個數據點上運行。 但是,當我指定自己的距離度量時,如下所示:
X = np.column_stack((beam, gate, time_index))
num_pts = X.shape[0]
epsilons = np.array([[beam_eps]*num_pts, [gate_eps] * num_pts, [time_eps] * num_pts]).T
metric = lambda x, y, eps: np.sqrt(np.sum((x/eps - y/eps)**2))
def dist_metric(x, y, eps):
return np.sqrt(np.sum((x - y)**2))
db = DBSCAN(eps=eps, min_samples=minPts, metric=dist_metric, metric_params={'eps': epsilons}).fit(X)
運行相同的數據需要 0.36 秒到 92 分鍾。
我在該代碼片段中所做的也可以通過預先轉換數據並運行標准歐幾里得 DBSCAN 來完成,但我正在嘗試實現基於網格的 DBSCAN 的合理快速版本,其中水平 epsilon 隨距離變化而變化雷達,所以我不能那樣做。
上述距離度量緩慢的部分原因是我認為 epsilon 的划分,因為如果我使用一個只是歐幾里德距離的“自定義度量”,它只需要大約一分鍾的時間運行:
metric = lambda x, y: np.sqrt(np.sum((x - y)**2))
sklearn 的歐幾里得 DBSCAN 如何運行得如此之快? 我一直在挖掘代碼,但到目前為止還沒有弄明白。
因為它使用了索引。
此外,它避免了緩慢且內存密集的 Python解釋器,而是在本機代碼(從 Cython 編譯)中完成所有工作。 在處理 Python 解釋器需要裝箱的大量原始數據(例如雙精度和整數)時,這會產生巨大的差異。
索引對相似性搜索產生了很大的影響。 他們可以將運行時間從 O(n²) 減少到 O(n log n)。
但是雖然球樹索引允許自定義度量,但每次距離計算調用 python 解釋器的成本非常高,所以如果你真的想要自定義度量,編輯 cython 源代碼並自己編譯 sklearn。 或者你可以使用 ELKI,因為 Java JVM 可以在必要時將擴展代碼編譯為本機代碼; 它不需要回退到像 sklearn 這樣的慢解釋器回調。
在您的情況下,最好對數據進行預處理。 在聚類之前對其進行縮放。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.