【问题标题】:Get element closest to cluster centroid获取最接近簇质心的元素
【发布时间】:2017-02-07 13:27:12
【问题描述】:

在使用scipy.cluster.hierarchy.linkage 对距离矩阵进行聚类,并使用scipy.cluster.hierarchy.cut_tree 将每个样本分配到一个聚类后,我想从每个聚类中提取一个元素,该元素最接近该聚类的质心。

  • 如果有现成的功能来解决这个问题,我会很高兴,但缺少它:
  • 已经提出了一些建议here 用于提取质心本身,但不是最接近质心的元素。
  • 请注意,不要将这与scipy.cluster.hierarchy.linkage 中的centroid 链接规则相混淆。我已经自己进行了聚类,只想访问最接近质心的元素。

【问题讨论】:

    标签: python numpy scipy scikit-learn


    【解决方案1】:

    使用 KD-Trees 最有效地计算最近邻。例如:

    from scipy.spatial import cKDTree
    
    def find_k_closest(centroids, data, k=1, distance_norm=2):
        """
        Arguments:
        ----------
            centroids: (M, d) ndarray
                M - number of clusters
                d - number of data dimensions
            data: (N, d) ndarray
                N - number of data points
            k: int (default 1)
                nearest neighbour to get
            distance_norm: int (default 2)
                1: Hamming distance (x+y)
                2: Euclidean distance (sqrt(x^2 + y^2))
                np.inf: maximum distance in any dimension (max((x,y)))
    
        Returns:
        -------
            indices: (M,) ndarray
            values: (M, d) ndarray
        """
    
        kdtree = cKDTree(data, leafsize=leafsize)
        distances, indices = kdtree.query(centroids, k, p=distance_norm)
        if k > 1:
            indices = indices[:,-1]
        values = data[indices]
        return indices, values
    
    indices, values = find_k_closest(centroids, data)
    

    【讨论】:

    • 感谢您的建议。我已经研究过了,但意识到它不适合我的问题,因为我有一个“平坦”距离矩阵(由 scipy.spatial.distance.pdist 返回),其中距离以自定义类之间的非平凡方式计算对象。因此,我意识到质心在这里甚至不适用(缺少正确的笛卡尔坐标),所以我将选择与集群中其他对象的平均距离最小的那个对象。我会尽快发布我的最终解决方案。
    • 如果您使用层次聚类,那么您必须定义点之间的距离度量。只是说。
    • 是的,但它有点特别。具体来说,我有 3D 对象(3D 中的 2-4 个点)并计算它们之间的 RMS 距离,但首先我旋转并平移它们以获得最佳对齐(请注意,这意味着每对对象都有不同的旋转/平移状态) .我的距离矩阵包含这些 RMS 距离。 kdtree.query 似乎用 Minkowski 类型的规范进行了硬编码,我不知道如何实现这个“拟合和测量”例程来代替 distance_norm。但毕竟,我什至可能不需要。
    • 您需要在问题中包含此类信息!无论如何,希望你能想出办法。一切顺利。
    • 对不起,我没有意识到,但我想人们首先会想到多维数组是合乎逻辑的。尽管如此,我还是尝试了您的代码,如果 k=1,indices = idx[:,-1] 会引发SystemError: error return without exception set。我会提出以下建议: if k==1: indices=idx[:] else: indices = idx[:,-1]
    【解决方案2】:

    Paul 的上述解决方案适用于多维数组。在更具体的情况下,您有一个距离矩阵dm,其中距离以“非平凡”方式计算(例如每对对象首先在 3D 中对齐,然后是 RMSD计算),我最终从每个集群中选择了与集群中其他元素的距离总和最低的元素,aka. 集群的中心点。 (请参阅下面的讨论this 答案。)这就是我在拥有距离矩阵dm 和相同顺序的对象名称列表names 时做到的:

    import numpy as np
    import scipy.spatial.distance as spd
    import scipy.cluster.hierarchy as sch
    
    # Square form of distance matrix
    sq=spd.squareform(dm)
    # Perform clustering, capture linkage object
    clusters=sch.linkage(dm,method=linkage)
    # List of cluster assignments
    assignments=sch.cut_tree(clusters,height=rmsd_cutoff)
    # Store object names and assignments as zip object (list of tuples)
    nameList=list(zip(names,assignments))
    
    ### Extract models closest to cluster centroids
    counter=0
    while counter<num_Clusters+1:
    
        # Create mask from the list of assignments for extracting submatrix of the cluster
        mask=np.array([1 if i==counter else 0 for i in assignments],dtype=bool)
    
        # Take the index of the column with the smallest sum of distances from the submatrix
        idx=np.argmin(sum(sq[:,mask][mask,:]))
    
        # Extract names of cluster elements from nameList
        sublist=[name for (name, cluster) in nameList if cluster==counter]
    
        # Element closest to centroid
        centroid=sublist[idx]
    

    【讨论】:

    • “我最终从每个集群中选择了与集群中其他元素的距离总和最低的元素”这与查找集群的 medoid 相同吗??
    猜你喜欢
    • 2014-03-06
    • 1970-01-01
    • 2012-11-03
    • 2017-10-07
    • 2013-09-29
    • 1970-01-01
    • 2012-11-17
    • 2018-08-19
    • 2014-07-21
    相关资源
    最近更新 更多