2012-10-22 10 views
8

Używam programu pydot do rysowania wykresów w pythonie. chciałbym reprezentować drzewo decyzyjne, powiedzieć coś w stylu (a1, a2, a3 są atrybuty i dwóch klas 0 i 1:pydot: czy możliwe jest wykreślenie dwóch różnych węzłów z tym samym ciągiem znaków?

 a1>3 
    / \ 
    a2>10 a3>-7 
/\ /\ 
    1 0 1 0 

Jednak użycie pydot tylko dwa liście są tworzone i drzewo wygląda następująco (png załączeniu):

 a1>3 
    / \ 
    a2>10 a3>-7 
     | X | 
     1  0 

teraz, w tym prostym przypadku logika jest w porządku, ale w większych drzew jest niechlujny węzły wewnętrzne należące do różnych gałęzi są zunifikowane

prosty kod I”. m stosuje się:

import pydot 
graph = pydot.Dot(graph_type='graph') 
edge = pydot.Edge("a_1>3", "a_2>10") 
graph.add_edge(edge) 
edge = pydot.Edge("a_1>3", "a_3>-7") 
graph.add_edge(edge) 
edge = pydot.Edge("a_2>10", "1") 
graph.add_edge(edge) 
edge = pydot.Edge("a_2>10", "0") 
graph.add_edge(edge) 
edge = pydot.Edge("a_3>-7", "1") 
graph.add_edge(edge) 
edge = pydot.Edge("a_3>-7", "0") 
graph.add_edge(edge) 
graph.write_png('simpleTree.png') 

Próbowałem też tworzenia różnych obiektów węzłów niż tworzą krawędzie i niż go dodać do wykresu, ale wydaje się, że pydot sprawdza basen węzła dla węzłów o tej samej nazwie, zamiast tworzenia nowego.

Wszelkie pomysły? dzięki!

the image created by the code above

Odpowiedz

13

Twoje węzły zawsze potrzebują unikalne nazwy, inaczej nie można nazwać je jednoznacznie dołączyć krawędzie między nimi. Można jednak nadać każdemu węzłowi etykietę, która jest wyświetlana po wyrenderowaniu.

Więc trzeba dodać węzły z unikalnymi identyfikatorami:

graph = pydot.Dot(graph_type='graph') 
graph.add_node(pydot.Node('literal_0_0', label='0')) 
graph.add_node(pydot.Node('literal_0_1', label='0')) 
graph.add_node(pydot.Node('literal_1_0', label='1')) 
graph.add_node(pydot.Node('literal_1_1', label='1')) 

następnie dodać krawędzi wykresu łączących te węzły:

edge = pydot.Edge("a_2>10", "literal_0_0") 
graph.add_edge(edge) 
edge = pydot.Edge("a_2>10", "literal_1_0") 
graph.add_edge(edge) 
edge = pydot.Edge("a_3>-7", "literal_0_1") 
graph.add_edge(edge) 
edge = pydot.Edge("a_3>-7", "literal_1_1") 
graph.add_edge(edge) 

Wraz z resztą krawędziach zdefiniowanymi to sprawia, że:

graph with correct edges

1

W "kanonicznym" odpowiedź jest użycie moduł uuid ze standardowej biblioteki, jako networkxdoes here.

To jest lepsze niż przy użyciu id do tworzenia nazw węzeł pydot które odpowiadają węzłów w swojej oryginalnej wykres, bo jeśli (w teorii) obiektu węzeł zostanie usunięty podczas budowania swój wykres pydot, to id won” t koniecznie być wyjątkowe. W przeciwieństwie do tego utworzone obiekty są unikalne, trwałe i niezależne od długości życia oryginalnych węzłów.

Jednak, aby tak się stało, musi się dziać coś bardzo dziwnego podczas tworzenia wykresu pydot, co jest raczej mało prawdopodobne. Zaletą korzystania z id jest to, że nie trzeba budować i przekazywać mapowania z oryginalnych węzłów do obiektów UUID (tak, aby po dodaniu węzłów konsekwentnie budować krawędzie).

Interesującą przypadku zagnieżdżonych wykresy: dwa różne wykresy może zawierać sam hashable obiektu w networkx (powiedzmy a), a następnie id nie mogą być montowane bezpośrednio do węzła. Ale w takim przypadku można jeszcze użyć id, łącząc parę (węzeł, wykres) jako: str(id(node)) + str(id(graph)).

Powiązane problemy