
networkx 中为同一节点重复赋值节点属性(如 `g.nodes[node]["date"] = value`)会直接覆盖旧值;若数据文件中存在同一节点的多条日期记录,后读取的会覆盖先读取的,导致后续校验失败。
在使用 NetworkX 构建图并加载节点属性时,一个常见但易被忽略的陷阱是:节点属性不支持自动去重或合并,而是简单覆盖。您提供的代码中,node-dates.txt 文件存在对同一 nodeID 的多行记录(例如某节点出现两次,对应不同 date 值),而程序对每行都执行:
G.nodes[int(nodeID)]["date"] = line.split()[1]
这意味着:最后一次读取到该节点的 date 值将完全取代之前所有赋值。因此,当第二次遍历 node-dates.txt 进行断言校验时,若某节点在文件中首次出现的 date 已被后续同节点的另一条记录覆盖,则 assert(G.nodes[node]["date"] == original_date) 必然失败——这正是输出中 count_failed_assert = 2446 的根本原因。
✅ 正确做法是:显式处理重复节点。推荐以下两种策略:
-
仅保留首次出现的日期(默认优先):
if int(nodeID) not in G.nodes or "date" not in G.nodes[int(nodeID)]: G.nodes[int(nodeID)]["date"] = line.split()[1] -
收集全部日期(如需多值):
date_val = line.split()[1] if "date" not in G.nodes[int(nodeID)]: G.nodes[int(nodeID)]["date"] = [date_val] # 初始化为列表 else: G.nodes[int(nodeID)]["date"].append(date_val) # 追加而非覆盖
⚠️ 注意事项:
- nx.read_edgelist() 默认不会为边中未显式出现的节点创建孤立节点;您通过 G.add_node(...) 补充节点是必要操作,但需确保属性赋值逻辑与之解耦;
- 字符串解析(如 nodeID[:2]=="11" 和 int(nodeID[2:]))建议封装为函数并添加异常处理,避免因格式异常中断流程;
- 断言失败时,建议打印具体 nodeID 和期望/实际值(而非仅计数),便于快速定位重复节点位置。
总结:NetworkX 的节点属性是纯字典映射,无内置冲突解决机制。数据预处理阶段必须校验节点唯一性——推荐先用 pandas 或原生 Python 统计 node-dates.txt 中各节点出现频次(collections.Counter),再决定采用覆盖、保留首条或聚合策略,从根本上规避静默覆盖问题。










