You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:20:35