我遇到了一个聚类问题,我认为这需要一个直观的距离函数。每个实例都有一个x,y坐标,但也有一组描述它的属性(每个实例的数量不同)。理想情况下,可以传递pythonobjects(类的实例)并根据它们的内容任意比较它们。
我想将距离表示为x,y值之间的欧几里德距离的加权和,以及用于测量其他属性的集合重叠的jaccard索引。类似的东西:
dist = (euclidean(x1, y1, x2, y2) * 0.6) + (1-jaccard(attrs1, attrs2) * 0.4)
我发现大多数聚类算法和实现都将实例功能转换为数字。例如,使用sklearn中的dbscan,为了完成我的距离函数,我需要以某种方式将数字转换回原始表示。
如果可以使用可以任意方式比较实例的距离函数进行聚类,那将会很棒。例如,想象一个欧几里德距离函数,如果它们在另一个非空间特征上匹配,则会将对象评估得更近。
def dist(ins1, ins2):
euc = euclidean(ins1.x, ins1.y, ins2.x, ins2.y)
if ins1.feature1 == ins2.feature1:
euc = euc * 0.9
return euc
有没有适合的方法?如果不需要预先设置群集的数量(但这对我来说并不重要),那也很好。
答案 0 :(得分:3)
实际上,几乎所有的聚类算法(除了用于k-means,显然需要数字来计算均值)都可以用于任意距离函数。 / p>
在sklearn中,大多数算法接受metric="precomputed"
和距离矩阵而不是原始输入数据。请仔细检查文档。例如DBSCAN:
如果度量是“预先计算的”,则假定X是距离矩阵,并且必须是正方形。
您失去的是通过索引加速某些算法的能力。计算距离矩阵是O(n ^ 2),因此您的算法不能快于此。在sklearn中,您需要修改sklearn Cython代码以添加新的距离函数(不幸的是,使用pyfunc会产生非常糟糕的性能)。诸如ELKI can be extended with little overhead之类的Java工具,因为Java的Just-in-time编译器可以很好地优化它。如果您的距离是 metric ,则可以使用许多索引来加速例如DBSCAN。