cómo trazar y anotar dendrogtwigs de agrupamiento jerárquico en scipy / matplotlib

Estoy usando dendrogram desde scipy para trazar un agrupamiento jerárquico usando matplotlib siguiente manera:

 mat = array([[1, 0.5, 0.9], [0.5, 1, -0.5], [0.9, -0.5, 1]]) plt.subplot(1,2,1) plt.title("mat") dist_mat = mat linkage_matrix = linkage(dist_mat, "single") print "linkage2:" print linkage(1-dist_mat, "single") dendrogram(linkage_matrix, color_threshold=1, labels=["a", "b", "c"], show_leaf_counts=True) plt.subplot(1,2,2) plt.title("1 - mat") dist_mat = 1 - mat linkage_matrix = linkage(dist_mat, "single") dendrogram(linkage_matrix, color_threshold=1, labels=["a", "b", "c"], show_leaf_counts=True) 

Mis preguntas son: primero, ¿por qué mat y 1-mat dan agrupamientos idénticos aquí? y segundo, ¿cómo puedo anotar la distancia a lo largo de cada twig del árbol utilizando el dendrogram para poder comparar las distancias entre pares de nodos?

finalmente, parece que se show_leaf_counts indicador show_leaf_counts , ¿hay alguna forma de activarlo para que se muestre el número de objetos en cada clase? Gracias. introduzca la descripción de la imagen aquí

La entrada a linkage() es una matriz nxm, que representa n puntos en el espacio tridimensional, o una matriz unidimensional que contiene la matriz de distancia condensada . En su ejemplo, mat es 3 x 3, por lo que está agrupando tres puntos 3-d. La agrupación se basa en la distancia entre estos puntos.

¿Por qué mat y 1-mat dan agrupamientos idénticos aquí?

La matriz mat y la mat 1-mat producen el mismo agrupamiento porque la agrupación se basa en distancias entre los puntos, y ni una reflexión ( -mat ) ni una traducción ( mat + offset ) de todo el conjunto de datos cambia las distancias relativas entre los puntos .

¿Cómo puedo anotar la distancia a lo largo de cada twig del árbol utilizando el dendrogtwig para poder comparar las distancias entre pares de nodos?

En el siguiente código, muestro cómo puede utilizar los datos devueltos por el dendrogtwig para etiquetar los segmentos horizontales del diagtwig con la distancia correspondiente. Los valores asociados con las teclas icoord y dcoord dan las coordenadas x e y de cada U invertida de tres segmentos de la figura. En augmented_dendrogram estos datos se utilizan para agregar una etiqueta de la distancia (es decir, el valor de y) de cada segmento de línea horizontal en el dendrogtwig.

 from scipy.cluster.hierarchy import dendrogram import matplotlib.pyplot as plt def augmented_dendrogram(*args, **kwargs): ddata = dendrogram(*args, **kwargs) if not kwargs.get('no_plot', False): for i, d in zip(ddata['icoord'], ddata['dcoord']): x = 0.5 * sum(i[1:3]) y = d[1] plt.plot(x, y, 'ro') plt.annotate("%.3g" % y, (x, y), xytext=(0, -8), textcoords='offset points', va='top', ha='center') return ddata 

Para su matriz mat , el dendrogtwig aumentado es

dendrograma para tres puntos

Así que el punto ‘a’ y ‘c’ están separados por 1.01 unidades, y el punto ‘b’ está a 1.57 unidades del grupo [‘a’, ‘c’].

Parece que se show_leaf_counts indicador show_leaf_counts , ¿hay alguna forma de activarlo para que se muestre el número de objetos en cada clase?

La bandera show_leaf_counts solo se aplica cuando no todos los puntos de datos originales se muestran como hojas. Por ejemplo, cuando trunc_mode = "lastp" , solo se muestran los últimos nodos p .

