【问题标题】:Creating hierarchical tree from nested dictionary in python从python中的嵌套字典创建层次树
【发布时间】:2017-11-26 14:19:31
【问题描述】:

我有一个包含大约 600,000 条 Wikidata 分类记录的大型 RDF 文件。从这个文件中,我只对 subclassOf 关系(谓词)感兴趣,因此,我忽略了仅保留“subclassOf”语句的所有其他语句。声明如下: ais a subclassOfb, bis a subclassOfc 就像cb 的父级,ba 的父级。任何父母都可以有很多孩子。我想使用此分类法构建分层树。 我检查了这个线程,它几乎解决了我的问题。 Recursively creating a tree hierarchy without using class/object 但是,有了这个,我得到了字典中的树,我想将其转换为树数据结构。以下是我尝试过的:

data = [['a','x'], ['b','x'], ['c','x'], ['x','y'], ['t','y'], ['y','p'], ['p','q']]

roots = set()
mapping = {}
for child,parent in data:        
    childitem = mapping.get(child,None)
    if childitem is None:
        childitem =  {}
        mapping[child] = childitem
    else:
        roots.discard(child)
    parentitem = mapping.get(parent,None)
    if parentitem is None:
        mapping[parent] = {child:childitem}
        roots.add(parent)
    else:
        parentitem[child] = childitem

for root in roots:
    print(mapping[root])

tree = { id : mapping[id] for id in roots }
print(tree)

树的输出如下:

{'q': {'p': {'y': {'t': {}, 'x': {'c': {}, 'b': {}, 'a': {}}}}}}

我想将此字典转换为树。所以例如当我说 print(mapping['y']) 时,它应该给我 Node y 即

q
├── p
    └── y

目前,如果我说映射['y'],它会给我以 y 为根的子树。我认为对此有一些简单的解决方案,但我无法理解。我也找到了此链接https://gist.github.com/hrldcpr/2012250 将字典转换为树,但不确定如何在我的情况下使用它。或者,如果有人知道直接从我上面给出的 RDF 数据构建树,那么它将是最受欢迎的。可能 python 的anytree API 会解决我的问题。

【问题讨论】:

  • 你需要一个“树”类吗?一种为您现在拥有的字典树漂亮地打印节点祖先的方法?还是两者兼而有之?
  • 最终我只需要祖先(或到该节点的路径)。无论我是使用树还是字典来获取它都无关紧要。因此,如果我能以某种方式访问​​嵌套字典中键的路径,我的问题将得到解决。

标签: python dictionary tree rdf taxonomy


【解决方案1】:

如果您不介意额外的 O(N) 空间,您可以保留一个 parents 字典,为每个键子项存储值父项。并将其填充到主 for 循环中。

现在很容易找到所有祖先。递归查找父节点的所有祖先并将当前节点附加到该结果。

data = [['a','x'], ['b','x'], ['c','x'], ['x','y'], ['t','y'], ['y','p'], ['p','q']]
parents = {} #to store parents
roots = set()
mapping = {}
for child,parent in data:
    parents[child] = parent #populate parents
    childitem = mapping.get(child,None)
    ................................

def ancestors(node): #the ancestor-finding function
    if not node: return []
    return ancestors(parents.get(node))+[node]

def first_k_ancestor(node,k=5):
    ances = ancestors(node)
    ances.reverse()
    return ances[:k]


print(ancestors('a'))

哪个打印:

['q', 'p', 'y']

【讨论】:

  • 对我来说似乎工作正常。如果我希望这个层次结构以相反的顺序排列,并且只到第 3 级。例如对于节点 'a' 我只想要 [a, x, y] 而不是 [a,x,y,p,q]
  • 性能有问题吗?那 3 个可能会改变,即前 5 个祖先可能吗?
  • 性能并不是一个真正的问题,因为创建这个层次结构是一个一次性的过程,稍后我将在字典中存储所需的键和它们各自的路径(作为值),我会经常访问。而我实际上只想要 5 个祖先,我说 3 个是为了让这个例子工作。在真实数据中,我可以有 50 个祖先,其中我只需要最后 5 个。
  • 看看first_k_ancestors 能不能完成这项工作。它会自动选择前 5 个,但你可以通过传递第二个参数来改变它
  • 好的。我会试试这个。谢谢:)
猜你喜欢
  • 2016-05-06
  • 1970-01-01
  • 2019-11-23
  • 2016-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-18
  • 2020-10-09
相关资源
最近更新 更多