从seaborn clustermap中提取聚类

35

我正在使用seaborn clustermap创建聚类图表,视觉效果很好(此示例生成非常相似的结果)。

但是,我无法找出如何编程提取这些聚类。例如,在示例链接中,我该如何找到1-1 rh、1-1 lh、5-1 rh和5-1 lh形成了一个好的聚类?在视觉上很容易,但我试图使用查看数据和树状图的方法,但一直没有成功。

编辑 示例代码:

import pandas as pd
import seaborn as sns
sns.set(font="monospace")

df = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)
used_networks = [1, 5, 6, 7, 8, 11, 12, 13, 16, 17]
used_columns = (df.columns.get_level_values("network")
                          .astype(int)
                          .isin(used_networks))
df = df.loc[:, used_columns]

network_pal = sns.cubehelix_palette(len(used_networks),
                                    light=.9, dark=.1, reverse=True,
                                    start=1, rot=-2)
network_lut = dict(zip(map(str, used_networks), network_pal))

networks = df.columns.get_level_values("network")
network_colors = pd.Series(networks).map(network_lut)

cmap = sns.diverging_palette(h_neg=210, h_pos=350, s=90, l=30, as_cmap=True)

result = sns.clustermap(df.corr(), row_colors=network_colors, method="average",
               col_colors=network_colors, figsize=(13, 13), cmap=cmap)
如何从result中提取哪些模型在哪些簇中? EDIT2 result中带有与dendrogram_col相关的linkage,我认为这可以与fcluster一起使用。但是选择阈值的值让我感到困惑。我会假设热图中高于阈值的值会被聚类在一起?
2个回答

25
使用result.linkage.dendrogram_colresult.linkage.dendrogram_row目前可以工作,但似乎是实现细节。最安全的方法是首先显式计算链接,并将它们传递给clustermap函数,该函数具有row_linkagecol_linkage参数。

用以下代码替换您示例中的最后一行(result = ...),将得到与以前相同的结果,但您还将拥有row_linkagecol_linkage变量,您可以将它们与fcluster等一起使用。

from scipy.spatial import distance
from scipy.cluster import hierarchy

correlations = df.corr()
correlations_array = np.asarray(df.corr())

row_linkage = hierarchy.linkage(
    distance.pdist(correlations_array), method='average')

col_linkage = hierarchy.linkage(
    distance.pdist(correlations_array.T), method='average')

sns.clustermap(correlations, row_linkage=row_linkage, col_linkage=col_linkage, row_colors=network_colors, method="average",
               col_colors=network_colors, figsize=(13, 13), cmap=cmap)

在这个特定的例子中,代码可以更加简化,因为相关数组是对称的,因此row_linkagecol_linkage将是相同的。
注意:先前的答案包括调用distance.squareshape,根据seaborn中的代码,但那是一个错误

嘿@Marcel M,你不想使用“不相似矩阵”而不是相关矩阵吗?例如1-np.abs(correlations)之类的东西? - O.rka
2
@O.rka 将相关性传递给sns.clustermap()是来自于问题中引用的seaborn示例,我只是复制了它。两个版本都计算相关性之间的距离,因此最终实际上使用的是距离,但我承认我不知道这样做有多少意义(我不知道为什么seaborn示例会这样做)。在我的项目中,我直接使用距离。 - Marcel M

8
您可能希望在数据框中加入新的一列,以表示簇的成员关系。我从网络上搜集了各处代码片段,并成功地完成了这个任务:
import seaborn
import scipy

g = seaborn.clustermap(df,method='average')
den = scipy.cluster.hierarchy.dendrogram(g.dendrogram_col.linkage,
                                         labels = df.index,
                                         color_threshold=0.60)  
from collections import defaultdict

def get_cluster_classes(den, label='ivl'):
    cluster_idxs = defaultdict(list)
    for c, pi in zip(den['color_list'], den['icoord']):
        for leg in pi[1:3]:
            i = (leg - 5.0) / 10.0
            if abs(i - int(i)) < 1e-5:
                cluster_idxs[c].append(int(i))

    cluster_classes = {}
    for c, l in cluster_idxs.items():
        i_l = [den[label][i] for i in l]
        cluster_classes[c] = i_l

    return cluster_classes

clusters = get_cluster_classes(den)

cluster = []
for i in df.index:
    included=False
    for j in clusters.keys():
        if i in clusters[j]:
            cluster.append(j)
            included=True
    if not included:
        cluster.append(None)

df["cluster"] = cluster

这将为您提供一个包含绿色或红色聚类群集的列。我通过绘制树状图并观察y轴值来确定我的color_threshold。


1
这在更大的数据上不起作用,因为组数比颜色多,例如绿色会重复出现,这将分组颜色。 - PvdL
1
要了解此代码的工作原理,可以在此处查看“原始”帖子:http://www.nxn.se/valent/extract-cluster-elements-by-color-in-python - Dataman
@Dataman 最好是原作者得到了应有的荣誉,我在发布代码片段时已经忘记了原始来源,并且不记得是否在发布前对原始代码进行了任何重大更改。 - sjc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接