我有一个带有许多 2 阶节点的图(从 Linestring 派生)。为了简化图形,我想将其简化为度数不等于 2 但仍包含相同整体连接的节点。您可以在下图中找到我的意思的示例。 所以如果在度数为 3 的两个节点之间有多个节点 mit degree=2,则应该删除中间的所有节点和边,并在两个 deg=3 节点之间建立一个与权重相同的连接。省略边的总和。
adslfly 回答:减少 nedworkx 中图的节点/边数
您可以通过以下方式识别链:1) 归纳出仅包含度数为 2 的节点的子图,以及 2) 然后识别归纳子图中的各个组件。然后只需将每个链中的权重相加,并在连接到链端点的节点之间创建具有该权重的新边。
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
def contract(g):
"""
Contract chains of neighbouring vertices with degree 2 into a single edge.
Arguments:
----------
g -- networkx.Graph or networkx.DiGraph instance
Returns:
--------
h -- networkx.Graph or networkx.DiGraph instance
the contracted graph
"""
# create subgraph of all nodes with degree 2
is_chain = [node for node,degree in g.degree() if degree == 2]
chains = g.subgraph(is_chain)
# contract connected components (which should be chains of variable length) into single node
components = list(nx.components.connected_component_subgraphs(chains))
hyper_edges = []
for component in components:
end_points = [node for node,degree in component.degree() if degree < 2]
candidates = set([neighbor for node in end_points for neighbor in g.neighbors(node)])
connectors = candidates - set(list(component.nodes()))
hyper_edge = list(connectors)
weights = [component.get_edge_data(*edge)['weight'] for edge in component.edges()]
hyper_edges.append((hyper_edge,np.sum(weights)))
# initialise new graph with all other nodes
not_chain = [node for node in g.nodes() if not node in is_chain]
h = g.subgraph(not_chain).copy()
for hyper_edge,weight in hyper_edges:
h.add_edge(*hyper_edge,weight=weight)
return h
# create weighted graph
edges = np.random.randint(0,20,size=(int(400*0.2),2))
weights = np.random.rand(len(edges))
g = nx.Graph()
for edge,weight in zip(edges,weights):
g.add_edge(*edge,weight=weight)
h = nx.algorithms.minimum_spanning_tree(g)
# contract
i = contract(h)
# plot
pos = nx.spring_layout(h)
fig,(ax1,ax2) = plt.subplots(1,2,sharex=True,sharey=True)
nx.draw(h,pos=pos,ax=ax1)
nx.draw(i,ax=ax2)
plt.show()