Pandas映射:根据树结构添加后缀
Pandas Mapping: add suffix based on tree structure
1.数据:
我在 pandas DataFrame 中有以下结构:
import pandas as pd
df = pd.DataFrame([['A', 'NaN', 'A', 'NaN'],['B', 'A', 'B/A', 'A'], ['B1', 'B', 'B1/B/A', 'B/A'],
['B2', 'B', 'B2/B/A', 'B/A'], ['C', 'B1', 'C/B1/B/A', 'B1/B/A'], ['D', 'B1', 'D/B1/B/A', 'B1/B/A'],
['E', 'B2', 'E/B2/B/A', 'B2/B/A']],
columns=['unit_id', 'group_id', 'new_unit_id', 'new_group_id'])
2。议题与目标:
我想将当前的 unit_id
和 group_id
替换为附加了 parent 结构的值,基本如下:
<unit_id> = <unit_id> + '/' + parent<unit_id>
和
<group_id> = parent<unit_id>
正如您在文件树结构或类似结构中看到的那样。
像这样:
index
unit_id
group_id
new_unit_id
new_group_id
0
A
NaN
A
NaN
1
B
A
B/A
A
2
B1
B
B1/B/A
B/A
3
B2
B
B2/B/A
B/A
4
C
B1
C/B1/B/A
B1/B/A
5
D
B1
D/B1/B/A
B1/B/A
6
E
B2
E/B2/B/A
B2/B/A
3。尝试与方法:
我已经尝试在不创建 'new' 列的情况下就地映射,但是 运行 遇到 parent 的 unit_id
更改时未反映在中的问题children.
的 group_id
df['unit_id'] = df['unit_id'] + '/' + df['group_id']
所以我似乎需要逐行迭代,以便将前一行的更改考虑在内。类似于:
df['unit_id'] = df.apply(lambda row : row['unit_id'].replace(str(row['unit_id']), str(row['unit_id'] + '/' + row['group_id'])), axis=1)
这会产生与上述相同(不准确)的值,但我认为 df.apply
具有正确的匿名 (lambda) 函数更接近我的需要。无法正确使用语法。
这可以是使用图论的方法。
这是你的图表:
您可以使用 networkx
to compute your graph and find the shortest_path
:
import networkx as nx
# ensure real NaN
df = df.replace('NaN', np.nan)
G = nx.from_pandas_edgelist(df.dropna(subset='group_id'),
source='unit_id', target='group_id',
create_using=nx.DiGraph)
#get final item
last = list(nx.topological_sort(G))[-1]
# get simple paths
df['new_unit_id'] = ['/'.join(nx.shortest_path(G, s, last))
if not pd.isna(s) else float('nan')
for s in df['unit_id']]
df['new_group_id'] = df['new_unit_id'].str.extract(r'[^/]+/(.+)')
输出:
unit_id group_id new_unit_id new_group_id
0 A NaN A NaN
1 B A B/A A
2 B1 B B1/B/A B/A
3 B2 B B2/B/A B/A
4 C B1 C/B1/B/A B1/B/A
5 D B1 D/B1/B/A B1/B/A
6 E B2 E/B2/B/A B2/B/A
1.数据:
我在 pandas DataFrame 中有以下结构:
import pandas as pd
df = pd.DataFrame([['A', 'NaN', 'A', 'NaN'],['B', 'A', 'B/A', 'A'], ['B1', 'B', 'B1/B/A', 'B/A'],
['B2', 'B', 'B2/B/A', 'B/A'], ['C', 'B1', 'C/B1/B/A', 'B1/B/A'], ['D', 'B1', 'D/B1/B/A', 'B1/B/A'],
['E', 'B2', 'E/B2/B/A', 'B2/B/A']],
columns=['unit_id', 'group_id', 'new_unit_id', 'new_group_id'])
2。议题与目标:
我想将当前的 unit_id
和 group_id
替换为附加了 parent 结构的值,基本如下:
<unit_id> = <unit_id> + '/' + parent<unit_id>
和
<group_id> = parent<unit_id>
正如您在文件树结构或类似结构中看到的那样。
像这样:
index | unit_id | group_id | new_unit_id | new_group_id |
---|---|---|---|---|
0 | A | NaN | A | NaN |
1 | B | A | B/A | A |
2 | B1 | B | B1/B/A | B/A |
3 | B2 | B | B2/B/A | B/A |
4 | C | B1 | C/B1/B/A | B1/B/A |
5 | D | B1 | D/B1/B/A | B1/B/A |
6 | E | B2 | E/B2/B/A | B2/B/A |
3。尝试与方法:
我已经尝试在不创建 'new' 列的情况下就地映射,但是 运行 遇到 parent 的 unit_id
更改时未反映在中的问题children.
group_id
df['unit_id'] = df['unit_id'] + '/' + df['group_id']
所以我似乎需要逐行迭代,以便将前一行的更改考虑在内。类似于:
df['unit_id'] = df.apply(lambda row : row['unit_id'].replace(str(row['unit_id']), str(row['unit_id'] + '/' + row['group_id'])), axis=1)
这会产生与上述相同(不准确)的值,但我认为 df.apply
具有正确的匿名 (lambda) 函数更接近我的需要。无法正确使用语法。
这可以是使用图论的方法。
这是你的图表:
您可以使用 networkx
to compute your graph and find the shortest_path
:
import networkx as nx
# ensure real NaN
df = df.replace('NaN', np.nan)
G = nx.from_pandas_edgelist(df.dropna(subset='group_id'),
source='unit_id', target='group_id',
create_using=nx.DiGraph)
#get final item
last = list(nx.topological_sort(G))[-1]
# get simple paths
df['new_unit_id'] = ['/'.join(nx.shortest_path(G, s, last))
if not pd.isna(s) else float('nan')
for s in df['unit_id']]
df['new_group_id'] = df['new_unit_id'].str.extract(r'[^/]+/(.+)')
输出:
unit_id group_id new_unit_id new_group_id
0 A NaN A NaN
1 B A B/A A
2 B1 B B1/B/A B/A
3 B2 B B2/B/A B/A
4 C B1 C/B1/B/A B1/B/A
5 D B1 D/B1/B/A B1/B/A
6 E B2 E/B2/B/A B2/B/A