Pandas - 在数据框中递归查找 children
Pandas - Recursively look for children in dataframe
考虑以下数据框:
id1 id2
0 aaa 111
1 bbb 222
2 333 ccc
3 999 zzz
4 ccc 111
5 888 zzz
6 zzz 222
7 ddd 888
8 eee 888
我怎样才能递归地为给定输入的所有 children 及其所有 grandchildren 的每个匹配项获取数据帧,在我的例子中,input = [111, 222 ]
即
父母 1:111
Child1:aaa
Child2:ccc(从第 4 行开始)
Child of Child2: 333(来自第 2 行)
父母 2:222
Child1: bbb
Child2:zzz(从第 6 行开始)
ChildA of Child2: 888(从第 5 行开始)
ChildB of Child2: 999(从第 3 行开始)
Child_i of ChildA:ddd(从第 8 行开始)
Child_ii of ChildA:eee(从第 7 行开始)
每个级别(parent->child->child of child)的预期输出为:
### for i = 111
# parent level
id1 id2
0 aaa 111
1 ccc 111
# child level
id1 id2
0 333 ccc
### for i = 222
# parent level
id1 id2
0 bbb 222
1 zzz 222
# child level
id1 id2
0 888 zzz
1 999 zzz
# child of child level
id1 id2
0 ddd 888
1 eee 888
我试过:
parents = [111, 222]
while len(parents) != 0:
for i in parents:
children = df[df['id2'].apply(lambda x: i in str(x))][['id1', 'id2']]
print(children) #print dataframe of match
parents = children['id1']
但它并没有完全完成,我想将 lambda 中的 i 更改为列表推导式,但未能成功。
result
数据框也将包含 NaN,但如果您想删除它们,请使用 result.dropna()
:
from io import StringIO
d = StringIO("""
ix id1 id2
0 aaa 111
1 bbb 222
2 333 ccc
3 999 zzz
4 ccc 111
5 888 zzz
6 zzz 222
7 ddd 888
8 eee 888
""")
import pandas as pd
df = pd.read_csv(d, sep='\s+', index_col='ix')
df.columns
result = (
df.rename(columns={'id2': 'id_parent', 'id1': 'id_child'})
.merge(df.set_index('id2'), how='left', left_on='id_child', right_index=True)
.rename(columns={'id1': 'id_grandchild'})
)
result
例如,这里有一种列出所有孙子的方法:
result.dropna().groupby('id_parent')['id_grandchild'].agg(list).reset_index()
这是一种创建查找字典的方法,其中包含一个人的所有孙辈:
dict_parents = result.dropna().groupby('id_parent')['id_grandchild'].agg(list).to_dict()
# e.g. try: print(dict_parents['222'])
这是获取特定个人结果的方法:
specific_ids = ['111', '222']
result = (
df[df['id2'].isin(specific_ids)].rename(columns={'id2': 'id_parent', 'id1': 'id_child'})
.merge(df.set_index('id2'), how='left', left_on='id_child', right_index=True)
.rename(columns={'id1': 'id_grandchild'})
)
result.dropna()
如果只想打印缩进图,可以使用简单的递归函数:
def desc(i, indent=0):
print(' '*indent + i)
for j in df.loc[df['id2'] == i, 'id1']:
desc(j, indent + 2)
for i in ('111', '222'): desc(i)
对于示例 df,它给出:
111
aaa
ccc
333
222
bbb
zzz
999
888
ddd
eee
考虑以下数据框:
id1 id2
0 aaa 111
1 bbb 222
2 333 ccc
3 999 zzz
4 ccc 111
5 888 zzz
6 zzz 222
7 ddd 888
8 eee 888
我怎样才能递归地为给定输入的所有 children 及其所有 grandchildren 的每个匹配项获取数据帧,在我的例子中,input = [111, 222 ]
即
父母 1:111
Child1:aaa
Child2:ccc(从第 4 行开始)
Child of Child2: 333(来自第 2 行)
父母 2:222
Child1: bbb
Child2:zzz(从第 6 行开始)
ChildA of Child2: 888(从第 5 行开始)
ChildB of Child2: 999(从第 3 行开始)
Child_i of ChildA:ddd(从第 8 行开始)
Child_ii of ChildA:eee(从第 7 行开始)
每个级别(parent->child->child of child)的预期输出为:
### for i = 111
# parent level
id1 id2
0 aaa 111
1 ccc 111
# child level
id1 id2
0 333 ccc
### for i = 222
# parent level
id1 id2
0 bbb 222
1 zzz 222
# child level
id1 id2
0 888 zzz
1 999 zzz
# child of child level
id1 id2
0 ddd 888
1 eee 888
我试过:
parents = [111, 222]
while len(parents) != 0:
for i in parents:
children = df[df['id2'].apply(lambda x: i in str(x))][['id1', 'id2']]
print(children) #print dataframe of match
parents = children['id1']
但它并没有完全完成,我想将 lambda 中的 i 更改为列表推导式,但未能成功。
result
数据框也将包含 NaN,但如果您想删除它们,请使用 result.dropna()
:
from io import StringIO
d = StringIO("""
ix id1 id2
0 aaa 111
1 bbb 222
2 333 ccc
3 999 zzz
4 ccc 111
5 888 zzz
6 zzz 222
7 ddd 888
8 eee 888
""")
import pandas as pd
df = pd.read_csv(d, sep='\s+', index_col='ix')
df.columns
result = (
df.rename(columns={'id2': 'id_parent', 'id1': 'id_child'})
.merge(df.set_index('id2'), how='left', left_on='id_child', right_index=True)
.rename(columns={'id1': 'id_grandchild'})
)
result
例如,这里有一种列出所有孙子的方法:
result.dropna().groupby('id_parent')['id_grandchild'].agg(list).reset_index()
这是一种创建查找字典的方法,其中包含一个人的所有孙辈:
dict_parents = result.dropna().groupby('id_parent')['id_grandchild'].agg(list).to_dict()
# e.g. try: print(dict_parents['222'])
这是获取特定个人结果的方法:
specific_ids = ['111', '222']
result = (
df[df['id2'].isin(specific_ids)].rename(columns={'id2': 'id_parent', 'id1': 'id_child'})
.merge(df.set_index('id2'), how='left', left_on='id_child', right_index=True)
.rename(columns={'id1': 'id_grandchild'})
)
result.dropna()
如果只想打印缩进图,可以使用简单的递归函数:
def desc(i, indent=0):
print(' '*indent + i)
for j in df.loc[df['id2'] == i, 'id1']:
desc(j, indent + 2)
for i in ('111', '222'): desc(i)
对于示例 df,它给出:
111
aaa
ccc
333
222
bbb
zzz
999
888
ddd
eee