什么是 python 用于在非二叉树中列出祖先的后代的递归方法?
What is a python recursion method for listing descendants from an ancestor in a non-binary tree?
我是使用 Python 的初学者。我有一个包含家谱的 MS Access 数据库。我希望使用 Python 来查询家谱以列出已识别祖先的所有后代。家谱保存在 table 我已经导出到 excel。它包含三列:关系 ID、Node1_ID、Node2_ID。每行中列出的关系是从 Node1_ID 到 Node2_ID 的单向关系。树是非二进制的,因此树可以有几个 Node2_ID 从 Node1_ID.
下降
婚姻中处于 Node1_ID 位置的每个伴侣都与 Node2_ID 中的同一个伙伴关系节点相关(在下面的示例中,父节点 1 和 2 与伙伴关系节点 3 相关)。伙伴关系节点然后与子节点相关(例如,伙伴关系节点 3 连接到子节点 4、5 和 6)。
RID
Node1_ID
Node2_ID
1
1
3
2
2
3
3
3
4
4
3
5
5
3
6
我希望使用代码调用 excel 电子表格,并允许我通过递归查询特定节点的所有后代的列表。然后我希望将该列表写入一个新的 excel 文件,我可以将该文件导入回我的 MS Access 数据库或在其他软件(如 GraphViz)中进行可视化。
在网上搜索时,我遇到了以下代码,似乎可以解决问题:
import pandas as pd
import sys
sys.setrecursionlimit(100000000)
df = pd.read_excel(r'excelfilepath')
columns = df.columns.ravel()
def get_ancestry_dataframe_flat(df):
def get_child_list(parent_id):
list_of_children = list()
list_of_children.append(df[df['P1ID'] == parent_id]['P2ID'].values)
for i, r in df[df['P1ID'] == parent_id].iterrows():
if r['P2ID'] != parent_id:
list_of_children.append(get_child_list(r['P2ID']))
# flatten list
list_of_children = [item for sublist in list_of_children for item in sublist]
return list_of_children
new_df = pd.DataFrame(columns=['descendant', 'ancestor']).astype(int)
for index, row in df.iterrows():
temp_df = pd.DataFrame(columns=['descendant', 'ancestor'])
temp_df['descendant'] = pd.Series(get_child_list(row['P1ID']))
temp_df['ancestor'] = row['P1ID']
new_df = new_df.append(temp_df)
new_df = new_df\
.drop_duplicates()\
.sort_values(['ancestor', 'descendant'])\
.reset_index(drop=True)
return new_df
writer = pd.ExcelWriter('20210408_descendant_relationships.xlsx',engine='xlsxwriter')
get_ancestry_dataframe_flat(df).to_excel(writer,sheet_name='Sheet1')
writer.save()
这段代码的问题是,我在创建所有祖先的后代列表时似乎达到了递归限制(家谱相当大)。因此,我希望只查询特定祖先的后代。我可以做哪些编辑来做到这一点?除了递归限制问题,我仍然想识别特定祖先的后代。
我是 Python 的初学者,所以如果可能的话,我将不胜感激。谢谢你的时间。
编辑:来自 @Ajax1234
建议的代码
import pandas as pd
from collections import deque
df = pd.read_excel('input.xlsx')
tree = df.values.tolist()
def get_ancestors(node):
d, seen = deque([node]), set()
while d:
yield (n:=d.popleft())
seen.add(n)
d.extend([int(c) for _, b, c in tree if int(b) == int(n)])
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
vals = [[[a, i] for i in b] for a, b in r.items()]
df1 = pd.DataFrame([dict(zip(['node', 'descendent'], i)) for i in vals])
print(r)
df1.to_excel('output.xlsx')
预期输出 excel table 应该是这样的:
Node
Descendant
1
3
1
4
1
5
1
6
2
3
2
4
2
5
2
6
3
4
3
5
3
6
可以使用广度优先搜索的非递归解决方案:
from collections import deque
tree = [[1, 1, 3], [2, 2, 3], [3, 3, 4], [4, 3, 5], [5, 3, 6]]
def get_ancestors(node):
d, seen = deque([node]), set()
while d:
yield (n:=d.popleft())
seen.add(n)
d.extend([int(c) for _, b, c in tree if int(b) == int(n)])
get_ancestors
接收一个节点并通过广度优先搜索生成该节点的所有后代。例如,要获取 node1_id
的所有后代:
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
输出:
{1: [3, 4, 5, 6], 2: [3, 4, 5, 6], 3: [4, 5, 6]}
编辑:写入 Excel:
writer = pd.ExcelWriter('20210408_descendant_relationships.xlsx',engine='xlsxwriter')
df = pd.read_excel(writer, 'sheet1')
tree = df.values.tolist()
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
vals = [[a, i] for a, b in r.items() for i in b]
df1 = pd.DataFrame([dict(zip(['node', 'descendent'], i) for i in vals])
df1.to_excel(writer)
我是使用 Python 的初学者。我有一个包含家谱的 MS Access 数据库。我希望使用 Python 来查询家谱以列出已识别祖先的所有后代。家谱保存在 table 我已经导出到 excel。它包含三列:关系 ID、Node1_ID、Node2_ID。每行中列出的关系是从 Node1_ID 到 Node2_ID 的单向关系。树是非二进制的,因此树可以有几个 Node2_ID 从 Node1_ID.
下降婚姻中处于 Node1_ID 位置的每个伴侣都与 Node2_ID 中的同一个伙伴关系节点相关(在下面的示例中,父节点 1 和 2 与伙伴关系节点 3 相关)。伙伴关系节点然后与子节点相关(例如,伙伴关系节点 3 连接到子节点 4、5 和 6)。
RID | Node1_ID | Node2_ID |
---|---|---|
1 | 1 | 3 |
2 | 2 | 3 |
3 | 3 | 4 |
4 | 3 | 5 |
5 | 3 | 6 |
我希望使用代码调用 excel 电子表格,并允许我通过递归查询特定节点的所有后代的列表。然后我希望将该列表写入一个新的 excel 文件,我可以将该文件导入回我的 MS Access 数据库或在其他软件(如 GraphViz)中进行可视化。
在网上搜索时,我遇到了以下代码,似乎可以解决问题:
import pandas as pd
import sys
sys.setrecursionlimit(100000000)
df = pd.read_excel(r'excelfilepath')
columns = df.columns.ravel()
def get_ancestry_dataframe_flat(df):
def get_child_list(parent_id):
list_of_children = list()
list_of_children.append(df[df['P1ID'] == parent_id]['P2ID'].values)
for i, r in df[df['P1ID'] == parent_id].iterrows():
if r['P2ID'] != parent_id:
list_of_children.append(get_child_list(r['P2ID']))
# flatten list
list_of_children = [item for sublist in list_of_children for item in sublist]
return list_of_children
new_df = pd.DataFrame(columns=['descendant', 'ancestor']).astype(int)
for index, row in df.iterrows():
temp_df = pd.DataFrame(columns=['descendant', 'ancestor'])
temp_df['descendant'] = pd.Series(get_child_list(row['P1ID']))
temp_df['ancestor'] = row['P1ID']
new_df = new_df.append(temp_df)
new_df = new_df\
.drop_duplicates()\
.sort_values(['ancestor', 'descendant'])\
.reset_index(drop=True)
return new_df
writer = pd.ExcelWriter('20210408_descendant_relationships.xlsx',engine='xlsxwriter')
get_ancestry_dataframe_flat(df).to_excel(writer,sheet_name='Sheet1')
writer.save()
这段代码的问题是,我在创建所有祖先的后代列表时似乎达到了递归限制(家谱相当大)。因此,我希望只查询特定祖先的后代。我可以做哪些编辑来做到这一点?除了递归限制问题,我仍然想识别特定祖先的后代。
我是 Python 的初学者,所以如果可能的话,我将不胜感激。谢谢你的时间。
编辑:来自 @Ajax1234
建议的代码
import pandas as pd
from collections import deque
df = pd.read_excel('input.xlsx')
tree = df.values.tolist()
def get_ancestors(node):
d, seen = deque([node]), set()
while d:
yield (n:=d.popleft())
seen.add(n)
d.extend([int(c) for _, b, c in tree if int(b) == int(n)])
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
vals = [[[a, i] for i in b] for a, b in r.items()]
df1 = pd.DataFrame([dict(zip(['node', 'descendent'], i)) for i in vals])
print(r)
df1.to_excel('output.xlsx')
预期输出 excel table 应该是这样的:
Node | Descendant |
---|---|
1 | 3 |
1 | 4 |
1 | 5 |
1 | 6 |
2 | 3 |
2 | 4 |
2 | 5 |
2 | 6 |
3 | 4 |
3 | 5 |
3 | 6 |
可以使用广度优先搜索的非递归解决方案:
from collections import deque
tree = [[1, 1, 3], [2, 2, 3], [3, 3, 4], [4, 3, 5], [5, 3, 6]]
def get_ancestors(node):
d, seen = deque([node]), set()
while d:
yield (n:=d.popleft())
seen.add(n)
d.extend([int(c) for _, b, c in tree if int(b) == int(n)])
get_ancestors
接收一个节点并通过广度优先搜索生成该节点的所有后代。例如,要获取 node1_id
的所有后代:
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
输出:
{1: [3, 4, 5, 6], 2: [3, 4, 5, 6], 3: [4, 5, 6]}
编辑:写入 Excel:
writer = pd.ExcelWriter('20210408_descendant_relationships.xlsx',engine='xlsxwriter')
df = pd.read_excel(writer, 'sheet1')
tree = df.values.tolist()
r = dict([(next(n:=get_ancestors(i)), list(n)) for i in set([t[1] for t in tree])])
vals = [[a, i] for a, b in r.items() for i in b]
df1 = pd.DataFrame([dict(zip(['node', 'descendent'], i) for i in vals])
df1.to_excel(writer)