如何将Python NetworkX本体子图转换为RDF格式并导入Protégé
问题描述
我需要在Python中加载本体图,根据指定的目标节点列表筛选所有前驱节点生成子图,并将该子图保存为可导入Protégé软件的RDF格式(.obo或.owl)。目前我通过以下代码加载本体数据库:
url = "http://purl.obolibrary.org/obo/hp.obo" graph = obonet.read_obo(url)
已成功生成子图,代码如下:
df_nodes = pd.read_csv('./code_test.csv', header = None) nodes = list(df_nodes[0]) def predecessor_nodes(node): node_list.append(node) pred = graph.predecessors(node) for node2 in pred: return predecessor_nodes(node2) node_list = [] for node in nodes: predecessor_nodes(node) node_set = set(node_list) node_list = list(node_set) result = graph.subgraph(node_list)
但无法找到将子图保存为RDF格式的方法,请问是否可行?若不可行,能否直接在原格式下完成上述操作?
解决方案
先修正前驱节点遍历的bug
你的predecessor_nodes函数存在逻辑问题:遇到第一个前驱节点就直接return,会遗漏同一层级的其他前驱节点。正确的递归遍历方式应该是:
def predecessor_nodes(node): if node not in node_list: node_list.append(node) # 遍历所有前驱节点,递归收集 for pred_node in graph.predecessors(node): predecessor_nodes(pred_node)
这样能确保所有层级的前驱节点都被完整收集。
保存为可导入Protégé的格式
方案1:直接保存为OBO格式
obonet没有内置的子图导出API,但可以手动按照OBO格式规范生成内容,生成的文件可直接导入Protégé:
def save_subgraph_to_obo(subgraph, output_path): with open(output_path, 'w', encoding='utf-8') as f: # 写入OBO头部信息 f.write("format-version: 1.2\n") f.write("date: 2024-05-20T12:00:00Z\n") f.write("ontology: hp-subset\n") f.write("default-namespace: hp\n\n") # 遍历子图节点,写入Term块 for node_id, node_data in subgraph.nodes(data=True): f.write("[Term]\n") f.write(f"id: {node_id}\n") # 写入节点名称 if 'name' in node_data: f.write(f"name: {node_data['name']}\n") # 写入节点定义(如果有) if 'def' in node_data: f.write(f"def: {node_data['def']}\n") # 写入父节点关系 for parent_id in subgraph.predecessors(node_id): f.write(f"is_a: {parent_id}\n") # 空行分隔不同Term f.write("\n") # 调用函数保存子图 save_subgraph_to_obo(result, './hp_subset.obo')
方案2:转换并保存为OWL(RDF)格式
如果需要标准RDF格式的OWL文件,可以借助rdflib库实现:
- 将obonet图转换为RDF图
import rdflib rdf_graph = rdflib.Graph() # 定义常用的RDF/OWL术语 rdfs_subclassof = rdflib.URIRef("http://www.w3.org/2000/01/rdf-schema#subClassOf") rdfs_label = rdflib.RDFS.label iao_def = rdflib.URIRef("http://purl.obolibrary.org/obo/IAO_0000115") # 遍历obonet图的边和节点,构建RDF三元组 for u, v, key, data in graph.edges(data=True, keys=True): if key == 'is_a': rdf_graph.add((rdflib.URIRef(u), rdfs_subclassof, rdflib.URIRef(v))) # 添加节点属性(名称、定义等) for node_id, node_data in graph.nodes(data=True): node_uri = rdflib.URIRef(node_id) if 'name' in node_data: rdf_graph.add((node_uri, rdfs_label, rdflib.Literal(node_data['name']))) if 'def' in node_data: rdf_graph.add((node_uri, iao_def, rdflib.Literal(node_data['def'])))
- 筛选子图对应的RDF三元组
# 生成子图节点的URI集合 sub_node_uris = {rdflib.URIRef(node_id) for node_id in node_list} # 筛选包含子图节点的三元组 sub_rdf_graph = rdflib.Graph() for triple in rdf_graph: if triple[0] in sub_node_uris or triple[2] in sub_node_uris: sub_rdf_graph.add(triple)
- 保存为OWL格式
# 以RDF/XML格式保存,Protégé支持该格式 sub_rdf_graph.serialize(destination='./hp_subset.owl', format='xml')
补充说明
- OBO和OWL格式都能被Protégé完美识别,OBO更贴近原始本体的结构,OWL是标准RDF语义网格式,可根据需求选择。
- 如果你的本体包含更多属性(如同义词、注释等),需要在保存函数中对应添加这些属性的写入逻辑。
内容的提问来源于stack exchange,提问作者Alexandre Girard
相关产品推荐
相关产品推荐

