java - Apache Commons Math 中 DBSCAN 的自定义距离度量(v3.1 与 v3.6)
问题描述
我想使用 Apache Commons MathDBSCANClusterer<T extends Clusterable>
使用 DBSCAN 算法执行聚类,但使用自定义距离度量,因为我的数据点包含非数值。这似乎在旧版本中很容易实现(请注意,此类的完全限定名称是org.apache.commons.math3.stat.clustering.DBSCANClusterer<T>
,而它org.apache.commons.math3.ml.clustering.DBSCANClusterer<T>
适用于当前版本),现在已被弃用。在旧版本中,Clusterable
将采用 type-param, T
,描述被聚类的数据点的类型,并且两点之间的距离将由 的实现来定义Clusterable.distanceFrom(T)
,例如:
class MyPoint implements Clusterable<MyPoint> {
private String someStr = ...;
private double someDouble = ...;
@Override
public double distanceFrom(MyPoint p) {
// Arbitrary distance metric goes here, e.g.:
double stringsEqual = this.someStr.equals(p.someStr) ? 0.0 : 10000.0;
return stringsEqual + Math.sqrt(Math.pow(p.someDouble - this.someDouble, 2.0));
}
}
在当前版本中,Clusterable
不再参数化。这意味着必须想出一种方法来将一个(可能是非数字的)数据点表示为 adouble[]
并从 中返回该表示getPoint()
,例如:
class MyPoint implements Clusterable {
private String someStr = ...;
private double someDouble = ...;
@Override
public double[] getPoint() {
double[] res = new double[2];
res[1] = someDouble; // obvious
res[0] = ...; // some way of representing someStr as a double required
return res;
}
}
然后提供一个实现,根据被比较的两个点DistanceMeasure
的表示来定义自定义距离函数double[]
,例如:
class CustomDistanceMeasure implements DistanceMeasure {
@Override
public double compute(double[] a, double[] b) {
// Let's mimic the distance function from earlier, assuming that
// a[0] is different from b[0] if the two 'someStr' variables were
// different when their double representations were created.
double stringsEqual = a[0] == b[0] ? 0.0 : 10000.0;
return stringsEqual + Math.sqrt(Math.pow(a[1] - b[1], 2.0));
}
}
我的数据点的形式为(整数、整数、字符串、字符串):
class MyPoint {
int i1;
int i2;
String str1;
String str2;
}
我想使用一个距离函数/度量,它基本上说“如果str1
和/或str2
不同MyPoint mpa
,MyPoint mpb
则距离是最大的,否则距离是整数之间的欧几里德距离”,如下面的片段所示:
class Dist {
static double distance(MyPoint mpa, MyPoint mpb) {
if (!mpa.str1.equals(mpb.str1) || !mpa.str2.equals(mpb.str2)) {
return Double.MAX_VALUE;
}
return Math.sqrt(Math.pow(mpa.i1 - mpb.i1, 2.0) + Math.pow(mpa.i2 - mpb.i2, 2.0));
}
}
问题:
- 我如何将 a 表示
String
为 adouble
,以便在 Apache Commons Math 的当前版本(v3.6.1)中启用上述距离度量?String.hashCode()
是不够的,因为哈希码冲突会导致不同的字符串被认为是相等的。这似乎是一个无法解决的问题,因为我本质上是在尝试创建一个从无限字符串集到有限数值集(64bitdouble
)的唯一映射。 - 由于(1)似乎不可能,我是否误解了如何使用该库?如果是,我是不是走错路了?
- 对于这种距离度量,我唯一的选择是使用不推荐使用的版本吗?如果是,(3a)为什么设计者会选择使库不那么通用?也许有利于速度?也许是为了摆脱
class MyPoint implements Clusterable<MyPoint>
某些人可能认为设计不佳的自我参照?(我意识到这可能太自以为是了,所以如果是这样,请忽略它)。对于公共数学专家:(3b)使用不推荐使用的版本除了前向兼容性之外还有哪些缺点(不推荐使用的版本将在 4.0 中删除)?是不是比较慢?也许甚至不正确?
注意:我知道ELKI在一组 SO 用户中很受欢迎,但它不符合我的需求,因为它是作为命令行和 GUI 工具销售的,而不是包含在第三方应用程序中的 Java 库:
您甚至可以将 ELKI 嵌入到您的应用程序中(如果您接受 AGPL-3 许可),但我们目前(还)不建议这样做,因为 API 仍在发生重大变化。[...]
ELKI 并非设计为可嵌入库。它可以使用,但它不是为这种方式设计的。ELKI 有大量的选项和功能,这是有代价的,无论是在运行时(尽管它可以轻松胜过 R 和 Weka,例如!)内存使用,尤其是在代码复杂性方面。
ELKI 是为研究数据挖掘算法而设计的,而不是为了让它们易于包含在任意应用程序中。相反,如果您遇到特定问题,您应该使用 ELKI 找出哪种方法效果好,然后以针对您的问题的优化方式重新实现该方法(甚至可能在 C++ 中,以进一步减少内存和运行时间)。
解决方案
推荐阅读
- perl - 循环遍历perl中的两个文件
- python - Cython ->ValueError:未知的 MS 编译器版本 1915
- c# - Xamarin Forms:如何更改工具栏中“后退”符号的颜色
- bash - AWK递归树结构
- java - gSOAP HTTPS 连接到 java web 服务
- php - Laravel 访问数组数据
- arrays - 关联数组与多维数组,VBA
- github - 如何在 GitHub 上为组织固定存储库?
- typescript - 如何显示 VS Code 的预定义变量(例如“${workspaceFolder}”或“${fileWorkspaceFolder}”)的当前值?
- android - 将CompoundDrawablePadding() 设置为零