我想在Spark上做一些DBSCAN。我目前发现了2个实现:
我已经使用github中给出的sbt配置测试了第一个但是:
函数与doc或github上的源代码中的函数不同。例如,我在jar
我设法使用 fit 函数(在jar中找到)运行测试,但是epsilon的错误配置(从小到大)将代码置于无限循环中。 / p>
代码:
val model = DBSCAN.fit(eps, minPoints, values, parallelism)
有人设法与第一个图书馆合作吗?
有人测试了第二个吗?
答案 0 :(得分:9)
请尝试ELKI。由于这是Java,因此从Scala调用应该很容易。
ELKI非常优化,并且使用索引可以扩展到非常大的数据集。
我们尝试在我们的基准研究中包含其中一个Spark实现 - 但是内存耗尽(而且它是内存耗尽的唯一实现...... Spark和Mahout的k-means也属于最慢):
Hans-Peter Kriegel,Erich Schubert和Arthur Zimek The (black) art of runtime evaluation: Are we comparing algorithms or implementations?
在:知识和信息系统(KAIS)。 2016年,1-38
Neukirchen教授在本技术报告中对DBSCAN的并行实施进行了基准测试:
显然他有一些Spark实现工作,但注意到:Helmut Neukirchen
Survey and Performance Evaluation of DBSCAN Spatial Clustering Implementations for Big Data and High-Performance Computing Paradigms
结果是毁灭性的:Apache Spark的任何实现都没有接近HPC实现。特别是在较大(但仍然相当小)的数据集上,大多数数据集完全失败,甚至无法提供正确的结果。
和更早:
当运行任何" Spark DBSCAN"在利用我们集群的所有可用内核的同时,我们遇到了内存不足的异常。
(同样," Spark DBSCAN"在928个核心上花了2406秒,ELKI在1个核心上用了997秒用于较小的基准测试 - 其他Spark实现也没有太好,特别是它没有返回正确的结果......)
" DBSCAN on Spark"没有崩溃,但完全错了 簇。
而#34; DBSCAN on Spark"它完成得更快 完全错误的聚类结果。由于DBSCAN无可救药地长时间运行 已经具有最大内核数量的Spark的实现,我们没有执行 核心数量较少的测量。
您可以将double[][]
数组包装为ELKI数据库:
// Adapter to load data from an existing array.
DatabaseConnection dbc = new ArrayAdapterDatabaseConnection(data);
// Create a database (which may contain multiple relations!)
Database db = new StaticArrayDatabase(dbc, null);
// Load the data into the database (do NOT forget to initialize...)
db.initialize();
// Squared Euclidean is faster than Euclidean.
Clustering<Model> c = new DBSCAN<NumberVector>(
SquaredEuclideanDistanceFunction.STATIC, eps*eps, minpts).run(db);
for(Cluster<KMeansModel> clu : c.getAllClusters()) {
// Process clusters
}
另请参阅:Java API example(特别是,如何将DBID映射回行索引)。为了获得更好的性能,请将索引工厂(例如new CoverTree.Factory(...)
)作为第二个参数传递给StaticArrayDatabase
构造函数。
答案 1 :(得分:3)
我在项目中成功使用了第二个库(https://github.com/alitouka/spark_dbscan)。实际上,我不能按如下方式使用它:
libraryDependencies += "org.alitouka" % "spark_dbscan_2.10" % "0.0.4"
resolvers += "Aliaksei Litouka's repository" at "http://alitouka-public.s3-website-us-east-1.amazonaws.com/"
相反,我下载代码并将其更新为spark 2.2.1版本。另外,应该添加一些库。最后,将代码添加到我的项目中,它可以工作!
答案 2 :(得分:1)
我测试了https://github.com/irvingc/dbscan-on-spark并且可以说它消耗了大量内存。对于具有平滑分布的400K数据集,我使用-Xmx12084m,甚至在这种情况下它工作太长(> 20分钟)。另外,它只是2D。我使用maven项目,而不是sbt。
我测试了第二次实现。这仍然是我发现的最好的。不幸的是,作者自2015年以来就不支持它。它确实需要一些时间来提升Spark的版本并解决版本冲突。我需要它在aws上部署。
答案 3 :(得分:0)
您还可以考虑使用提供DBSCAN实现的smile。您将必须以最直接的方式将groupBy
与mapGroups
或flatMapGroups
结合使用,然后在此处运行dbscan
。这是一个示例:
import smile.clustering._
val dataset: Array[Array[Double]] = Array(
Array(100, 100),
Array(101, 100),
Array(100, 101),
Array(100, 100),
Array(101, 100),
Array(100, 101),
Array(0, 0),
Array(1, 0),
Array(1, 2),
Array(1, 1)
)
val dbscanResult = dbscan(dataset, minPts = 3, radius = 5)
println(dbscanResult)
// output
DBSCAN clusters of 10 data points:
0 6 (60.0%)
1 4 (40.0%)
Noise 0 ( 0.0%)
如果需要提高性能,还可以编写用户定义的聚合函数(UDAF)。
我在工作中使用这种方法对时间序列数据进行聚类,因此使用Spark的时间窗口功能进行分组,然后能够在每个窗口内执行DBSCAN,可以使实现并行化。
我受到以下article的启发