在 Python 中使用自定义距离函数对任意对象进行聚类

Posted

技术标签:

【中文标题】在 Python 中使用自定义距离函数对任意对象进行聚类【英文标题】:Clustering arbitrary objects with custom distance function in Python 【发布时间】:2021-08-01 23:00:54 【问题描述】:

我有一个 Python 对象列表,我想将这些对象聚集到未知数量的组中。对象不能简单地通过 scikit-learn 提出的任何距离函数进行比较,而是通过自定义的距离函数进行比较。我正在使用 scikit-learn 库中的 DBSCAN,当在我的数据上运行时会引发 TypeError。

这是错误代码的样子。我要聚类的对象是“补丁”对象,通过扫描 3d 网格获得:

from sklearn.cluster import DBSCAN

def getPatchesSimilarity(patch1, patch2):
    ... #Logic to calculate distance between patches
    return dist 

#Reading the data (a mesh object) and extracting its patches
mesh = readMeshFromFile("foo.obj")
patchesList = extractPatchesFromMesh(mesh)

clustering = DBSCAN(metric = getPatchesSimilarity).fit(np.array([[patch] for patch in meshPatches]))

运行时,此代码会产生以下错误:

TypeError: float() argument must be a string or a number, not 'Patch'

这似乎意味着 scikit-learn 提出的 DBSCAN 算法不适用于非向量或字符串的值?

我也尝试只使用补丁的索引,以便传递的数据是数字的,但它也不起作用。现在最后一个可行的解决方案是使用距离矩阵,但是对象的数量非常大,我的计算机无法存储这样的矩阵。

【问题讨论】:

【参考方案1】:

简短的回答:两个部分都否。

    “Adding an API for user-defined distance functions in clustering”自 2012 年以来一直是一个未解决的问题。(编辑:我错过了一部分:DBSCAN 确实支持传递 metric 可调用,但这仍然必须是相对于矢量表示完成)。 对.fit 的任何调用都必须成功通过check_array

一种解决方案是实现一种将对象转换为列表/向量的方法:

import numpy as np
data = np.array([[-0.538,-0.478,-0.374,-0.338,-0.346,0.230,0.246,0.366,0.362,0.342],[0.471,0.559,0.411,0.507,0.631,0.579,0.467,0.475,0.543,0.659]]).T

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def to_list(self):
        return [self.x, self.y]

    def __repr__(self):
        return str(self.__class__.__name__) + "(" + str(self.x) + "," + str(self.y) + ")"

points = [Point(*xy) for xy in data]
# [Point(-0.538,0.471), Point(-0.478,0.559), ... , Point(0.342,0.659)]

然后你可以对向量表示进行聚类:

from sklearn.cluster import KMeans

points_vector = np.array([point.to_list() for point in points])
# [[-0.538  0.471]
#  [-0.478  0.559]
#  ...
#  [ 0.342  0.659]]

cluster = KMeans(n_clusters=2)
cluster.fit(points_vector)

为任意 Python 对象的列表实现聚类算法可能是可能的(我发现了一个可能很接近的 cluster 库)。如果有人尝试过,我会很感兴趣。

【讨论】:

似乎 DBSCAN 还支持使用metric='precomputed' 传递距离矩阵(这不需要向量表示,但需要预先计算,当然)

以上是关于在 Python 中使用自定义距离函数对任意对象进行聚类的主要内容,如果未能解决你的问题,请参考以下文章

具有自定义距离的层次聚类

Day21-自定义simple_tag

python中怎样定义一个函数来计算两点距离?

对纬度/经度对使用自定义距离度量进行聚类

在 Python 中使用 multiprocessing.Pool 和返回自定义对象的函数

C++ 支持向量机 (SVM) 模板库?