我有一个有向图,想要高效地查找一个节点的所有K阶邻居节点列表。K阶邻居定义为从该节点恰好经过 K
次跳跃可以到达的所有节点。
我看了一下 networkx
,唯一相关的函数是 neighbors
,但这只返回一阶邻居。对于更高阶,我们需要迭代以确定完整集合。我相信在 networkx
中应该有一种更有效的访问K阶邻居的方式。
是否存在一种能够高效地返回 K 阶邻居而无需逐步构建集合的函数呢?
编辑:如果存在其他 Python 图形库可能在此处有用,请提及。
我有一个有向图,想要高效地查找一个节点的所有K阶邻居节点列表。K阶邻居定义为从该节点恰好经过 K
次跳跃可以到达的所有节点。
我看了一下 networkx
,唯一相关的函数是 neighbors
,但这只返回一阶邻居。对于更高阶,我们需要迭代以确定完整集合。我相信在 networkx
中应该有一种更有效的访问K阶邻居的方式。
是否存在一种能够高效地返回 K 阶邻居而无需逐步构建集合的函数呢?
编辑:如果存在其他 Python 图形库可能在此处有用,请提及。
nx.single_source_shortest_path_length(G, node, cutoff=K)
其中,G
是你的图形对象。是的,您可以获得一个节点的k阶邻域图。
subgraph = nx.ego_graph(G,node,radius=k)
然后,邻居节点就是子图中的节点。
neighbors= list(subgraph.nodes())
import networkx as nx
def knbrs(G, start, k):
nbrs = set([start])
for l in range(k):
nbrs = set((nbr for n in nbrs for nbr in G[n]))
return nbrs
if __name__ == '__main__':
G = nx.gnp_random_graph(50,0.1,directed=True)
print(knbrs(G, 0, 3))
i
个邻居,其中 i
的范围从1一直到 K
。我希望我能找到捷径。看来没有。感谢您的回复。 - Nikl
? - MERosedef neighbors_n(G, root, n):
E = nx.DiGraph()
def n_tree(tree, n_remain):
neighbors_dict = G[tree]
for neighbor, relations in neighbors_dict.iteritems():
E.add_edge(tree, neighbor, rel=relations['rel'])
#you can use this map if you want to retain functional purity
#map(lambda neigh_rel: E.add_edge(tree, neigh_rel[0], rel=neigh_rel[1]['rel']), neighbors_dict.iteritems() )
neighbors = list(neighbors_dict.iterkeys())
n_forest(neighbors, n_remain= (n_remain - 1))
def n_forest(forest, n_remain):
if n_remain <= 0:
return
else:
map(lambda tree: n_tree(tree, n_remain=n_remain), forest)
n_forest( [root] , n)
return E
{n: path for n, path in nx.single_source_shortest_path(G, 'a', cutoff=2).items() if len(path)==3}
另一种稍微更快的解决方案(使用timeit
测量,6.68 µs ± 191 ns vs. 13.3 µs ± 32.1 ns),在无向图中,邻居的邻居可以再次成为源:
def k_neighbors(G, source, cutoff):
neighbors = {}
neighbors[0] = {source}
for k in range(1, cutoff+1):
neighbors[k] = set()
for node in level[k-1]:
neighbors[k].update(set(G.neighbors(node)))
return neighbors
k_neighbors(B, 'a', 2) #dict keyed with level until `cutoff`, in this case 2
这两种解决方案都将源代码本身作为零阶邻居。
因此,取决于您的上下文环境,您可以选择其中一种。
#!/usr/bin/python
# -*- coding: utf-8 -*-
from collections import defaultdict
from collections import deque
kth_step = defaultdict(list)
class BFS:
def __init__(self, node,edges, source):
self.node = node
self.edges = edges
self.source = source
self.color=['W' for i in range(0,node)] # W for White
self.graph =color=[[False for i in range(0,node)] for j in range(0,node)]
self.queue = deque()
# Start BFS algorithm
self.construct_graph()
self.bfs_traversal()
def construct_graph(self):
for u,v in self.edges:
self.graph[u][v], self.graph[v][u] = True, True
def bfs_traversal(self):
self.queue.append((self.source, 1))
self.color[self.source] = 'B' # B for Black
kth_step[0].append(self.source)
while len(self.queue):
u, level = self.queue.popleft()
if level > 5: # limit searching there
return
for v in range(0, self.node):
if self.graph[u][v] == True and self.color[v]=='W':
self.color[v]='B'
kth_step[level].append(v)
self.queue.append((v, level+1))
'''
0 -- 1---7
| |
| |
2----3---5---6
|
|
4
'''
node = 8 # 8 nodes from 0 to 7
edges =[(0,1),(1,7),(0,2),(1,3),(2,3),(3,5),(5,6),(2,4)] # bi-directional edge
source = 0 # set fist node (0) as source
bfs = BFS(node, edges, source)
for key, value in kth_step.items():
print key, value
输出:
$ python test.py
0 [0]
1 [1, 2]
2 [3, 7, 4]
3 [5]
4 [6]
我不熟悉 networkx
,也没有在 Graph Tool 中找到现成的算法。我认为这样的问题并不常见,因此没有专门的函数来解决。而且,我认为为图实例中的任何节点存储 k-th 邻居列表会过于复杂、低效和冗余,因此这样的函数可能仍需要迭代节点。
看起来你正在寻找nx.descendants_at_distance(G, source, distance)
。
>>> G = nx.DiGraph()
>>> G.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)])
>>> nx.descendants_at_distance(G, 0, 2)
{3, 4, 5, 6}
>>> nx.descendants_at_distance(G, 5, 0)
{5}
>>> nx.descendants_at_distance(G, 5, 1)
set()