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


Estoy usando dendrogram de scipy para trazar la agrupación jerárquica usando matplotlib de la 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 rama del árbol usando dendrogram para que las distancias entre pares de nodos puedan compararse?

Finalmente parece que show_leaf_counts flag es ignorado, ¿hay alguna manera de activarlo para que se muestre el número de objetos en cada clase? gracias.introduzca la descripción de la imagen aquí

Author: tjanez, 2012-08-12

2 answers

La entrada a linkage() es una matriz n x m, que representa n puntos en m-espacio dimensional, o una matriz unidimensional que contiene el condensed distance matrix . 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í?

Los arrays mat y 1-mat producen la misma agrupación porque agrupación se basa en las distancias entre los puntos, y ni una reflexión (-mat) ni una traducción (mat + offset) de todo el conjunto de datos cambia el relativo distancias entre los puntos.

¿Cómo puedo anotar la distancia a lo largo de cada rama del árbol usando dendrograma para poder comparar las distancias entre pares de nodos?

En el siguiente código, I mostrar cómo puede utilizar los datos devueltos por dendrogram para etiquetar la horizontal segmentos del diagrama con el distancia correspondiente. Los valores asociados con las teclas icoord y dcoord dar las coordenadas x e y de cada uno u invertida de tres segmentos de la figura. En augmented_dendrogram estos datos se utiliza para agregar una etiqueta de la distancia (es decir, el valor y) de cada horizontal segmento de línea en dendrograma.

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 dendrograma aumentado es

dendrograma para tres puntos

Así que el punto ' a 'y' c 'están a 1.01 unidades de distancia, y el punto' b ' está a 1.57 unidades de el cluster ['a', "c"].

Parece que show_leaf_counts la bandera se ignora, ¿hay una manera de encenderla ¿para que se muestre el número de objetos en cada clase?

La bandera show_leaf_counts solo se aplica cuando no todos los datos originales los puntos 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

Por p=6 y trunc_mode="lastp", dendrogram solo muestra superior" del dendrograma. A continuación se muestra el efecto de show_leaf_counts.

Mostrar el efecto de show_leaf_counts

 65
Author: Warren Weckesser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:42

Creo que hay un par de malentendidos en cuanto al uso de las funciones que está tratando de usar. Aquí hay un fragmento de código que funciona completamente 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 realmente no cambió 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 soporte de forma nativa...

Para la última pregunta, show_leaf_counts parece funcionar solo cuando intenta mostrar nodos hoja no-singleton con la opción truncate_mode='lastp'. Básicamente, las hojas están agrupadas tan juntas que no son fáciles de ver. Así que usted tiene una opción de sólo mostrar una hoja, pero tienen un opción de mostrar (entre paréntesis) cuántos están agrupados en esa hoja.

Espero que esto ayude.

 14
Author: Taro Sato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-07 04:13:46