在 Python 中使用自定义距离函数聚类任意对象
Clustering arbitrary objects with custom distance function in Python
我有一个 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 算法不适用于非向量或字符串的值?
我也试过只使用补丁的索引,这样传递的数据是数字的,但也没有用。现在最后一个可行的解决方案是使用距离矩阵,但是对象的数量确实很大,我的计算机无法存储这样的矩阵。
简答:两部分都不是。
- "Adding an API for user-defined distance functions in clustering" has been an open issue since 2012. (Edit: I missed one part:
DBSCAN
确实支持传递 metric
可调用对象,但这仍然必须针对向量表示来完成)。
- 对
.fit
的任何调用都必须成功通过 check_array
。
一个解决方案是实现一个将对象转换为 list/vector:
的方法
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
库)。如果有人试过这个,我会很感兴趣。
我有一个 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 算法不适用于非向量或字符串的值?
我也试过只使用补丁的索引,这样传递的数据是数字的,但也没有用。现在最后一个可行的解决方案是使用距离矩阵,但是对象的数量确实很大,我的计算机无法存储这样的矩阵。
简答:两部分都不是。
- "Adding an API for user-defined distance functions in clustering" has been an open issue since 2012. (Edit: I missed one part:
DBSCAN
确实支持传递metric
可调用对象,但这仍然必须针对向量表示来完成)。 - 对
.fit
的任何调用都必须成功通过check_array
。
一个解决方案是实现一个将对象转换为 list/vector:
的方法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
库)。如果有人试过这个,我会很感兴趣。