如何将DataFrame存储的subclassOf层级输出为带缩进的文本列表
子类层级缩进打印问题
问题描述
我有一组subclassOf层级关系可通过DataFrame表示,其中subjects是objects的子类。我需要将该层级打印为带缩进的列表,缩进代表当前术语是上一行术语的子类。我目前使用递归函数实现,已经可以正确增加缩进,但找不到合适的位置通过减少prefix_level来回退缩进,导致输出不符合预期。欢迎提供任意解决方案,无需基于我现有的实现调整。
示例数据
构造层级关系DataFrame的代码如下:
import pandas as pd current_direct_sco = pd.DataFrame( { "subject": { 986: "ENVO:01000025", 989: "ENVO:01000028", 990: "ENVO:01000029", 991: "ENVO:01000030", 1011: "ENVO:01000050", 1014: "ENVO:01000053", 1015: "ENVO:01000054", 1096: "ENVO:01000127", 1242: "ENVO:01000252", 1243: "ENVO:01000253", }, "object": { 986: "ENVO:01000024", 989: "ENVO:01000024", 990: "ENVO:01000024", 991: "ENVO:01000024", 1011: "ENVO:01000029", 1014: "ENVO:01000030", 1015: "ENVO:01000030", 1096: "ENVO:01000024", 1242: "ENVO:00000873", 1243: "ENVO:00000873", }, } )
数据内容如下:
| 序号 | subject | object |
|---|---|---|
| 986 | ENVO:01000025 | ENVO:01000024 |
| 989 | ENVO:01000028 | ENVO:01000024 |
| 990 | ENVO:01000029 | ENVO:01000024 |
| 991 | ENVO:01000030 | ENVO:01000024 |
| 1011 | ENVO:01000050 | ENVO:01000029 |
| 1014 | ENVO:01000053 | ENVO:01000030 |
| 1015 | ENVO:01000054 | ENVO:01000030 |
| 1096 | ENVO:01000127 | ENVO:01000024 |
| 1242 | ENVO:01000252 | ENVO:00000873 |
| 1243 | ENVO:01000253 | ENVO:00000873 |
可通过igraph绘制层级结构图(需安装pycairo依赖):
import igraph as ig g = ig.Graph.TupleList( current_direct_sco.itertuples(index=False), directed=True, vertex_name_attr="label" ) ig.plot(g)
根节点计算
首先计算层级的根节点(即只作为父类出现、没有上级类的术语):
roots = list(set(current_direct_sco["object"]) - set(current_direct_sco["subject"])) print(roots)
输出结果:
['ENVO:00000873', 'ENVO:01000024']
现有实现及问题
当前递归实现代码如下:
def recurse_envo(starting_term): global prefix_level global prefix_chunk global current_prefix print(current_prefix + starting_term) current_children = list( current_direct_sco["subject"].loc[current_direct_sco["object"] == starting_term] ) if len(current_children) > 0: prefix_level = prefix_level + 1 current_prefix = prefix_chunk * prefix_level for current_child in current_children: recurse_envo(current_child) for i in roots: first_term = i prefix_level = 0 prefix_chunk = " " current_prefix = "" recurse_envo(first_term)
当前错误输出
ENVO:00000873 ENVO:01000252 ENVO:01000253 ENVO:01000024 ENVO:01000025 ENVO:01000028 ENVO:01000029 ENVO:01000050 ENVO:01000030 ENVO:01000053 ENVO:01000054 ENVO:01000127
错误原因是ENVO:01000127实际并不是ENVO:01000030的子类,缩进层级错误。
期望输出
ENVO:00000873 ENVO:01000252 ENVO:01000253 ENVO:01000024 ENVO:01000025 ENVO:01000028 ENVO:01000029 ENVO:01000050 ENVO:01000030 ENVO:01000053 ENVO:01000054 ENVO:01000127
解决方案
问题核心是使用全局变量存储缩进层级,遍历完子节点后没有回退层级值,导致后续同级节点继承了子节点的缩进层级。改为将缩进层级作为递归函数的入参传递即可解决:
prefix_chunk = " " def recurse_envo(starting_term, level=0): # 打印当前节点 print(prefix_chunk * level + starting_term) # 获取所有子节点 current_children = current_direct_sco["subject"].loc[current_direct_sco["object"] == starting_term].tolist() # 递归遍历子节点,层级+1 for child in current_children: recurse_envo(child, level + 1) # 遍历所有根节点 for root in roots: recurse_envo(root)
运行上述代码即可得到符合预期的缩进输出。
内容的提问来源于stack exchange,提问作者Mark Miller
相关产品推荐
相关产品推荐

