我正在尝试使用ELKI库实现DBSCAN集群测试应用程序。我的数据集是6维的,由大约100,000个对象组成。
我尝试在我的代码中使用R * -Tree ELKI优化,但是对代码进行基准测试似乎它仍然符合O(n ^ 2)。
这是我在我的应用程序中使用的代码:
ListParameterization dbscanParams = new ListParameterization();
dbscanParams.addParameter(DBSCAN.Parameterizer.EPSILON_ID, eps);
dbscanParams.addParameter(DBSCAN.Parameterizer.MINPTS_ID, minPts);
dbscanParams.addParameter(DBSCAN.DISTANCE_FUNCTION_ID, EuclideanDistanceFunction.class);
DBSCAN<DoubleVector, DoubleDistance> dbscan = ClassGenericsUtil.parameterizeOrAbort(DBSCAN.class, dbscanParams);
ArrayAdapterDatabaseConnection arrayAdapterDatabaseConnection = new ArrayAdapterDatabaseConnection(featuresMatrix, featuresLabels);
ListParameterization dbparams = new ListParameterization();
dbparams.addParameter(AbstractDatabase.Parameterizer.INDEX_ID, RStarTreeFactory.class);
dbparams.addParameter(RStarTreeFactory.Parameterizer.BULK_SPLIT_ID, SortTileRecursiveBulkSplit.class);
dbparams.addParameter(AbstractDatabase.Parameterizer.DATABASE_CONNECTION_ID, arrayAdapterDatabaseConnection);
dbparams.addParameter(AbstractPageFileFactory.Parameterizer.PAGE_SIZE_ID, pageSize);
Database db = ClassGenericsUtil.parameterizeOrAbort(StaticArrayDatabase.class, dbparams);
db.initialize();
Clustering<Model> result = dbscan.run(db);
运行上面的代码会产生以下结果:
| NUM_OBJECTS | TIME(ms) |
|-------------|------------|
| 4444 | 1508 |
| 8887 | 5547 |
| 17768 | 23401 |
| 35536 | 103733 |
| 71040 | 426494 |
| 142080 | 1801652 |
使用围绕dbscan.run(db)的简单System.currentTimeMillis()对时间进行基准测试。查看时间列,您可以看到趋势类似于n ^ 2而不是像nlog(n),但我无法理解使用ELKI DBSCAN和R * -Tree优化时所缺少的内容。
感谢您提供任何帮助或建议。
答案 0 :(得分:1)
如果您选择查询半径epsilon太大,则每个对象都会有O(n)
个邻居。
然后运行时将O(n^2)
或更糟,即使有索引支持;因为每个查询的答案大小为O(n)
。
如果您选择epsilon,平均10%的对象将在epsilon半径范围内,那么您的运行时间至少为O(n * 10% * n)
,即O(n^2)
。
很好地说明O(n log n)
的理论运行时在实践中可能不会给你O(n log n)
的运行时。对于小答案集,R * -tree可以平均在O(log n)
中回答半径或kNN个查询,其中答案集大小可以忽略不计。更精确的分析可能会产生O(log n + |answer| log |answer|)
的运行时间(因为我们目前按距离对答案进行排序;对于某些算法,我们可以删除它。)
通常,假定为O(n*n)
的算法将花费您O(n*n log n)
运行时间,因为对于每个对象,您按距离对所有其他对象进行排序。幸运的是,排序得到了很好的优化,因此额外的log n
并不重要。