Python处理CSV生成Pyvis可视化数据时节点缺失问题求助
问题根因
原来的代码仅将接触发起方存入节点列表,未收录仅作为接收方存在的人员,同时没有提前存储全量人员的角色、家族属性,导致纯接收方节点无法被正确写入nodes.csv。
原生代码修复方案
修改点1:新增全量人员属性存储,补充收录接收方节点
在全局变量区域新增person_attr = {}用于存储所有人的角色、家族信息。修改generate_parsed_data函数内的节点添加逻辑:
def generate_parsed_data(): global nodes, parsed_data, person_attr print("parsing dataset:") headings = [] # 改用with自动管理文件句柄,避免资源泄漏 with open(basepath + "db.csv", "r") as excel_file, open(basepath + "proof.csv", "w") as proof_file: proof_file.write("Source,Target,Contract count,Role,Family\n") for line in excel_file: parts = line.rstrip().split(',') if not headings: headings = parts continue # 先存储当前行接收方的属性 target_name = parts[0] person_attr[target_name] = (parts[-2], parts[-1]) for name, item in zip(headings, parts): if item.isdigit(): parsed_data.append(f"{target_name},{name},{item},{parts[-2]},{parts[-1]}") proof_file.write(f"{target_name},{name},{item},{parts[-2]},{parts[-1]}\n") # 同时添加发起方和接收方到节点列表 nodes.append(target_name) nodes.append(name) nodes = list(dict.fromkeys(nodes)) print(f"总节点数:{len(nodes)}")
修改点2:重写节点生成逻辑,遍历全量节点
def generate_node_data(): global node_data print("tinkering node data:") with open(basepath + "nodes.csv", "w") as nodes_file: for node in nodes: # 从预存的属性字典取节点的角色、家族信息,无匹配时默认填未知 role, family = person_attr.get(node, ("未知", "未知")) contact_count = get_contact_count(node) node_line = f"{node},{role},{family},{contact_count}" node_data.append(node_line) node_data = list(dict.fromkeys(node_data)) for line in node_data: nodes_file.write(f"{line}\n")
更优工具选型建议
推荐直接使用pandas完成转换,代码量可缩减70%,且避免手动遍历的逻辑错误:
- 用
pandas.read_csv读取原始CSV - 用
melt函数直接将宽表(行是接收方、列是发起方)转换为边表的长表格式 - 单独提取人员属性表,批量关联计算节点的接触次数
示例代码如下:
import pandas as pd basepath = "/home/user/netmap/rc/" # 读取原始数据 df = pd.read_csv(basepath + "db.csv") # 提取人员属性表:姓名、角色、家族,将下面的「接收方列名」替换为原始CSV第一列的实际列名 person_attr = df[["接收方列名", "Role", "Family"]].set_index("接收方列名").to_dict("index") # 宽表转长表生成边数据 edge_df = df.melt(id_vars=["接收方列名", "Role", "Family"], var_name="Source", value_name="Contract count") edge_df = edge_df.rename(columns={"接收方列名": "Target"}) # 过滤接触次数为数字的有效行 edge_df = edge_df[edge_df["Contract count"].apply(lambda x: str(x).isdigit())] # 生成proof.csv edge_df.to_csv(basepath + "proof.csv", index=False) # 生成edges.csv edge_df[["Source", "Target", "Contract count"]].to_csv(basepath + "edges.csv", index=False, header=False) # 计算每个节点的接触次数 all_nodes = pd.concat([edge_df["Source"], edge_df["Target"]]).unique() node_list = [] for node in all_nodes: cnt = len(pd.concat([edge_df[edge_df["Source"]==node]["Target"], edge_df[edge_df["Target"]==node]["Source"]]).unique()) role = person_attr[node]["Role"] family = person_attr[node]["Family"] node_list.append([node, role, family, cnt]) node_df = pd.DataFrame(node_list, columns=["Name", "Role", "Family", "ContactCount"]) node_df.to_csv(basepath + "nodes.csv", index=False, header=False)
内容的提问来源于stack exchange,提问作者asatru
相关产品推荐
相关产品推荐

