【问题标题】:Single linkage clustering of edit distance matrix with distance threshold stopping criterion具有距离阈值停止准则的编辑距离矩阵的单链接聚类
【发布时间】:2019-09-20 20:47:02
【问题描述】:

在给定平方距离矩阵的情况下,我正在尝试将平坦的单链接集群分配给由编辑距离 scipy.cluster.hierarchy.fclusterdata() 和 criterion='distance' 可能是一种方法,但它并没有完全返回我对这个玩具示例所期望的集群。

具体来说,在下面的 4x4 距离矩阵示例中,我希望 clusters_50(它使用 t=50)创建 2 个集群,实际上它找到了 3 个。我认为问题是 fclusterdata() 不期望一个距离矩阵,但 fcluster() 似乎也没有做我想要的。

我也查看了sklearn.cluster.AgglomerativeClustering,但这需要指定n_clusters,并且我想根据需要创建尽可能多的集群,直到满足我指定的距离阈值。

我看到有一个 当前未合并 scikit-learn 对这个确切功能的拉取请求:https://github.com/scikit-learn/scikit-learn/pull/9069

谁能指出我正确的方向?使用绝对距离阈值标准进行聚类似乎是一个常见的用例。

import pandas as pd
from scipy.cluster.hierarchy import fclusterdata

cols = ['a', 'b', 'c', 'd']

df = pd.DataFrame([{'a': 0, 'b': 29467, 'c': 35, 'd': 13},
                   {'a': 29467, 'b': 0, 'c': 29468, 'd': 29470},
                   {'a': 35, 'b': 29468, 'c': 0, 'd': 38},
                   {'a': 13, 'b': 29470, 'c': 38, 'd': 0}],
                  index=cols)

clusters_20 = fclusterdata(df.values, t=20, criterion='distance')
clusters_50 = fclusterdata(df.values, t=50, criterion='distance')
clusters_100 = fclusterdata(df.values, t=100, criterion='distance')

names_clusters_20 = {n: c for n, c in zip(cols, clusters_20)}
names_clusters_50 = {n: c for n, c in zip(cols, clusters_50)}
names_clusters_100 = {n: c for n, c in zip(cols, clusters_100)}
names_clusters_20  # Expecting 3 clusters, finds 3
>>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}

names_clusters_50  # Expecting 2 clusters, finds 3
>>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}

names_clusters_100 # Expecting 2 clusters, finds 2
>>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}

【问题讨论】:

    标签: python python-3.x scipy cluster-analysis bioinformatics


    【解决方案1】:

    通过将linkage() 传递给fcluster() 来解决这个问题,与fclusterdata() 不同,它支持metric='precomputed'

    fcluster(linkage(condensed_dm, metric='precomputed'), criterion='distance', t=20)
    

    解决方案:

    import pandas as pd
    from scipy.spatial.distance import squareform
    from scipy.cluster.hierarchy import linkage, fcluster
    
    cols = ['a', 'b', 'c', 'd']
    
    df = pd.DataFrame([{'a': 0, 'b': 29467, 'c': 35, 'd': 13},
                       {'a': 29467, 'b': 0, 'c': 29468, 'd': 29470},
                       {'a': 35, 'b': 29468, 'c': 0, 'd': 38},
                       {'a': 13, 'b': 29470, 'c': 38, 'd': 0}],
                      index=cols)
    
    dm_cnd = squareform(df.values)
    
    clusters_20 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=20)
    clusters_50 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=50)
    clusters_100 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=100)
    
    names_clusters_20 = {n: c for n, c in zip(cols, clusters_20)}
    names_clusters_50 = {n: c for n, c in zip(cols, clusters_50)}
    names_clusters_100 = {n: c for n, c in zip(cols, clusters_100)}
    
    names_clusters_20
    >>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}
    
    names_clusters_50
    >>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}
    
    names_clusters_100
    >>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}
    

    作为一个函数:

    import pandas as pd
    from scipy.spatial.distance import squareform
    from scipy.cluster.hierarchy import fcluster, linkage
    
    def cluster_df(df, method='single', threshold=100):
        '''
        Accepts a square distance matrix as an indexed DataFrame and returns a dict of index keyed flat clusters 
        Performs single linkage clustering by default, see scipy.cluster.hierarchy.linkage docs for others
        '''
    
        dm_cnd = squareform(df.values)
        clusters = fcluster(linkage(dm_cnd,
                                    method=method,
                                    metric='precomputed'),
                            criterion='distance',
                            t=threshold)
        names_clusters = {s:c for s, c in zip(df.columns, clusters)}
    return names_clusters
    

    【讨论】:

      【解决方案2】:

      您没有设置指标参数。

      那么默认是metric='euclidean',而不是预先计算的

      【讨论】:

      • 谢谢,但我认为这实际上不是问题所在。 fclusterdata() 不接受 metric='precomputed',因为我现在的理解是,与 fcluster() 相比,它旨在直接处理观察而不是距离矩阵。将metric='precomputed' 传递给fclusterdata() 得到ValueError: Unknown Distance Metric: precomputed
      • 嗯, fclusterdata 使用欧几里得距离的问题,它不能使用预先计算的距离矩阵(所以你需要使用另一个函数),不是是吗?
      • 请把你的讽刺带到别处——我试图表达感激之情。向下滚动查看已接受的答案,在您之前一小时发布,由我发布。
      • 没有提到metric参数是key。将来可以对 fclusterdata 进行简单的修改以接受预先计算的距离矩阵。
      • 同意 API 可以更简单和/或通过使用示例更好地记录。在接受的答案中强调了metric arg。
      猜你喜欢
      • 2016-11-18
      • 1970-01-01
      • 2016-03-20
      • 1970-01-01
      • 2014-10-24
      • 2018-11-17
      • 2013-04-21
      • 2014-07-28
      • 2014-07-09
      相关资源
      最近更新 更多