12

Używam seaborn clustermap do tworzenia klastrów i wizualnie działa świetnie (to example daje bardzo podobne wyniki).Wyodrębnianie klastrów z selorn clustermap

Jednak mam problem z ustaleniem, jak programowo wyodrębnić klastry. Na przykład, w przykładowym łączu, jak mogę się dowiedzieć, że 1-1 rh, 1-1 lh, 5-1 rh, 5-1 lh tworzą dobre skupienie? Wizualnie to łatwe. Próbuję użyć metody pominie danych oraz dendrogramów ale mam mały sukces

EDIT kod z przykładu:

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) 

Jak mogę wyciągnąć co modele są w klastrach, które się z result?

EDIT2result niesie z nim linkage wz dendrogram_col który myślę, że praca z fcluster. Ale wartość progowa do wyboru jest myląca. Zakładam, że wartości w mapie termicznej, które są wyższe niż próg, zostaną zebrane razem?

Odpowiedz

10

Podczas pracy z result.linkage.dendrogram_col lub result.linkage.dendrogram_row będzie działać, wydaje się być szczegółem realizacji. Najbezpieczniejszą drogą jest najpierw jednoznaczne wyliczenie powiązań i przekazanie ich do funkcji clustermap, która ma parametry row_linkage i col_linkage.

Wymiana ostatni wiersz w swoim przykładzie (result = ...) za pomocą następującego kodu daje taki sam efekt jak poprzednio, ale będzie również row_linkage i col_linkage zmienne, które można używać z fcluster itp

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) 

W tym konkretnym przykładzie kod można uprościć bardziej, ponieważ tablica korelacji jest symetryczna, a zatem row_linkage i col_linkage będą identyczne.

Uwaga: poprzedniej odpowiedzi zawarte wezwanie do distance.squareshape według tego, co kod w Seaborn robi, ale że is a bug.

+0

Hej @Marcel M, czy nie chciałbyś użyć "matrycy odmienności" zamiast macierzy korelacji? Jak '1 - np.abs (korelacje)' czy coś takiego? –

+1

@ O.rka Przekazywanie korelacji do 'sns.clustermap()' pochodzi z przykładu seaborn cytowanego w pytaniu, które właśnie skopiowałem. Obie wersje obliczają odległości między korelacjami, więc na koniec w rzeczywistości są używane odległości, ale przyznaję, że nie wiem, jak wiele to robi (nie wiem, dlaczego robi to przykład). W moim własnym projekcie używam odległości bezpośrednio. –

3

Prawdopodobnie chcesz mieć nową kolumnę w ramce danych z członkostwem w klastrze. Udało mi się to zrobić z zmontowane fragmenty kodu skradzionych z całej sieci:

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 

Więc to daje kolumnę z „g” lub „R” dla zielono lub czerwono znakowany klastrów. Ustalam moją kolorową próg, wykreślając dendrogram i przyglądając się wartościom osi y.

+0

To nie będzie działać na większych danych, gdzie jest więcej grup niż kolorów, ponieważ (na przykład) zielony się powtórzy, to będzie grupować kolory. – PvdL