
networkx 中节点属性“丢失”通常并非保存失败,而是因数据中存在同一节点的多条属性记录,后写入的值覆盖了前值,导致断言校验不一致。本文详解该常见陷阱及安全赋值方案。
在您的代码中,G.nodes[int(nodeID)]["date"] = line.split()[1] 这一行看似无害,实则隐含关键风险:如果 node-dates.txt 文件中存在同一 nodeID 的多行记录,每次赋值都会覆盖前一次的 "date" 值。而您后续的二次遍历校验(第二次 assert)恰好读取的是文件中最后一处出现该节点的日期值,但第一次遍历时可能已将中间某次的值覆盖为其他日期——因此断言失败数(2446)正对应于被重复定义的节点数量。
这与 NetworkX 本身无关,而是数据层面的典型问题:节点属性应具有确定性,但原始数据存在“一对多”映射(一个节点对应多个日期)。NetworkX 的 G.nodes[n]["attr"] 是普通 Python 字典赋值,不提供冲突检测或合并逻辑。
✅ 正确做法:首次赋值时检查是否存在,避免意外覆盖
# 替换原赋值逻辑:
date_val = line.split()[1]
node_int = int(nodeID)
if node_int in G:
if "date" not in G.nodes[node_int]:
G.nodes[node_int]["date"] = date_val
# else: 可选择跳过、报错或记录警告
else:
G.add_node(node_int, date=date_val) # 直接初始化属性⚠️ 进阶建议:
- 预检重复节点:在加载前用 collections.Counter 统计 nodeID 出现频次,快速定位歧义数据;
-
使用结构化属性:若业务上允许多日期,可存为列表:
if "date" not in G.nodes[node_int]: G.nodes[node_int]["date"] = [] G.nodes[node_int]["date"].append(date_val) - 启用严格模式:结合 nx.set_node_attributes() 并配合 defaultdict 或校验函数,提升健壮性。
总结:NetworkX 完全忠实执行您的赋值指令——所谓“属性未保存”,本质是多次写入引发的静默覆盖。务必在数据加载阶段校验节点唯一性,并根据语义选择覆盖、跳过或聚合策略。










