2015-01-23 2 views
0

я запустить эту программу:Назначение NetworkX края атрибутов/веса в Словаре

import networkx as nx 
from pylab import * 
g=nx.Graph() 

g.add_edge('a','b', weight=3) 

g.add_edge('a','c', weight=2) 

g.add_edge('b','c', weight=7) 

w=nx.get_edge_attributes(g, 'weight') 

w[('b','a')]=3 

w[('c','a')]=2 

w[('c','b')]=7 

, и я не понимаю, почему w ДИКТ содержит только 5 вместо 6 пунктов:

{('b', 'a'): 3, ('c', 'a'): 2, ('a', 'b'): 3, ('c', 'b'): 7, ('a', 'c'): 2} 

('b','c') запись не прошла ...

Что я здесь делаю неправильно?

+0

Я не могу воспроизвести вашу ошибку, но вместо этого я получаю '{('b', 'c'): 7, ('b', 'a'): 3, ('c', 'a') : 2, ('c', 'b'): 7} 'поэтому только последнее назначение сохраняется – EdChum

+0

Я отправил ответ. Я не знаю, почему так происходит, но я получил ту же ошибку, что и вы. И я немного поиграл и заметил это поведение. – ProgrammingIsAwsome

+0

Причина в том, что для неориентированных графов, когда networkx возвращает ребра, вы должны считать, что порядок узлов в каждом ребре произволен, так же, как при просмотре ключей dict, вы должны предположить, что они находятся в произвольном порядке. Точный способ появления этой проблемы будет зависеть от реализации. Мой ответ ниже дает объяснение. – Joel

ответ

1

Я узнал (после некоторых попыток и поиска кода get_edge_attribute). В этом методе здесь извлекаются ребра:

if G.is_multigraph(): 
     edges = G.edges(keys=True, data=True) 
    else: 
     edges = G.edges(data=True) 
    return dict((x[:-1], x[-1][name]) for x in edges if name in x[-1]) 

В вашем случае график не является мультиграфом. Таким образом, он создает словарь на основе списка G.edges() возвращает. Так что я сделал небольшой тест с помощью следующего кода:

g.add_edge('a','b', weight=3) 

print "edges after adding 'ab': " + str(g.edges(data=True)) 

g.add_edge('a','c', weight=2) 

print "edges after adding 'ac': " + str(g.edges(data=True)) 

g.add_edge('b','c', weight=7) 

print "edges after adding 'bc': " + str(g.edges(data=True)) 

Выход:

edges after adding 'ab': [('a', 'b', {'weight': 3})] 
edges after adding 'ac': [('a', 'c', {'weight': 2}), ('a', 'b', {'weight': 3})] 
edges after adding 'bc': [('a', 'c', {'weight': 2}), ('a', 'b', {'weight': 3}), ('c', 'b', {'weight': 7})] 

Посмотрите на последнюю строку на выходе: Мы добавили край «BC» NOT «Cb», но в список краев, нет ребра «bc», а есть край «cb». Вот почему вы не видите край «bc», потому что его нет.

Я не знаю точно, почему это так.

2

Ваш график не задан. Это основная причина проблемы.

При запуске первой части кода:

import networkx as nx 
from pylab import * 
g=nx.Graph() 

g.add_edge('a','b', weight=3) 

g.add_edge('a','c', weight=2) 

g.add_edge('b','c', weight=7) 

w=nx.get_edge_attributes(g, 'weight') 

Вы делаете w в Словаре, каждый из которых ключей является одним из краев. Но порядок узлов внутри ребра не имеет значения. Итак, давайте посмотрим на w:

w 
> {('a', 'b'): 3, ('a', 'c'): 2, ('c', 'b'): 7} 

Примечание --- вы определили вес края для ('b', 'c'). Но в w он хранится с ключом ('c','b').

Итак, когда вы определяете w[('c','b')], вы переписываете это. Этого не произошло для других ребер, потому что networkx случайным образом случалось возвращать их в том порядке, в котором вы ожидали.

Я думаю, вы пытаетесь определить w так, чтобы у вас был вес одинаковым независимо от порядка ребер, которые вы проверяете.

Это, вероятно, лучше использовать встроенную NetworkX команду, чтобы получить вес и не использовать w вообще:

g.get_edge_data('a','b')['weight'] 

Но если вы действительно хотите, чтобы ваш w, один из способов сделать это будет делать петлю через ключей w в

for edge in w: 
    w[([edge[1],edge[0])] = w[edge] 

или вы можете определить функцию

def f(edge,w): 
    if edge in w: 
     return w[edge] 
    else: 
     return w[(edge[1],edge[0]) 

Немного больше объяснений о том, что происходит:

Вы не можете предположить, что networkx вернет вам края неориентированного графа с тем же порядком, что и им. Это неориентированный граф, поэтому все, что предполагает некоторое неявное направление к краям, будет запущено.

В основном это потому, что networkx хранит узлы в структуре словаря. Из-за этого вы не можете предположить, что он возвращает узлы в любом порядке. Поэтому, в частности, в вашем случае, когда networkx ищет свои ребра, он проходит через узлы в некотором порядке. В этом случае он достигает 'c', прежде чем он доберется до 'b'. Поэтому он получает преимущество с c. Когда он достигает b, он знает, что у него уже есть этот край, поэтому он его не выпускает.