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

如何在Pandas中合并含父子关系且多子项的行

合并Pandas中父案件与多个子案件的实现方案

需求说明

需要将案件数据中的父案件与所有关联子案件合并,每个父案件保留一行,遵循以下规则:

  • A、B、C、D字段:优先级为Yes>No>Unknown,只要父/子项中有Yes则取Yes,无Yes但有No则取No,否则为Unknown
  • Demanded和Paid字段:取父案件与所有子案件中的最大值
  • Notes字段:拼接父案件与所有非空子案件的备注内容
  • 新增Child_Case #字段,存储所有关联子案件的编号列表

原始数据

import pandas as pd
import numpy as np

d = [{'Case #': 'CHI22-01234',
  'Parent Case #': np.nan,
  'Name': 'Abraham Lincoln',
  'Demanded': 5000.0,
  'Paid': 2000.0,
  'A': 'Yes',
  'B': 'No',
  'C': 'Yes',
  'D': 'Yes',
  'Notes': 'Honest Abe with his stovepipe hat'},
 {'Case #': 'CHI22-01237',
  'Parent Case #': np.nan,
  'Name': 'Ebenezer Scrooge',
  'Demanded': 10000.0,
  'Paid': 0.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'Unknown',
  'D': 'No',
  'Notes': 'What a scrooge!'},
 {'Case #': 'NYC21-02222',
  'Parent Case #': 'CHI22-01237',
  'Name': 'Ebenezer Scrooge',
  'Demanded': 0.0,
  'Paid': 9500.0,
  'A': 'Unknown',
  'B': 'Unknown',
  'C': 'No',
  'D': 'Yes',
  'Notes': 'Scrooge has an apartment in NYC'},
 {'Case #': 'NYC22-03333',
  'Parent Case #': np.nan,
  'Name': 'Bob Marley',
  'Demanded': 1000000.0,
  'Paid': 0.0,
  'A': 'No',
  'B': 'Unknown',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'He will send three ghosts'},
 {'Case #': 'PHX21-01234',
  'Parent Case #': np.nan,
  'Name': 'Bob Cratchit',
  'Demanded': 0.0,
  'Paid': 0.0,
  'A': 'Unknown',
  'B': 'Unknown',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'Jr. accountant'},
 {'Case #': 'PHX21-01238',
  'Parent Case #': 'PHX21-01234',
  'Name': 'Bob Cratchit',
  'Demanded': 500000.0,
  'Paid': 22000.0,
  'A': 'No',
  'B': 'Yes',
  'C': 'No',
  'D': 'No',
  'Notes': 'Promoted to Sr. accountant 12/14/2021'},
 {'Case #': 'LAX22-12345',
  'Parent Case #': np.nan,
  'Name': 'Kim Kardashian',
  'Demanded': 50000.0,
  'Paid': 0.0,
  'A': 'Yes',
  'B': 'No',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'Kim & Kanye for president'},
 {'Case #': 'LAX22-12349',
  'Parent Case #': 'LAX22-12345',
  'Name': 'Kim Kardashian',
  'Demanded': 50000.0,
  'Paid': 30000.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'Updated data'},
 {'Case #': 'NYC23-21456',
  'Parent Case #': 'NYC22-03333',
  'Name': 'Bob Marley Mon',
  'Demanded': 0.0,
  'Paid': 0.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': np.nan},
 {'Case #': 'NYC23-21457',
  'Parent Case #': 'NYC22-03333',
  'Name': 'Bob Marley Jamaican Mon',
  'Demanded': 0.0,
  'Paid': 0.0,
  'A': 'Unknown',
  'B': 'Unknown',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'Can it handle multiple children?'}]

df = pd.DataFrame(d)

原始代码的问题

原始代码仅支持父案件关联0-1个子案件,当父案件有2个及以上子案件时,会因索引重复导致合并失败,无法正确聚合所有子案件数据。

修改后的实现代码

import pandas as pd
import numpy as np

def get_priority_value(values):
    # 按Yes>No>Unknown的优先级取值
    if 'Yes' in values:
        return 'Yes'
    elif 'No' in values:
        return 'No'
    else:
        return 'Unknown'

# 1. 分离父案件和子案件
parent_df = df[df['Parent Case #'].isna()].copy().set_index('Case #')
child_df = df[df['Parent Case #'].notna()].copy()

# 2. 聚合子案件数据:按Parent Case #分组处理
child_agg = child_df.groupby('Parent Case #').agg(
    Child_Case_List=('Case #', list),
    Max_Demanded=('Demanded', max),
    Max_Paid=('Paid', max),
    A_Values=('A', list),
    B_Values=('B', list),
    C_Values=('C', list),
    D_Values=('D', list),
    Notes_Combined=('Notes', lambda x: '; '.join([str(note) for note in x if pd.notna(note)]))
).reset_index().rename(columns={'Parent Case #': 'Case #'})

# 3. 合并父案件与聚合后的子案件数据
merged_df = parent_df.merge(child_agg, on='Case #', how='left')

# 4. 应用规则计算最终字段
merged_df['Demanded'] = merged_df.apply(lambda row: max(row['Demanded'], row['Max_Demanded']) if pd.notna(row['Max_Demanded']) else row['Demanded'], axis=1)
merged_df['Paid'] = merged_df.apply(lambda row: max(row['Paid'], row['Max_Paid']) if pd.notna(row['Max_Paid']) else row['Paid'], axis=1)

merged_df['A'] = merged_df.apply(lambda row: get_priority_value([row['A']] + (row['A_Values'] if pd.notna(row['A_Values']) else [])), axis=1)
merged_df['B'] = merged_df.apply(lambda row: get_priority_value([row['B']] + (row['B_Values'] if pd.notna(row['B_Values']) else [])), axis=1)
merged_df['C'] = merged_df.apply(lambda row: get_priority_value([row['C']] + (row['C_Values'] if pd.notna(row['C_Values']) else [])), axis=1)
merged_df['D'] = merged_df.apply(lambda row: get_priority_value([row['D']] + (row['D_Values'] if pd.notna(row['D_Values']) else [])), axis=1)

merged_df['Notes'] = merged_df.apply(lambda row: f"{row['Notes']}; {row['Notes_Combined']}" if pd.notna(row['Notes_Combined']) else f"{row['Notes']}; ", axis=1)
merged_df['Child_Case #'] = merged_df['Child_Case_List'].fillna(value=np.nan).apply(lambda x: x if isinstance(x, list) else [])

# 5. 清理不必要的列,调整顺序
final_df = merged_df.drop(columns=['Max_Demanded', 'Max_Paid', 'A_Values', 'B_Values', 'C_Values', 'D_Values', 'Notes_Combined', 'Child_Case_List']).reset_index()

# 输出结果
print(final_df.to_dict('records'))

代码逻辑说明

  1. 分离父/子案件:将无Parent Case #的行作为父案件,有值的作为子案件。
  2. 子案件聚合:按Parent Case #分组,聚合子案件编号为列表,计算Demanded/Paid的最大值,收集A/B/C/D的所有取值,拼接非空Notes。
  3. 合并数据:将父案件与聚合后的子案件数据按Case #左连接,确保所有父案件都保留。
  4. 规则计算:
    • Demanded/Paid:取父案件值与子案件最大值的较大者
    • A/B/C/D:将父案件值与子案件所有取值合并后,按优先级返回结果
    • Notes:父案件Notes拼接子案件聚合后的Notes,无子案件则添加分号结尾
    • Child_Case #:无子案件时设为空列表
  5. 清理列:移除中间计算用的列,整理最终输出格式。

输出结果

[{'Case #': 'CHI22-01234',
  'Parent Case #': nan,
  'Name': 'Abraham Lincoln',
  'Demanded': 5000.0,
  'Paid': 2000.0,
  'A': 'Yes',
  'B': 'No',
  'C': 'Yes',
  'D': 'Yes',
  'Notes': 'Honest Abe with his stovepipe hat; ',
  'Child_Case #': []},
 {'Case #': 'CHI22-01237',
  'Parent Case #': nan,
  'Name': 'Ebenezer Scrooge',
  'Demanded': 10000.0,
  'Paid': 9500.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'No',
  'D': 'Yes',
  'Notes': 'What a scrooge!; Scrooge has an apartment in NYC',
  'Child_Case #': ['NYC21-02222']},
 {'Case #': 'NYC22-03333',
  'Parent Case #': nan,
  'Name': 'Bob Marley',
  'Demanded': 1000000.0,
  'Paid': 0.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'He will send three ghosts; Can it handle multiple children?',
  'Child_Case #': ['NYC23-21456', 'NYC23-21457']},
 {'Case #': 'PHX21-01234',
  'Parent Case #': nan,
  'Name': 'Bob Cratchit',
  'Demanded': 500000.0,
  'Paid': 22000.0,
  'A': 'No',
  'B': 'Yes',
  'C': 'No',
  'D': 'No',
  'Notes': 'Jr. accountant; Promoted to Sr. accountant 12/14/2021',
  'Child_Case #': ['PHX21-01238']},
 {'Case #': 'LAX22-12345',
  'Parent Case #': nan,
  'Name': 'Kim Kardashian',
  'Demanded': 50000.0,
  'Paid': 30000.0,
  'A': 'Yes',
  'B': 'Yes',
  'C': 'Unknown',
  'D': 'Unknown',
  'Notes': 'Kim & Kanye for president; Updated data',
  'Child_Case #': ['LAX22-12349']}]

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:31:02