2012-03-23 10 views
22

Napisałem własną procedurę klastrowania i chciałbym stworzyć dendrogram. Najłatwiej to zrobić, używając funkcji dendrogramu scipy. Wymaga to jednak, aby dane wejściowe były w tym samym formacie, co funkcja łączenia scipy. Nie mogę znaleźć przykładu, w jaki sposób dane wyjściowe są sformatowane. Zastanawiałem się, czy ktoś tam może mnie oświecić.scipy format linkowy

+0

Zaznacz to: http://users.soe.ucsc.edu/~eads/iris.html może uda Ci pomóc! –

Odpowiedz

23

To z dokumentacji scipy.cluster.hierarchy.linkage() funkcji, to, że jest to całkiem jasne, opis formatu wyjściowego:

A ( n -1) przez 4 macierzy Z jest zwracany. W tej iteracji klastry z indeksami Z [i, 0] i Z [i, 1] są łączone w celu utworzenia klastra + n + n. Klaster o indeksie mniejszym niż n odpowiada jednej z pierwotnych obserwacji. Odległość między skupieniami Z [i, 0] i Z [i, 1] jest określona przez Z [i, 2]. Czwarta wartość Z [i, 3] reprezentuje liczbę oryginalnych obserwacji w nowo utworzonym skupieniu.

Potrzebujesz czegoś więcej?

+2

Drobna korekcja: jest to (n-1) przez 4 macierzy. – HerrKaputt

+4

Tak, więcej informacji byłoby niezwykle pomocne. Na przykład, gdybym miał wyliczyć wszystkie wskaźniki, jakie to jest przejście? Jak dokładnie są oznaczane węzły? Czy mógłbyś zadowalać się jasnym i dokładnym przykładem i krok po kroku, jak to jest sformatowane, wraz z drzewem i wszystkimi etykietami odpowiadającymi każdemu z węzłów. – mortonjt

7

Zgadzam się z https://stackoverflow.com/users/1167475/mortonjt, że dokumentacja nie wyjaśnia w pełni indeksowania klastrów pośrednich, podczas gdy ja zgadzam się z https://stackoverflow.com/users/1354844/dkar, że format jest inaczej dokładnie wyjaśniony.

na przykładzie danych z tego pytania: 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]]) 

Macierz podnośnik może być zbudowany za pomocą pojedynczego (tzn najbliższe punkty pasujące do całości):

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.  ]]) 

Jako dokumentacja wyjaśnia klastry poniżej n (tutaj: 11) są po prostu punktami danych w oryginalnej macierzy A. Klastry pośrednie idą do przodu, są kolejno indeksowane.

W ten sposób klastry 7 i 9 (pierwsze scalenie) są scalane w skupienie 11, klastry 4 i 6 w 12. Następnie obserwuj linię trzecią, łącząc klastry 5 (od A) i 12 (od niepokazywanego klastra pośredniego 12) wynikający z odległości wewnątrz klastra (WCD) równej 0,5. Pojedyncza metoda zakłada, że ​​nowe WCS wynosi 0,5, czyli odległość między A [5] a najbliższym punktem w grupie 12, A [4] i A [6]. Sprawdźmy:

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

Ten klaster powinien być teraz klastrem pośrednim 13, który następnie jest połączony z A [2]. Tak więc nowa odległość powinna być najbliższa pomiędzy punktami A [2] i 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 

Co, jak widać, sprawdza się i wyjaśnia format pośredni nowych klastrów.

4

Dokumentacja scipy jest dokładna, jak wskazał dkar ... ale trochę trudniej jest zamienić zwrócone dane w coś, co można wykorzystać do dalszej analizy.

Moim zdaniem powinny one zawierać możliwość zwracania danych w strukturze drzewa jak struktura danych.Poniższy kod będzie iterację matrycy i budowania drzewa:

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)