12

Desidero colorare i miei cluster con una mappa dei colori che ho creato sotto forma di un dizionario (ad esempio {leaf: color}).Colori cluster personalizzati del dendrogramma SciPy in Python (link_color_func?)

Ho provato a seguire https://joernhees.de/blog/2015/08/26/scipy-hierarchical-clustering-and-dendrogram-tutorial/ ma i colori sono incasinati per qualche motivo. La trama di default sembra buona, voglio solo assegnare quei colori in modo diverso. Ho visto che c'era un link_color_func ma quando ho provato ad usare la mia mappa dei colori (dizionario D_leaf_color) ho ricevuto un errore b/c che non era una funzione. Ho creato D_leaf_color per personalizzare i colori delle foglie associate a particolari cluster. Nel mio set di dati effettivo, i colori significano qualcosa, quindi mi sto allontanando da assegnazioni di colori arbitrarie.

Non voglio usare color_threshold b/c nei miei dati effettivi, ho molto più cluster e SciPy ripete i colori, quindi questa domanda. . .

Come posso utilizzare il mio dizionario foglia-colore per personalizzare il colore dei miei cluster di dendrogrammi?

ho fatto un problema GitHub https://github.com/scipy/scipy/issues/6346 dove ho ulteriormente elaborati sull'approccio per colorare le foglie in Interpreting the output of SciPy's hierarchical clustering dendrogram? (maybe found a bug...), ma non riesco ancora a capire come in realtà sia: (i) utilizzare l'uscita dendrogramma di ricostruire la mia dendrogram con il mio specificato dizionario colori o (ii) riformattare il dizionario D_leaf_color per il parametro link_color_func.

# Init 
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as sns; sns.set() 

# Load data 
from sklearn.datasets import load_diabetes 

# Clustering 
from scipy.cluster.hierarchy import dendrogram, fcluster, leaves_list 
from scipy.spatial import distance 
from fastcluster import linkage # You can use SciPy one too 

%matplotlib inline 

# Dataset 
A_data = load_diabetes().data 
DF_diabetes = pd.DataFrame(A_data, columns = ["attr_%d" % j for j in range(A_data.shape[1])]) 

# Absolute value of correlation matrix, then subtract from 1 for disimilarity 
DF_dism = 1 - np.abs(DF_diabetes.corr()) 

# Compute average linkage 
A_dist = distance.squareform(DF_dism.as_matrix()) 
Z = linkage(A_dist,method="average") 

# Color mapping 
D_leaf_colors = {"attr_1": "#808080", # Unclustered gray 

       "attr_4": "#B061FF", # Cluster 1 indigo 
       "attr_5": "#B061FF", 
       "attr_2": "#B061FF", 
       "attr_8": "#B061FF", 
       "attr_6": "#B061FF", 
       "attr_7": "#B061FF", 

       "attr_0": "#61ffff", # Cluster 2 cyan 
       "attr_3": "#61ffff", 
       "attr_9": "#61ffff", 
       } 

# Dendrogram 
# To get this dendrogram coloring below `color_threshold=0.7` 
D = dendrogram(Z=Z, labels=DF_dism.index, color_threshold=None, leaf_font_size=12, leaf_rotation=45, link_color_func=D_leaf_colors) 
# TypeError: 'dict' object is not callable 

enter image description here

Ho anche provato how do I get the subtrees of dendrogram made by scipy.cluster.hierarchy

+0

Non riesco a distinguere dalla descrizione cosa si intende per dendrogramma risultante * in generale * (ad es. Per un dizionario arbitrario di colori foglia). Per quanto posso dire, non ha senso specificare i colori in termini di foglie da solo, perché non si ha alcuna garanzia che le foglie che si danno allo stesso colore siano vicine l'una all'altra nel dendrogramma.Le cose nel dendrogramma che sono colorate non sono foglie; sono i collegamenti tra i cluster. Hai in qualche modo generato il tuo 'leaf_colors' dai cluster? In tal caso, non puoi invece generare i colori di collegamento dai cluster? – BrenBarn

+0

Questo è vero, ma il modo in cui ho creato il dizionario del colore foglia è utilizzando fcluster per ottenere i cluster effettivi –

+0

Ma non è possibile utilizzare una logica simile per ottenere i collegamenti e specificare i colori in termini di tali? Non è possibile ottenere i colori solo sulla base di 'fcluster', poiché' fcluster' restituisce solo i cluster * flat * e getta via le informazioni sui cluster di livello inferiore. È necessaria la struttura completa del collegamento. – BrenBarn

risposta

4

