python - example - Extracción de grupos de mapas de conglomerados marinos
scipy cluster hierarchy example python (2)
Probablemente desee una nueva columna en su marco de datos con la membresía del clúster. He logrado hacer esto desde fragmentos de código ensamblados de toda la web:
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
Así que esto le da una columna con ''g'' o ''r'' para los grupos marcados en verde o rojo. Determino mi umbral de color trazando el dendrograma y observando los valores del eje y.
Estoy utilizando el seaborn clustermap
para crear clústeres y visualmente funciona muy bien (este example produce resultados muy similares).
Sin embargo, estoy teniendo problemas para averiguar cómo extraer los clústeres mediante programación. Por ejemplo, en el enlace de ejemplo, ¿cómo podría descubrir que 1-1 rh, 1-1 lh, 5-1 rh, 5-1 lh es un buen grupo? Visualmente es fácil. Estoy tratando de usar métodos para examinar los datos y los dendrogramas, pero estoy teniendo poco éxito.
EDITAR código del ejemplo:
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)
¿Cómo puedo extraer qué modelos hay en qué grupos de result
?
EDIT2 El result
conlleva un linkage
con el dendrogram_col
que creo que funcionaría con fcluster . Pero el valor de umbral para seleccionar que me confunde. ¿Supondría que los valores en el mapa de calor que son más altos que el umbral se agruparían juntos?
Si bien actualmente funciona result.linkage.dendrogram_col
o result.linkage.dendrogram_row
, parece ser un detalle de implementación. La ruta más segura es primero calcular los enlaces explícitamente y pasarlos a la función clustermap
, que tiene parámetros de row_linkage
y col_linkage
solo para eso.
Reemplazar la última línea en su ejemplo ( result =
...) con el siguiente código da el mismo resultado que antes, pero también tendrá variables row_linkage
y col_linkage
que puede usar con fcluster
etc.
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)
En este ejemplo particular, el código podría simplificarse más, ya que la matriz de correlaciones es simétrica y, por row_linkage
tanto, row_linkage
y col_linkage
serán idénticos.
Nota: una respuesta anterior incluía una llamada a distance.squareshape
según lo que hace el código en seaborn, pero eso es un error .