Aquí hay un ejemplo con 100 puntos:

 import numpy as np from scipy.cluster.hierarchy import linkage import matplotlib.pyplot as plt from augmented_dendrogram import augmented_dendrogram # Generate a random sample of `n` points in 2-d. np.random.seed(12312) n = 100 x = np.random.multivariate_normal([0, 0], np.array([[4.0, 2.5], [2.5, 1.4]]), size=(n,)) plt.figure(1, figsize=(6, 5)) plt.clf() plt.scatter(x[:, 0], x[:, 1]) plt.axis('equal') plt.grid(True) linkage_matrix = linkage(x, "single") plt.figure(2, figsize=(10, 4)) plt.clf() plt.subplot(1, 2, 1) show_leaf_counts = False ddata = augmented_dendrogram(linkage_matrix, color_threshold=1, p=6, truncate_mode='lastp', show_leaf_counts=show_leaf_counts, ) plt.title("show_leaf_counts = %s" % show_leaf_counts) plt.subplot(1, 2, 2) show_leaf_counts = True ddata = augmented_dendrogram(linkage_matrix, color_threshold=1, p=6, truncate_mode='lastp', show_leaf_counts=show_leaf_counts, ) plt.title("show_leaf_counts = %s" % show_leaf_counts) plt.show() 

Estos son los puntos en el conjunto de datos:

gráfico de dispersión de 100 puntos

Con p=6 y trunc_mode="lastp" , el dendrogram solo muestra la “parte superior” del dendrogtwig. A continuación se muestra el efecto de show_leaf_counts .

Mostrar efecto de show_leaf_counts

Creo que hay un par de malentendidos en cuanto al uso de las funciones que está intentando utilizar. Aquí hay un fragmento de código completamente funcional para ilustrar mis puntos:

 import matplotlib.pyplot as plt from scipy.cluster.hierarchy import dendrogram, linkage from numpy import array import numpy as np mat = array([184, 222, 177, 216, 231, 45, 123, 128, 200, 129, 121, 203, 46, 83, 83]) dist_mat = mat linkage_matrix = linkage(dist_mat, 'single') print linkage_matrix plt.figure(101) plt.subplot(1, 2, 1) plt.title("ascending") dendrogram(linkage_matrix, color_threshold=1, truncate_mode='lastp', labels=array(['a', 'b', 'c', 'd', 'e', 'f']), distance_sort='ascending') plt.subplot(1, 2, 2) plt.title("descending") dendrogram(linkage_matrix, color_threshold=1, truncate_mode='lastp', labels=array(['a', 'b', 'c', 'd', 'e', 'f']), distance_sort='descending') def make_fake_data(): amp = 1000. x = [] y = [] for i in range(0, 10): s = 20 x.append(np.random.normal(30, s)) y.append(np.random.normal(30, s)) for i in range(0, 20): s = 2 x.append(np.random.normal(150, s)) y.append(np.random.normal(150, s)) for i in range(0, 10): s = 5 x.append(np.random.normal(-20, s)) y.append(np.random.normal(50, s)) plt.figure(1) plt.title('fake data') plt.scatter(x, y) d = [] for i in range(len(x) - 1): for j in range(i+1, len(x) - 1): d.append(np.sqrt(((x[i]-x[j])**2 + (y[i]-y[j])**2))) return d mat = make_fake_data() plt.figure(102) plt.title("Three Clusters") linkage_matrix = linkage(mat, 'single') print "three clusters" print linkage_matrix dendrogram(linkage_matrix, truncate_mode='lastp', color_threshold=1, show_leaf_counts=True) plt.show() 

En primer lugar, el cálculo m -> m – 1 no cambió realmente su resultado, ya que la matriz de distancia, que básicamente describe las distancias relativas entre todos los pares únicos, no cambió en su caso específico. (En mi código de ejemplo anterior, todas las distancias son euclidianas, por lo que todas son positivas y consistentes desde puntos en un plano 2d).

Para su segunda pregunta, probablemente necesite implementar su propia rutina de anotación para hacer lo que quiera, ya que no creo que dendromgram lo respalde de forma nativa …

Para la última pregunta, show_leaf_counts parece funcionar solo cuando intentas mostrar nodos hoja no singleton con la opción truncate_mode = ‘lastp’. Básicamente, las hojas se agrupan tan juntas que no son fáciles de ver. Así que tienes la opción de mostrar solo una hoja, pero tienes la opción de mostrar (entre paréntesis) cuántos están agrupados en esa hoja.

Espero que esto ayude.