【问题标题】:Get all directly intermediate and ultimate parent nodes of a child node in a pandas data frame获取熊猫数据框中子节点的所有直接中间和最终父节点
【发布时间】:2020-05-19 10:02:40
【问题描述】:

我有如下父子关系的数据框:

**child                Parent              relationship**

   A1x2                 bc11                direct_parent
   bc11                 Aw00                direct_parent
   bc11                 Aw00                ultimate_parent
   Aee1                 Aee0                direct_parent
   Aee1                 Aee0                ultimate_parent

我想在新数据框中获取所有子节点的所有祖先。结果看起来像这样:

node                   ancesstory_tree

A1x2                    [A1x2,bc11,Aw00]   
Aee1                    [Aee1,Aee0]

注意:真实数据集在子节点和最终父节点之间可能有很多直接前驱节点。

【问题讨论】:

    标签: python-3.x pandas numpy


    【解决方案1】:

    另一种方法,使用 networkx 包中的 from_pandas_edgelistancestors

    import networkx as nx
    
    # Create the Directed Graph
    G = nx.from_pandas_edgelist(df,
                                source='Parent',
                                target='child',
                                create_using=nx.DiGraph())
    
    # Create dict of nodes and ancestors
    ancestors = {n: {n} | nx.ancestors(G, n) for n in df['child'].unique()}
    
    # Convert dict back to DataFrame if necessary
    df_ancestors = pd.DataFrame([(k, list(v)) for k, v in ancestors.items()],
                                columns=['node', 'ancestry_tree'])
    
    print(df_ancestors)
    

    [出]

       node       ancestry_tree
    0  A1x2  [A1x2, Aw00, bc11]
    1  bc11        [bc11, Aw00]
    2  Aee1        [Aee1, Aee0]
    

    要从输出表中过滤掉“中间孩子”,您可以仅使用 out_degree 方法过滤到最后一个孩子 - 其中最后一个孩子应该有一个 out_degree == 0

    last_children = [n for n, d in G.out_degree() if d == 0]
    
    ancestors = {n: {n} | nx.ancestors(G, n) for n in last_children}
    
    df_ancestors = pd.DataFrame([(k, list(v)) for k, v in ancestors.items()],
                                columns=['node', 'ancestry_tree'])
    

    [出]

       node       ancestry_tree
    0  A1x2  [A1x2, Aw00, bc11]
    1  Aee1        [Aee1, Aee0]
    

    【讨论】:

    • 谢谢,这个解决方案对我来说更容易理解,但是在创建节点和祖先的字典时出现错误:NetworkXError: The node xvr00001 is not in the graph.
    • @MuhammadAliZia 如果您觉得这个答案有用,也可以随意投票。
    • @MuhammadAliZia,如果您不将 DataFrame 过滤到“from_edgelist”方法会发生什么......即G = nx.from_pandas_edgelist(df, source='Parent', target='child', create_using=nx.DiGraph())
    • 我注意到在某些情况下,子节点出现在祖先树的末尾或中间,如下所示:A1x2 [Aw00, bc11, A1x2] A11c [An21, A11c,bb2]跨度>
    • @MuhammadAliZia 如果这回答了您的问题,请考虑单击复选标记将其选为已接受的答案。
    【解决方案2】:
    • 创建关系字典
    • 逐个检查不是parentchild
    • 跟踪祖先路径以及后代的set
      • 这很重要,因为如果我们遇到一个已经看到的节点,我们希望终止 while 循环

    relate = dict(zip(df.child, df.Parent))
    paths = {}
    nodes = {}
    for child in cp.keys() - {*cp.values()}:
        paths[child] = [child]
        nodes[child] = {child}
        parent = relate[child]
        while parent in relate and parent not in nodes[child]:
            paths[child].append(parent)
            nodes[child].add(parent)
            parent = relate[parent]
        paths[child].append(parent)
    
    pd.Series(paths).rename_axis('node').reset_index(name='ancestry_tree')
    
    
       node       ancestry_tree
    0  Aee1        [Aee1, Aee0]
    1  A1x2  [A1x2, bc11, Aw00]
    

    【讨论】:

    • 我的原始数据框很大(几百万行)。我在以下位置收到内存错误:d[c].append(p)
    • 哦!内存占用应该不是问题......除非你的网络中有一个循环使它递归......嗯,让我弄清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多