You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何比较两个Pandas DataFrame中的层级结构?(已更新示例数据)

如何比较两个Pandas DataFrame中的层级结构?(已更新示例数据)

嘿,这个问题我之前处理过类似的,这种片段式的父子行确实绕得慌!核心思路就是先把两个DataFrame里的零散层级关系,转换成每个节点的完整根到节点路径,这样就能用Df1的标准路径来直接校验Df2的内容了。咱们一步步来实操:

第一步:处理标准DataFrame(Df1),构建全局层级映射

首先得说明,Df1里的Ultimate Parent列其实是每行片段的顶层,不是全局的终极父,所以咱们直接提取所有直接父子对,不管这个列的干扰:

import pandas as pd

# 你的Df1示例数据
df1 = pd.DataFrame({
    'Ultimate Parent': ['A', 'B', 'C'],
    'Parent': ['B', 'C', 'D'],
    'Child': ['C', 'D', 'E']
})

# 提取所有直接父子关系(包括每行的Ultimate Parent→Parent,Parent→Child)
parent_child_pairs = []
for _, row in df1.iterrows():
    parent_child_pairs.append( (row['Ultimate Parent'], row['Parent']) )
    parent_child_pairs.append( (row['Parent'], row['Child']) )

# 去重后,生成「子节点→直接父节点」的字典
child_to_parent_df1 = {}
for parent, child in parent_child_pairs:
    if child not in child_to_parent_df1:
        child_to_parent_df1[child] = parent

# 找到全局根节点(没有父节点的节点,也就是真正的终极父)
all_nodes_df1 = set(child_to_parent_df1.keys()).union(set(child_to_parent_df1.values()))
root_df1 = [node for node in all_nodes_df1 if node not in child_to_parent_df1][0]  # 这里是'A'

然后写个小函数,给任意节点生成从根到它的完整路径:

def get_full_path(node, child_parent_map, root):
    path = [node]
    current = node
    while current in child_parent_map:
        current = child_parent_map[current]
        path.append(current)
        if current == root:
            break
    return ' > '.join(reversed(path))

# 生成Df1所有节点的标准路径
node_path_df1 = {node: get_full_path(node, child_to_parent_df1, root_df1) for node in all_nodes_df1}
# 结果:
# {'A': 'A', 'B': 'A > B', 'C': 'A > B > C', 'D': 'A > B > C > D', 'E': 'A > B > C > D > E'}

第二步:处理待校验的DataFrame(Df2)

用同样的方法处理Df2,生成它的节点路径:

# 你的Df2示例数据(假设是只有A、D、E的情况)
df2 = pd.DataFrame({
    'Ultimate Parent': ['A'],
    'Parent': ['D'],
    'Child': ['E']
})

# 同样提取父子对
parent_child_pairs_df2 = []
for _, row in df2.iterrows():
    parent_child_pairs_df2.append( (row['Ultimate Parent'], row['Parent']) )
    parent_child_pairs_df2.append( (row['Parent'], row['Child']) )

# 生成子→父字典
child_to_parent_df2 = {}
for parent, child in parent_child_pairs_df2:
    if child not in child_to_parent_df2:
        child_to_parent_df2[child] = parent

# 找Df2的根节点(这里是'A')
all_nodes_df2 = set(child_to_parent_df2.keys()).union(set(child_to_parent_df2.values()))
root_df2 = [node for node in all_nodes_df2 if node not in child_to_parent_df2][0]

# 生成Df2的节点路径
node_path_df2 = {node: get_full_path(node, child_to_parent_df2, root_df2) for node in all_nodes_df2}
# 结果:
# {'A': 'A', 'D': 'A > D', 'E': 'A > D > E'}

第三步:用Df1的标准校验Df2

现在就可以直接对比了,分两种情况检查:

  1. 检查Df2的节点是否在Df1中存在:如果有Df1没有的节点,标记为异常
  2. 检查Df2的节点路径是否和Df1的标准路径一致:不一致就是层级错误
# 开始校验
validation_results = []
for node, df2_path in node_path_df2.items():
    # 情况1:节点不在Df1中
    if node not in node_path_df1:
        validation_results.append(f"⚠️ 节点 {node} 不在标准层级(Df1)中")
    else:
        df1_path = node_path_df1[node]
        # 情况2:路径不一致
        if df2_path != df1_path:
            validation_results.append(f"❌ 节点 {node} 层级错误:Df2路径为「{df2_path}」,标准路径应为「{df1_path}」")
        # 情况3:路径一致
        else:
            validation_results.append(f"✅ 节点 {node} 层级校验通过:「{df2_path}」")

# 输出校验结果
for result in validation_results:
    print(result)

运行后会输出:

✅ 节点 A 层级校验通过:「A」
❌ 节点 D 层级错误:Df2路径为「A > D」,标准路径应为「A > B > C > D」
❌ 节点 E 层级错误:Df2路径为「A > D > E」,标准路径应为「A > B > C > D > E」

额外优化:检查Df2缺失的中间节点

如果还想知道Df2少了哪些Df1里的关键节点,可以直接求差集:

missing_nodes = all_nodes_df1 - all_nodes_df2
if missing_nodes:
    print(f"\nℹ️ Df2缺失标准层级中的节点:{', '.join(missing_nodes)}")
# 输出:ℹ️ Df2缺失标准层级中的节点:B, C

这样就能完整覆盖你的需求啦,把零散的层级片段转换成统一的路径后,对比就变得特别直观,再也不用盯着每行的Ultimate Parent/Child头晕了~

备注:内容来源于stack exchange,提问作者L H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 10:18:09