我对PYTHON中父母/子女关系中的层级管理有一个小问题.

为了给出一些上下文,我有一个由x个字段组成的表.以下是我感兴趣的:

  • 产品_id
  • parent_ref
  • child_ref

该表代表了多种产品的扁平 struct (产品_id =汽车型号).

第一个父母是身体,我们在上面安装门、发动机支架、发动机,发动机本身由数百个零件组成等等..

一些车型重复使用其他车辆的零部件,相同的发动机、相同的离合.

这是我的 case ,我有一个大约180万行的文件,向我展示了我每个产品的 struct .

我想创建一个"级别"的概念,它是根据 struct 中的位置计算的.例如,我知道所有第一个子级(即级别1)在父列中的值都为"-1".

`Ex: 
Product_id           Parent_ref            child_ref
BMW316E46              -1                  15G0001-013    --> First parent
BMW316E46              -1                  15G0001-014    --> Second parent
BMW316E46          15G0001-013             14G0009-001    --> First parent first child...
BMW316E46          15G0001-013             14G0017-001    --> First parent second child...
BMW316E46          15G0001-013             14G0018-001`   --> Each child can be (or not) a parent as well

我的目标是 for each 产品(Products_id)制定一个 struct ,每个子元素都有一个级别列,这将取决于父母,并且是视觉的.换句话说,子元素的身份是相对于父母的(我事先不知道可能有多少个级别).

类似于这样的:

Product_id    Parent_ref     Child_ref    Level (with visual identation)
BMW316E46       -1          15G0001-013     1
BMW316E46    15G0001-013    14G0009-001     __2
BMW316E46    15G0001-013    14G0017-001     __2
BMW316E46    14G0017-001    14G0017-001     ____3
BMW316E46       -1          15G0001-014     1
BMW316E46    15G0001-014    14G0009-001     __2
BMW316E46    15G0001-014    14G0017-001     __2

我在Python中try 了类似的事情, for each 循环创建一个数组,以找出不同的子元素,但它只适用于第一个循环,因为我需要分开每个父母的不同子元素.

df = pd.read_csv("file.csv")


for index, row in df.iterrows():
    if row['parent_ref'] == "'-1":
        array_lvl_1.append(row['child_ref'])
        parent_level = alc[count]
        df.loc[index, 'level'] = parent_level
        count += 1


for index, row in df.iterrows():
    if row['parent_ref'] in array_lvl_1:
        for value in array_lvl_1:
            array_lvl_1_1.append(row['child_ref'])
            df.loc[index, 'level'] = alc[count2]
            count2 += 1

但它不是循环的,它迫使我创建与级别一样多的表,而且我事先不知道级别的数量.

推荐答案

由于这是一个图形问题,因此我会在topological_generations的帮助下使用networkx来获取每个 node 的深度,并使用dfs_edges来生成按DFS顺序的边列表:

import networkx as nx

def make_hierarchy(g):
    G = nx.from_pandas_edgelist(g, create_using=nx.DiGraph,
                                source='Parent_ref', target='Child_ref')
    depth = {n: f'{"_"*(d-1)}{d}' for d, l in
             enumerate(nx.topological_generations(G))
             for n in l}
    return (pd
       .DataFrame(nx.dfs_edges(G), columns=['Parent_ref', 'Child_ref'])
       .assign(Product_id=g.name,
               Level=lambda d: d['Child_ref'].map(depth)
              )
    )[['Product_id', 'Parent_ref', 'Child_ref', 'Level']]

# compute the hierarchy per group
out = df.groupby('Product_id', group_keys=False).apply(make_hierarchy)

# optional, left justify the strings
out['Level'] = out['Level'].str.ljust(out['Level'].str.len().max())

输出:

  Product_id   Parent_ref    Child_ref Level
0  BMW316E46           -1  15G0001-013   1  
1  BMW316E46  15G0001-013  14G0009-001   _2 
2  BMW316E46  15G0001-013  14G0017-001   _2 
3  BMW316E46  14G0017-001  14G0018-001   __3
4  BMW316E46           -1  15G0001-014   1  

使用的输入(与问题中略有不同,有3个级别):

0  BMW316E46           -1  15G0001-013
1  BMW316E46           -1  15G0001-014
2  BMW316E46  15G0001-013  14G0009-001
3  BMW316E46  15G0001-013  14G0017-001
4  BMW316E46  14G0017-001  14G0018-001

图表:

enter image description here

Python相关问答推荐

从管道将Python应用程序部署到Azure Web应用程序,不包括需求包

在Pandas框架中截短至固定数量的列

Odoo -无法比较使用@api.depends设置计算字段的日期

使用FASTCGI在IIS上运行Django频道

如何使用pandasDataFrames和scipy高度优化相关性计算

如何更改分组条形图中条形图的 colored颜色 ?

如何获得每个组的时间戳差异?

如何在WSL2中更新Python到最新版本(3.12.2)?

lityter不让我输入左边的方括号,'

在Python中调用变量(特别是Tkinter)

dask无groupby(ddf. agg([min,max])?''''

处理具有多个独立头的CSV文件

寻找Regex模式返回与我当前函数类似的结果

重置PD帧中的值

为什么Python内存中的列表大小与文档不匹配?

在二维NumPy数组中,如何 Select 内部数组的第一个和第二个元素?这可以通过索引来实现吗?

如何在FastAPI中替换Pydantic的constr,以便在BaseModel之外使用?'

Python将一个列值分割成多个列,并保持其余列相同

按条件添加小计列

利用SCIPY沿第一轴对数组进行内插