我有3个维度的大量向量。我需要根据欧几里德距离对这些进行聚类,使得任何特定聚类中的所有向量彼此之间的欧几里德距离小于阈值“T”。
我不知道有多少个集群存在。最后,可能存在不属于任何聚类的个别向量,因为其欧氏距离不小于空间中任何向量的“T”。
这里应该使用哪些现有算法/方法?
答案 0 :(得分:68)
您可以使用hierarchical clustering。这是一种相当基本的方法,因此有很多实现可用。例如,它包含在Python的scipy中。
例如,请参阅以下脚本:
import matplotlib.pyplot as plt
import numpy
import scipy.cluster.hierarchy as hcluster
# generate 3 clusters of each around 100 points and one orphan point
N=100
data = numpy.random.randn(3*N,2)
data[:N] += 5
data[-N:] += 10
data[-1:] -= 20
# clustering
thresh = 1.5
clusters = hcluster.fclusterdata(data, thresh, criterion="distance")
# plotting
plt.scatter(*numpy.transpose(data), c=clusters)
plt.axis("equal")
title = "threshold: %f, number of clusters: %d" % (thresh, len(set(clusters)))
plt.title(title)
plt.show()
产生类似于下图的结果。
作为参数给出的阈值是距离值,在该距离值的基础上决定点/群集是否将合并到另一个群集中。也可以指定使用的距离度量。
注意,有多种方法可用于计算簇内/簇间相似性,例如,最近点之间的距离,最远点之间的距离,到集群中心的距离等。 scipys层次聚类模块(single/complete/average... linkage)也支持其中一些方法。根据你的帖子,我认为你会想要使用complete linkage。
请注意,如果小(单点)群集不符合其他群集的相似性标准,即距离阈值,则此方法也允许这些群集。
还有其他算法表现更好,这些算法在有大量数据点的情况下会变得相关。正如其他答案/评论所示,您可能还想查看DBSCAN算法:
有关这些和其他聚类算法的精彩概述,还可以查看此演示页面(Python的scikit-learn库):
从该地方复制的图片:
如您所见,每种算法都会对需要考虑的群集的数量和形状做出一些假设。无论是算法强加的隐含假设还是参数化指定的明确假设。
答案 1 :(得分:21)
moooeeeep的答案建议使用分层聚类。我想详细说明如何选择聚类的阈值。
一种方法是根据不同的阈值计算聚类 t1 , t2 , t3 ,...然后计算一个指标聚类的“质量”。前提是具有最佳数量的聚类的聚类质量将具有质量度量的最大值。
我过去使用的优质指标的一个例子是Calinski-Harabasz。简而言之:您计算群集间平均距离并将其除以群集内距离。最佳聚类分配将具有彼此分离最多的聚类,以及“最紧密”的聚类。
顺便说一下,您不必使用分层聚类。您还可以使用 k -means之类的内容,为每个 k 预先计算它,然后选择具有最高Calinski-Harabasz分数的 k
如果您需要更多参考资料,请告诉我,我会在硬盘上搜索一些文件。
答案 2 :(得分:11)
查看DBSCAN算法。它基于矢量的局部密度聚类,即它们必须不超过一些ε距离,并且可以自动确定聚类的数量。它还将异常值(即具有不足数量的ε - 邻居的点)视为不属于群集的一部分。维基百科页面链接到一些实现。
答案 3 :(得分:0)
使用OPTICS,它适用于大型数据集。
OPTICS:确定聚类结构的排序点与DBSCAN紧密相关,找到高密度的核心样本并从中1扩展聚类。与DBSCAN不同,保留集群层次结构用于可变的邻域半径。比当前的DBSCAN sklearn实现更适合用于大型数据集
from sklearn.cluster import OPTICS
db = DBSCAN(eps=3, min_samples=30).fit(X)
根据您的要求微调 eps,min_samples 。
答案 4 :(得分:0)
您可能没有解决方案:任何两个不同的输入数据点之间的距离始终大于T就是这种情况。如果您只想根据输入数据计算聚类数,则可以查看MCG,具有自动停止条件的分层聚类方法:请参见https://hal.archives-ouvertes.fr/hal-02124947/document上的免费研讨会论文(包含书目参考)。
答案 5 :(得分:0)
我想通过使用层次聚类来增加moooeeeep的答案。 尽管选择阈值非常“随机”,但此解决方案对我有用。 通过参考其他来源并自己进行测试,我得到了更好的方法,并且可以通过树状图轻松选择阈值:
from scipy.cluster import hierarchy
from scipy.spatial.distance import pdist
import matplotlib.pyplot as plt
ori_array = ["Your_list_here"]
ward_array = hierarchy.ward(pdist(ori_array))
dendrogram = hierarchy.dendrogram(hierarchy.linkage(ori_array, method = "ward"))
plt.title('Dendrogram')
plt.xlabel('Customers')
plt.ylabel('Euclidean distances')
plt.show()
您将看到这样的情节 click here。 然后通过画一条水平线,假设在distance = 1处,连词的数量将成为您想要的聚类数量。因此,我在这里为4个群集选择阈值= 1。
threshold = 1
clusters_list = hierarchy.fcluster(ward_array, threshold, criterion="distance")
print("Clustering list: {}".format(clusters_list))
现在cluster_list中的每个值将是ori_array中对应点的已分配cluster-id。