Ecco una soluzione che utilizza la matrice di ritorno Z di linkage() (descritta presto, ma un po 'nascosto nel docs) e link_color_func:

# see question for code prior to "color mapping" 

# Color mapping 
dflt_col = "#808080" # Unclustered gray 
D_leaf_colors = {"attr_1": dflt_col, 

       "attr_4": "#B061FF", # Cluster 1 indigo 
       "attr_5": "#B061FF", 
       "attr_2": "#B061FF", 
       "attr_8": "#B061FF", 
       "attr_6": "#B061FF", 
       "attr_7": "#B061FF", 

       "attr_0": "#61ffff", # Cluster 2 cyan 
       "attr_3": "#61ffff", 
       "attr_9": "#61ffff", 
       } 

# notes: 
# * rows in Z correspond to "inverted U" links that connect clusters 
# * rows are ordered by increasing distance 
# * if the colors of the connected clusters match, use that color for link 
link_cols = {} 
for i, i12 in enumerate(Z[:,:2].astype(int)): 
    c1, c2 = (link_cols[x] if x > len(Z) else D_leaf_colors["attr_%d"%x] 
    for x in i12) 
    link_cols[i+1+len(Z)] = c1 if c1 == c2 else dflt_col 

# Dendrogram 
D = dendrogram(Z=Z, labels=DF_dism.index, color_threshold=None, 
    leaf_font_size=12, leaf_rotation=45, link_color_func=lambda x: link_cols[x]) 

Qui l'output: dendrogram

+0

Hey, grazie per la tua risposta, qual è il modo migliore per lasciare le 'foglie' come' etichette'? Stavo scrivendo un dizionario all'indietro ma gli indici di 'D_leaf_colors' dal' for-loop' sono confusi. Ho molte funzioni che dipendono dagli altri, quindi gli indici lo buttano via molto –

+1

Ho appena cambiato il codice per usare le etichette foglia. :) –

+0

Ho intenzione di provare a lavorare all'indietro da questo. Le mie effettive etichette foglia sono come "F8_2/3/13_Pre", quindi usare gli indici per costruire 'link_cols' non funzionerà con i miei dati reali. Andare a scherzare e farti sapere. –

-1

ho trovato una soluzione hackish, e non richiede di utilizzare la soglia di colore (ma bisogno di utilizzare in modo da ottenere la stessa colorazione originale, altrimenti i colori non sono gli stessi presentati nell'OP), ma potrebbero portare a una soluzione. Tuttavia, potresti non avere abbastanza informazioni per sapere come impostare l'ordine della tavolozza dei colori.

# Init 
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as sns; sns.set() 

# Load data 
from sklearn.datasets import load_diabetes 

# Clustering 
from scipy.cluster.hierarchy import dendrogram, fcluster, leaves_list, set_link_color_palette 
from scipy.spatial import distance 
from fastcluster import linkage # You can use SciPy one too 

%matplotlib inline 
# Dataset 
A_data = load_diabetes().data 
DF_diabetes = pd.DataFrame(A_data, columns = ["attr_%d" % j for j in range(A_data.shape[1])]) 

# Absolute value of correlation matrix, then subtract from 1 for disimilarity 
DF_dism = 1 - np.abs(DF_diabetes.corr()) 

# Compute average linkage 
A_dist = distance.squareform(DF_dism.as_matrix()) 
Z = linkage(A_dist,method="average") 

# Color mapping dict not relevant in this case 
# Dendrogram 
# To get this dendrogram coloring below `color_threshold=0.7` 
#Change the color palette, I did not include the grey, which is used above the threshold 
set_link_color_palette(["#B061FF", "#61ffff"]) 
D = dendrogram(Z=Z, labels=DF_dism.index, color_threshold=.7, leaf_font_size=12, leaf_rotation=45, 
       above_threshold_color="grey") 

Il risultato:

enter image description here

+0

Hai eseguito questa risposta? 'link_color_func = getcolor' lancia un' KeyError'. – wflynny

+0

Sì, stavo solo cercando di capire. È corretto Gli indici vanno da 10 a 18. Forse corrisponde agli attributi da 1 a 9, la mappatura degli attributi non è corretta ma è la soluzione ... – rll

+0

Non è corretto. Gli indici 'n + 1' per' n + n' (da 10 a 18 qui) corrispondono ai cluster nella matrice di collegamento 'Z'. – wflynny

0

due-liner per l'applicazione di mappa di colori personalizzati alle filiali a grappolo:

import matplotlib as mpl 
from matplotlib.pyplot import cm 
from scipy.cluster import hierarchy 

cmap = cm.rainbow(np.linspace(0, 1, 10)) 
hierarchy.set_link_color_palette([mpl.colors.rgb2hex(rgb[:3]) for rgb in cmap]) 

Si può quindi sostituire arcobaleno da qualsiasi cmap e cambiare 10 per il numero di cluster che si desidera.

+0

Sembra che l'O.rka abbia problemi a ottenere i suoi colori, che ha definito in un dizionario nella trama. Forse potresti adattare il tuo esempio di lavoro minimo per mostrargli come è fatto. – NOhs

+0

Oh, giusto, stavo cercando me stesso come applicare una mappa colori personalizzata e non riuscivo a trovare nessuna soluzione facile. Spero che aiuti le persone a cercare quella cosa speciale;) – alelouis