Извлечение кластеров из морской кластерной карты
Я использую seaborn clustermap
для создания кластеров и визуально он отлично работает (этот example дает очень похожие результаты).
Однако мне трудно понять, как программно извлекать кластеры. Например, в примере ссылки, как я могу узнать, что 1-1 rh, 1-1 lh, 5-1 rh, 5-1 lh сделать хороший кластер? Визуально это легко. Я пытаюсь использовать методы просмотра данных и дендрограммы, но у меня мало успеха.
EDIT Код из примера:
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
выполняет с ним linkage
in с dendrogram_col
, который я THINK будет работать с fcluster. Но пороговое значение для выбора, которое меня путает. Я бы предположил, что значения в тепловой карте, превышающие порог, собираются вместе?
Ответы
Ответ 1
При использовании result.linkage.dendrogram_col
или result.linkage.dendrogram_row
в настоящее время работает, это, кажется, деталь реализации. Самый безопасный маршрут состоит в том, чтобы сначала явно вычислить связи и передать их функции clustermap
, которая имеет параметры row_linkage
и col_linkage
только для этого.
Замена последней строки в вашем примере (result =
...) следующим кодом дает тот же результат, что и раньше, но у вас также будут переменные row_linkage
и col_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_linkage
и col_linkage
будут идентичны.
Примечание. Предыдущий ответ включал вызов distance.squareshape
в соответствии с тем, что делает код в море, но является ошибкой.
Ответ 2
Вероятно, вам нужен новый столбец в вашем фреймворке данных с членством в кластере. Мне удалось сделать это из собранных фрагментов кода, украденных со всего Интернета:
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
Итак, это дает вам столбец с 'g' или 'r' для зеленых или красных помеченных кластеров. Я определяю свой color_threshold, создавая график дендрограммы и просматривая значения оси y.