
networkx 中为同一节点重复赋值属性(如 `date`)会直接覆盖旧值;若数据文件中存在一个节点对应多行日期记录,后读取的日期将覆盖先读取的,导致后续校验失败。
在您的代码中,问题根源并非 NetworkX 保存机制失效,而是数据本身存在一个节点对应多个 date 值的情况——即 node-dates.txt 文件中,某些 nodeID 出现了不止一次,每次携带不同的日期字符串。
您在第一遍遍历该文件时,对每个 nodeID 执行了:
G.nodes[int(nodeID)]["date"] = line.split()[1]
这属于「无条件覆盖式赋值」:无论该节点是否已有 date 属性,新值都会直接写入,旧值被静默丢弃。
而在第二遍校验时,程序按原始文件顺序再次读取同一 nodeID 的第一条记录,但此时 G.nodes[nodeID]["date"] 已被该节点在文件中最后出现的那一行所覆盖。因此,assert(G.nodes[...]["date"] == 第一行的日期) 必然失败——除非该节点仅出现一次。
您输出中的 count_failed_assert = 2446 正是这类「重复节点但首次校验值不匹配」的数量,与 num_dates = 38557(总行数)共同印证了约 6.3% 的节点存在多日期记录。
✅ 正确处理方式:避免盲目覆盖,优先保留首个/最新/或显式合并
推荐采用「首次赋值即锁定」策略(最常见需求):
# 替换原赋值逻辑:
date_val = line.split()[1]
node_int = int(nodeID)
if node_int in G:
# 仅当该节点尚未设置 date 时才赋值
if "date" not in G.nodes[node_int]:
G.nodes[node_int]["date"] = date_val
else:
G.add_node(node_int, date=date_val) # 直接初始化属性⚠️ 注意事项:
- G.nodes[node_id] 返回的是可变字典,支持原地修改,但不提供冲突检测;
- 若需保留所有日期(如时间序列),应使用列表:G.nodes[node_int].setdefault("dates", []).append(date_val);
- 使用 nx.set_node_attributes(G, values_dict, "date") 批量设置更安全,但仍要求 values_dict 键唯一;
- 建议预处理 node-dates.txt:用 pandas 或 collections.defaultdict(list) 统计重复节点,明确业务规则(取最早?最晚?去重?)后再注入图结构。
总结:NetworkX 完全忠实保存您写入的属性,所谓“未保存”实为数据层覆盖行为掩盖了多值事实。调试时应优先检查输入数据的唯一性约束,而非怀疑库的持久化能力。










