我一直在纠缠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分钟。
我在该代码段中所做的操作也可以通过仅预先转换数据并运行标准的Euclidean DBSCAN来完成,但是我正在尝试实现一个合理的基于Grid的DBSCAN版本,水平ε随其变化在距雷达的距离上,所以我将无法做到这一点。
上述距离度量标准的缓慢部分原因是因为我将其除以epsilon,因为如果我使用的只是一个欧几里德距离的“自定义度量标准”,则只需大约一分钟即可运行:
metric = lambda x, y: np.sqrt(np.sum((x - y)**2))
sklearn的欧式DBSCAN如何运行得如此快?我一直在仔细研究代码,但到目前为止还没有任何意义。
答案 0 :(得分:1)
因为它使用了索引。
此外,它避免使用速度慢且占用大量内存的Python 解释器,但可以使用本机代码(由Cython编译)完成所有工作。当处理大量原始数据(例如,Python解释器需要装箱的双精度和整数)时,这将产生巨大的差异。
索引使相似性搜索完全不同。它们可以将运行时间从O(n²)减少到O(n log n)。
但是,尽管ball tree索引允许自定义指标,但是每次距离计算调用python解释器的成本非常高,因此,如果您真的想要自定义指标,请编辑cython源代码并自己编译sklearn。或者,您可以使用ELKI,因为Java JVM可以在必要时将扩展代码编译为本机代码。不需要回退到诸如sklearn之类的缓慢的解释器回调。
在您的情况下,最好对数据进行预处理。在集群之前对其进行缩放。