从网络x有向图的data set考虑以下图形结构。将上述数据集转换为树时:
拓扑排序按级别顺序给出以下输出(或多或少,这是我要查找的),但不提供有关每个节点对应的每个级别的信息。例如:n0:级别0,n2:级别1和n3:级别1等等。
print(nx.topological_sort(G))
['n2', 'n1', 'n0', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9', 'n24', 'n27', 'n21', 'n23', 'n50', 'n15', 'n14', 'n16', 'n17', 'n25', 'n18', 'n19', 'n42', 'n28', 'n38', 'n30', 'n31', 'n32', 'n39', 'n33', 'n34', 'n35', 'n36', 'n37', 'n49', 'n41', 'n40', 'n43', 'n44', 'n29', 'n22', 'n20', 'n26', 'n45', 'n48', 'n46', 'n47', 'n51', 'n54', 'n52', 'n53', 'n11', 'n10', 'n13', 'n12', 'n55']
因此,我进一步使用nextworkx.single_source_shortest_path_length()
处理数据集,并根据级别对订单进行排序。由于在图中存在多个边缘,因此单个源最短路径输出不是非常准确。
from operator import itemgetter
nd = nx.single_source_shortest_path_length(G,'n0')
sorted(nd.items(), key=itemgetter(1))
[('n0', 0),
('n12', 1),
('n13', 1),
...
('n4', 1),
('n5', 1),
('n6', 1),
('n7', 1)]
为了解决这个问题,我试图找出一种基于以下方法的解决方案:
1.通过删除冗余路径并使用single_source_shortest_path()
计算级别顺序。为了实现这一点,我可能必须删除冗余路径,以便每个节点只有一条路径,直到根(n0),通过它父。冗余路径的所有路径除了在到根节点(n0)的路上访问附近节点(父节点)的路径之外。因此,节点只能有一条到根路径(不一定是最短路径)。
例如:如果节点(n221)与父节点(n22)有边缘,而另一边节点是祖父节点(n或n2),则删除所有边缘{s}到祖父节点(删除边缘n221 --- > n),如果父(n22)具有祖父母的边(n22 ---> n)。
nx.topological_sort(G)
和nx.bfs_successors(G, 'n0')
重建更简单的树,类似于this question 最终希望获得以下结果以从根目录n0开始迭代每个级别:
Levels: nodes
1: n0
2: n3, n21
3: n4
4: n5
6: n7, n15 ...
7: ...
为了达到正确的结果,我在这里失去了什么,我怎样才能达到预期的行为?
我正在处理具有~1.5K节点的非常大的数据集,因此这里采用了一个简单的例子,而不是呈现完整的数据集。
答案 0 :(得分:2)
当叶子同时存在时,您似乎想要从叶节点(已定义here)中删除任何边到根节点:
上面的G
图表有点凌乱,与您的图片'完全匹配。描写。 (例如,n511未显示)
import matplotlib as plt
import networkx as nx
pos=nx.drawing.nx_pydot.pydot_layout(G, prog='dot')
nx.draw(G, pos=pos, with_labels=True)
如果我理解正确,这个解决方案可能有所帮助。它遍历叶子并检查叶子是否具有到根节点的> 1路径。嵌套if条件检查leaf
与根节点'n'
removed = []
for leaf in (x for x in G.nodes_iter() if G.out_degree(x)==0 and G.in_degree(x)>=1):
if sum(1 for _ in nx.all_simple_paths(G, 'n', leaf)) >1: # equivalent to len(generator)
if G.has_edge('n',leaf):
removed.append(('n', leaf)) # shows edges removed
G.remove_edge('n', leaf)
print(removed)
[('n', 'n221'), ('n', 'n51'), ('n', 'n131')]
它清理图表,如果节点'n'
不是真正的根,这可能会中断。
pos=nx.drawing.nx_pydot.pydot_layout(G, prog='dot')
nx.draw(G, pos=pos, with_labels=True)
修改强>
这是我的最后一次尝试,可能应该将此留给更有经验的人回答。尝试迭代节点并提取从根到节点的最长路径。必须有更好的方法来执行此操作,也许有人可以推荐。
假设G
是根据您在评论中提供的链接中的代码创建的。
G1 = nx.DiGraph()
for n in nodes:
if n == 'n0': # skip n0
continue
if not nx.has_path(G, 'n0', n): #n1 and n2 are disconnected from n0
lpath= max(list(nx.all_simple_paths(G, n, 'n55')), key=len)
G1.add_path(lpath)
continue
lpath= max(list(nx.all_simple_paths(G, 'n0', n)), key=len)
G1.add_path(lpath)
#levels
sorted(nx.shortest_path_length(G1, 'n0').items(), key=operator.itemgetter(1)) # omits n1, n2
[('n0', 0),
('n21', 1),
('n3', 1),
('n4', 2),
('n5', 3),
('n15', 4),
('n24', 4),
('n6', 4),
('n7', 4),
('n8', 5),
('n12', 6),
(...
plt.figure(figsize=(20,12))
pos=nx.drawing.nx_pydot.pydot_layout(G1, prog='dot')
nx.draw(G1, pos=pos, with_labels=True)
答案 1 :(得分:1)
我不确定我理解你的问题,但我认为你想要的只是从根到图中任何节点只有一条路径。
如果这是您的要求,那么实现它的唯一方法就是使用树。如果我理解正确,您还希望所有剩余路径都是根目录中最短的路径,在这种情况下,您正在寻找的树就是BFS树。
你可以在NetworkX中得到它:
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([('n', 'n1'), ('n', 'n2'), ('n', 'n3'), ('n', 'n4'), ('n', 'n5')])
G.add_edges_from([('n4', 'n41'), ('n1', 'n11'), ('n1', 'n12'), ('n1', 'n13'), ('n5', 'n51'), ('n12', 'n131')])
G.add_edges_from([('n2', 'n21'), ('n2', 'n22'), ('n', 'n221'), ('n', 'n51')])
G.add_edges_from([('n13', 'n131'), ('n22', 'n221'), ('n', 'n131'), ('n', 'n221'), ('n', 'n511')])
G = nx.bfs_tree(G, 'n')
nx.draw(G, with_labels=True)
产生类似这样的东西: