在 pandas 中创建层次结构列
Create hierarchy column in pandas
我有这样一个数据框:
part part_parent
0 part1 NaN
1 part2 part1
2 part3 part2
3 part4 part3
4 part5 part2
我需要像这样添加一个额外的列层次结构:
part part_parent hierarchy
0 part1 NaN part1
1 part2 part1 part1/part2/
2 part3 part2 part1/part2/part3/
3 part4 part3 part1/part2/part3/part4
4 part5 part2 part1/part2/part5
创建 input/output 数据帧的字典:
from numpy import nan
df1 = pd.DataFrame({'part': {0: 'part1', 1: 'part2', 2: 'part3', 3: 'part4', 4: 'part5'},
'part_parent': {0: nan, 1: 'part1', 2: 'part2', 3: 'part3', 4: 'part2'}})
df2 = pd.DataFrame({'part': {0: 'part1', 1: 'part2', 2: 'part3', 3: 'part4', 4: 'part5'},
'part_parent': {0: nan, 1: 'part1', 2: 'part2', 3: 'part3', 4: 'part2'},
'hierarchy': {0: 'part1',
1: 'part1/part2/',
2: 'part1/part2/part3/',
3: 'part1/part2/part3/part4',
4: 'part1/part2/part5'}})
注意: 我已经看到几个与 NetworkX
相关的线程来解决这个问题,但我无法这样做。
感谢任何帮助。
这是一种递归的方法。它使用包含每个元素的 parent 的 Series 来查找给定的 parent 并返回到原始 parent 直到找到 NaN。此时它returns层次结构。
注意。如果你有一个循环网络或未定义的parents(后者可以很容易地被修复是需要的)
,这将不起作用
import pandas as pd
parents = df1.set_index('part')['part_parent']
def hierarchy(e):
if not isinstance(e, list):
return hierarchy([e])
parent = parents[e[0]]
if pd.isna(parent):
return '/'.join(e)
return hierarchy([parent]+e)
df2 = df1.copy()
df2['hierarchy'] = df1['part'].apply(hierarchy)
这是一个使用 networkx
的解决方案。它将nan
作为根节点,并以此为基础找到到每个节点的最短路径。
import networkx as nx
def find_path(net, source, target):
# Adjust this as needed (in case multiple paths are present)
# or error handling in case a path doesn't exist
path = nx.shortest_path(net, source, target)
return "/".join(list(path)[1:])
net = nx.from_pandas_edgelist(df1, "part", "part_parent")
df1["hierarchy"] = [find_path(net, nan, node) for node in df1["part"]]
part part_parent hierarchy
0 part1 NaN part1
1 part2 part1 part1/part2
2 part3 part2 part1/part2/part3
3 part4 part3 part1/part2/part3/part4
4 part5 part2 part1/part2/part5
路径的格式是针对此示例设计的,如果需要更强大的错误处理或多路径格式,则必须调整路径查找器。
我有这样一个数据框:
part part_parent
0 part1 NaN
1 part2 part1
2 part3 part2
3 part4 part3
4 part5 part2
我需要像这样添加一个额外的列层次结构:
part part_parent hierarchy
0 part1 NaN part1
1 part2 part1 part1/part2/
2 part3 part2 part1/part2/part3/
3 part4 part3 part1/part2/part3/part4
4 part5 part2 part1/part2/part5
创建 input/output 数据帧的字典:
from numpy import nan
df1 = pd.DataFrame({'part': {0: 'part1', 1: 'part2', 2: 'part3', 3: 'part4', 4: 'part5'},
'part_parent': {0: nan, 1: 'part1', 2: 'part2', 3: 'part3', 4: 'part2'}})
df2 = pd.DataFrame({'part': {0: 'part1', 1: 'part2', 2: 'part3', 3: 'part4', 4: 'part5'},
'part_parent': {0: nan, 1: 'part1', 2: 'part2', 3: 'part3', 4: 'part2'},
'hierarchy': {0: 'part1',
1: 'part1/part2/',
2: 'part1/part2/part3/',
3: 'part1/part2/part3/part4',
4: 'part1/part2/part5'}})
注意: 我已经看到几个与 NetworkX
相关的线程来解决这个问题,但我无法这样做。
感谢任何帮助。
这是一种递归的方法。它使用包含每个元素的 parent 的 Series 来查找给定的 parent 并返回到原始 parent 直到找到 NaN。此时它returns层次结构。
注意。如果你有一个循环网络或未定义的parents(后者可以很容易地被修复是需要的)
,这将不起作用import pandas as pd
parents = df1.set_index('part')['part_parent']
def hierarchy(e):
if not isinstance(e, list):
return hierarchy([e])
parent = parents[e[0]]
if pd.isna(parent):
return '/'.join(e)
return hierarchy([parent]+e)
df2 = df1.copy()
df2['hierarchy'] = df1['part'].apply(hierarchy)
这是一个使用 networkx
的解决方案。它将nan
作为根节点,并以此为基础找到到每个节点的最短路径。
import networkx as nx
def find_path(net, source, target):
# Adjust this as needed (in case multiple paths are present)
# or error handling in case a path doesn't exist
path = nx.shortest_path(net, source, target)
return "/".join(list(path)[1:])
net = nx.from_pandas_edgelist(df1, "part", "part_parent")
df1["hierarchy"] = [find_path(net, nan, node) for node in df1["part"]]
part part_parent hierarchy
0 part1 NaN part1
1 part2 part1 part1/part2
2 part3 part2 part1/part2/part3
3 part4 part3 part1/part2/part3/part4
4 part5 part2 part1/part2/part5
路径的格式是针对此示例设计的,如果需要更强大的错误处理或多路径格式,则必须调整路径查找器。