У меня есть такой фрейм данных:
data = {
'Parent': [None, None, 'A', 'B', 'C', 'I', 'D', 'F', 'G', 'H', 'Z', 'Y', None,None,None,None, 'AA', 'BB', 'CC', 'EE', 'FF', None, None],
'Child': ['A', 'B', 'D', 'D', 'D', 'C', 'E', 'E', 'F', 'F', 'G', 'H', 'Z', 'Y', 'AA', 'BB', 'CC', 'CC', 'DD', 'DD', 'DD', 'EE', 'FF']
}
df = pd.DataFrame(data)
Parent Child
0 None A
1 None B
2 A D
3 B D
4 C D
5 I C
6 D E
7 F E
8 G F
9 H F
10 Z G
11 Y H
12 None Z
13 None Y
14 None AA
15 None BB
16 AA CC
17 BB CC
18 CC DD
19 EE DD
20 FF DD
21 None EE
22 None FF
Мне нужен выходной фрейм данных следующим образом:
Я попробовал использовать пакет networkx
, как предложено в этом посте ,
Это код, который я использовал
df['parent']=df['parent'].fillna('No Parent')
leaves =set(df['parent']).difference(df['child'])
g= nx.from_pandas_edgelist(df, 'parent', 'child', create_using=nx.DiGraph())
ancestors = {
n: nx.algorithms.dag.ancestors(g, n) for n in leaves
}
df1=(pd.DataFrame.from_dict(ancestors, orient='index')
.rename(lambda x: 'parent_{}'.format(x+1), axis=1)
.rename_axis('child')
.fillna('')
)
Но я получаю пустой фрейм данных. Есть ли элегантный способ добиться этого?
🤔 А знаете ли вы, что...
Python позволяет создавать сценарии для автоматизации задач и обработки данных.
Один из вариантов — сделать финальный DataFrame from_dict из предшественников :
DG = nx.from_pandas_edgelist(
df.fillna("#"), "parent", "child", create_using=nx.DiGraph
)
DG.remove_node("#") # remove the placeholder
out = (
pd.DataFrame.from_dict(
{n: DG.predecessors(n) for n in DG}, orient = "index"
).rename(columns=lambda c: f"Parent {c+1}").reset_index(names = "Child")
)
# {"Parent 1": "deepskyblue", "Parent 2": "lightcoral", "Parent 3": "springgreen"}
Используйте cumcount
, чтобы отличить нескольких родителей, затем pivot
.
Используйте sort_values
, если вам важен порядок вывода, иначе вы можете удалить его.
out = (
df.assign(rank=df.groupby("Child").cumcount() + 1)
.pivot(index = "Child", columns = "rank", values = "Parent")
.add_prefix("Parent ")
.sort_values(by = "Child", key=lambda col: col.map(lambda x: (len(x), x)))
.reset_index()
)
out.columns.name = None
Child Parent 1 Parent 2 Parent 3
0 A None NaN NaN
1 B None NaN NaN
2 C I NaN NaN
3 D A B C
4 E D F NaN
5 F G H NaN
6 G Z NaN NaN
7 H Y NaN NaN
8 Y None NaN NaN
9 Z None NaN NaN
10 AA None NaN NaN
11 BB None NaN NaN
12 CC AA BB NaN
13 DD CC EE FF
14 EE None NaN NaN
15 FF None NaN NaN