2012-03-23 20 views
22

He escrito mi propia rutina de agrupamiento y me gustaría producir un dendrograma. La forma más fácil de hacer esto sería usar la función de dendrograma scipy. Sin embargo, esto requiere que la entrada esté en el mismo formato que la función de enlace scipy. No puedo encontrar un ejemplo de cómo se formatea el resultado de esto. Me preguntaba si alguien por ahí puede iluminarme.scipy linkage format

+0

Comprobar esto: http://users.soe.ucsc.edu/~eads/iris.html tal vez puede ayudarle! –

Respuesta

23

Esto es de la documentación scipy.cluster.hierarchy.linkage() función, creo que es una descripción bastante claro para el formato de salida:

A (n -1) por 4 matriz Z se devuelve. En el i -ésima iteración, los clústeres con índices Z [i, 0] y Z [i, 1] se combinan para formar el clúster n + i. Un clúster con un índice inferior a n corresponde a una de las observaciones originales. La distancia entre los conglomerados Z [i, 0] y Z [i, 1] está dada por Z [i, 2]. El cuarto valor Z [i, 3] representa el número de observaciones originales en el grupo recién formado.

¿Necesitas algo más?

+2

Corrección secundaria: es una matriz (n-1) por 4. – HerrKaputt

+4

Sí, más información sería extremadamente útil. Por ejemplo, si tuviera que enumerar a través de todos los índices, ¿qué tipo de recorrido sería? ¿Cómo están etiquetados los nodos? ¿Podría por favor, si un ejemplo claro y preciso, y paso exactamente cómo se formatea esto, junto con el árbol y todas las etiquetas correspondientes a cada uno de los nodos. – mortonjt

7

Estoy de acuerdo con https://stackoverflow.com/users/1167475/mortonjt que la documentación no explica completamente la indexación de clústeres intermedios, aunque estoy de acuerdo con el https://stackoverflow.com/users/1354844/dkar que el formato se explica de otra forma con precisión.

Uso de los datos de ejemplo de esta pregunta: Tutorial for scipy.cluster.hierarchy

A = np.array([[0.1, 2.5], 
       [1.5, .4 ], 
       [0.3, 1 ], 
       [1 , .8 ], 
       [0.5, 0 ], 
       [0 , 0.5], 
       [0.5, 0.5], 
       [2.7, 2 ], 
       [2.2, 3.1], 
       [3 , 2 ], 
       [3.2, 1.3]]) 

Una matriz de ligamiento se puede construir utilizando la única (es decir, los puntos coincidentes más cercanos):

z = hac.linkage(a, method="single") 

array([[ 7.  , 9.  , 0.3  , 2.  ], 
     [ 4.  , 6.  , 0.5  , 2.  ], 
     [ 5.  , 12.  , 0.5  , 3.  ], 
     [ 2.  , 13.  , 0.53851648, 4.  ], 
     [ 3.  , 14.  , 0.58309519, 5.  ], 
     [ 1.  , 15.  , 0.64031242, 6.  ], 
     [ 10.  , 11.  , 0.72801099, 3.  ], 
     [ 8.  , 17.  , 1.2083046 , 4.  ], 
     [ 0.  , 16.  , 1.5132746 , 7.  ], 
     [ 18.  , 19.  , 1.92353841, 11.  ]]) 

Como la documentación explica la los conglomerados debajo de n (aquí: 11) son simplemente los puntos de datos en la matriz original A. Los conglomerados intermedios en el futuro se indexan sucesivamente.

Por lo tanto, los clusters 7 y 9 (la primera combinación) se fusionan en el clúster 11, los clústeres 4 y 6 en 12. Luego observe la línea tres, fusionando clústeres 5 (de A) y 12 (del clúster intermedio no mostrado 12) que resulta con una distancia dentro del conglomerado (WCD) de 0.5. El único método implica que el nuevo WCS es 0.5, que es la distancia entre A [5] y el punto más cercano en el grupo 12, A [4] y A [6]. Vamos a comprobar:

In [198]: norm([a[5]-a[4]]) 
Out[198]: 0.70710678118654757 
In [199]: norm([a[5]-a[6]]) 
Out[199]: 0.5 

Este clúster ahora debe ser el clúster intermedio 13, que posteriormente se combina con A [2]. Por lo tanto, la nueva distancia debe ser la más cercana entre los puntos A [2] y A [4,5,6].

In [200]: norm([a[2]-a[4]]) 
Out[200]: 1.019803902718557 
In [201]: norm([a[2]-a[5]]) 
Out[201]: 0.58309518948452999 
In [202]: norm([a[2]-a[6]]) 
Out[202]: 0.53851648071345048 

Que, como se puede ver, también se controla y explica el formato intermedio de los nuevos clústeres.

4

La documentación scipy es precisa, como señaló dkar ... pero es un poco difícil convertir los datos devueltos en algo que pueda utilizarse para un análisis posterior.

En mi opinión, deberían incluir la posibilidad de devolver los datos en un árbol como la estructura de datos.El código siguiente itera a través de la matriz y construir un árbol:

from scipy.cluster.hierarchy import linkage 
import numpy as np 

a = np.random.multivariate_normal([10, 0], [[3, 1], [1, 4]], size=[100,]) 
b = np.random.multivariate_normal([0, 20], [[3, 1], [1, 4]], size=[50,]) 
centers = np.concatenate((a, b),) 

def create_tree(centers): 
    clusters = {} 
    to_merge = linkage(centers, method='single') 
    for i, merge in enumerate(to_merge): 
     if merge[0] <= len(to_merge): 
      # if it is an original point read it from the centers array 
      a = centers[int(merge[0]) - 1] 
     else: 
      # other wise read the cluster that has been created 
      a = clusters[int(merge[0])] 

     if merge[1] <= len(to_merge): 
      b = centers[int(merge[1]) - 1] 
     else: 
      b = clusters[int(merge[1])] 
     # the clusters are 1-indexed by scipy 
     clusters[1 + i + len(to_merge)] = { 
      'children' : [a, b] 
     } 
     #^you could optionally store other info here (e.g distances) 
    return clusters 

print create_tree(centers)