NetworkX edge_betweenness_centrality未随权重变化问题求助
问题:NetworkX修改边权重后边介数中心性无变化
我尝试随机化NetworkX图的链路权重以改变网络的边介数中心性,已确认权重确实修改,但edge_betweenness_centrality函数输出未发生变化。怀疑这与节点和边附加的自定义对象有关——移除这些对象时功能正常,但代码其他部分依赖这些对象,无法删除。同时测试了load_centrality和betweenness_centrality,均存在相同问题;已验证权重输入为整数或浮点数,也尝试过直接使用权重和权重的倒数(因函数将其视为距离),该问题已困扰数周,求解决思路。
复现代码
import networkx as nx import numpy as np from itertools import combinations, groupby import random class Link(object): def __init__(self,link_id,rate,distance,network): self.link_id = link_id self.rate = rate self.distance = distance self.network = network self.buffer = [] class Node: def __init__(self,node_id,network): self.node_id = node_id self.len = 0 self.queue = [] self.network = network self.packet_delay = [] self.packets = [] def gnp_random_connected_graph(n, p): graph_seed = np.random.default_rng(2021) network = nx.Graph() node_dict = {} for node in range(n): new_node = Node(node, network) node_dict[node] = new_node network.add_nodes_from(node_dict.items()) edges = list(combinations(range(n), 2)) link_dict = {} for id, node_edges in groupby(edges, key=lambda x: x[0]): rate = random.randint(8000000,40000000) #bps distance = random.randint(10,185) #meters node_edges = list(node_edges) random_edge = tuple(graph_seed.choice(node_edges)) link_dict[random_edge] = Link(random_edge,rate,distance,network) for e in node_edges: if graph_seed.random() < p: link_dict[e] = Link(e,rate,distance,network) for key,value in link_dict.items(): nodes = list(network.nodes) network.add_edge(nodes[key[0]],nodes[key[1]],obj=value,weight=int(value.distance),rp = float(1/(value.distance))) return network def randomize_weights(network): for edge in network.edges(): rand_num = random.randint(10,100) network[edge[0]][edge[1]]['weight'] = rand_num network[edge[0]][edge[1]]['rp'] = 1/rand_num return network org_net = gnp_random_connected_graph(10,.1) #print("edges weight",nx.get_edge_attributes(org_net,'weight')) bc_dict = nx.edge_betweenness_centrality(org_net, weight='rp') print("OLD",bc_dict) new_net = randomize_weights(org_net.copy()) #print("edges weight",nx.get_edge_attributes(new_net,'weight')) new_bc_dict = nx.edge_betweenness_centrality(new_net, weight='rp') print("NEW", new_bc_dict)
问题根源与解决思路
1. 核心问题:节点添加方式错误
当前代码中network.add_nodes_from(node_dict.items())的用法不符合NetworkX规范。add_nodes_from接受的元组格式应为(节点ID, 属性字典),但你传入的是(整数ID, Node对象),这会导致NetworkX将Node对象错误解析为节点的属性结构,进而干扰后续的边关联、权重修改以及路径计算(中心性计算依赖最短路径逻辑)。
2. 修正方案
步骤1:正确添加节点与自定义属性
将Node对象作为节点的属性存储,而非错误传入add_nodes_from:
def gnp_random_connected_graph(n, p): graph_seed = np.random.default_rng(2021) network = nx.Graph() # 先添加整数ID的节点 network.add_nodes_from(range(n)) # 为每个节点绑定自定义Node对象属性 for node_id in range(n): new_node = Node(node_id, network) network.nodes[node_id]['obj'] = new_node edges = list(combinations(range(n), 2)) link_dict = {} for id, node_edges in groupby(edges, key=lambda x: x[0]): rate = random.randint(8000000,40000000) #bps distance = random.randint(10,185) #meters node_edges = list(node_edges) random_edge = tuple(graph_seed.choice(node_edges)) link_dict[random_edge] = Link(random_edge,rate,distance,network) for e in node_edges: if graph_seed.random() < p: link_dict[e] = Link(e,rate,distance,network) # 直接使用整数节点ID添加边,无需从nodes列表取值 for (u, v), link_obj in link_dict.items(): network.add_edge(u, v, obj=link_obj, weight=int(link_obj.distance), rp=float(1/link_obj.distance)) return network
步骤2:验证权重修改逻辑
修改后的randomize_weights函数无需调整,此时边的节点为整数ID,权重修改会正确关联到对应边属性:
def randomize_weights(network): for u, v in network.edges(): rand_num = random.randint(10,100) network[u][v]['weight'] = rand_num network[u][v]['rp'] = 1/rand_num return network
3. 关键注意点
- NetworkX的中心性计算依赖可哈希比较的节点标识(如整数、字符串),自定义对象作为节点ID会导致路径计算异常,进而使中心性结果无变化。
- 保留自定义Node和Link对象作为节点/边的属性,完全不影响NetworkX的算法计算,只需确保节点ID使用基础类型即可。
内容的提问来源于stack exchange,提问作者Emma Van Hoogmoed
相关产品推荐
相关产品推荐

