Pandas DataFrame中按相同ID合并多行至单行的实现方案
问题描述
现有如下DataFrame:
ID Qnt Rec value AB1234 20 1 2 xy123 30 1 5 xy123 30 2 2
需求:按ID分组,将相同ID的行合并为单行,计算Qnt、所有Rec、所有Value列值的乘积(例如ID xy123的计算式为 30*1*5*2*2 = 600),输出格式如下:
ID Qnt Rec Value Rec Value output AB1234 20 1 2 Null Null 40 xy123 30 1 5 2 2 600
当前实现方式是将DataFrame按Rec拆分为两部分后合并,现寻求其他灵活的可行方案(后续对输出格式有调整需求)。
方案1:GroupBy + 自定义聚合函数
通过groupby('ID')对每个分组单独处理列展开与乘积计算,灵活性强,适配后续格式调整:
import pandas as pd # 构造原始数据 df = pd.DataFrame({ 'ID': ['AB1234', 'xy123', 'xy123'], 'Qnt': [20, 30, 30], 'Rec': [1, 1, 2], 'value': [2, 5, 2] }) def process_group(group): # 提取Qnt(*假设同一ID的Qnt值一致,取第一个即可*) qnt = group['Qnt'].iloc[0] # 提取当前分组的所有Rec和value值 rec_list = group['Rec'].tolist() value_list = group['value'].tolist() # 计算总乘积:Qnt × 所有Rec的乘积 × 所有value的乘积 total_product = qnt * pd.Series(rec_list).prod() * pd.Series(value_list).prod() # 构造结果行,缺省值补Null result_row = { 'ID': group.name, 'Qnt': qnt, 'Rec_1': rec_list[0] if len(rec_list) >= 1 else None, 'Value_1': value_list[0] if len(value_list) >= 1 else None, 'Rec_2': rec_list[1] if len(rec_list) >= 2 else None, 'Value_2': value_list[1] if len(value_list) >= 2 else None, 'output': total_product } return pd.Series(result_row) # 应用分组处理并重置索引 result_df = df.groupby('ID').apply(process_group).reset_index(drop=True) # 重命名列以匹配期望输出格式 result_df.columns = ['ID', 'Qnt', 'Rec', 'Value', 'Rec', 'Value', 'output'] print(result_df)
如果后续需要支持更多Rec条目,只需修改process_group中结果行的列构造逻辑即可。
方案2:Pivot 重塑宽表后计算
利用pivot将Rec转为列索引,把Rec和value分别转成宽表,再合并计算乘积,适合Rec取值为连续整数的场景:
import pandas as pd df = pd.DataFrame({ 'ID': ['AB1234', 'xy123', 'xy123'], 'Qnt': [20, 30, 30], 'Rec': [1, 1, 2], 'value': [2, 5, 2] }) # 将Rec列转为宽表 rec_wide = df.pivot(index='ID', columns='Rec', values='Rec').add_prefix('Rec_') # 将value列转为宽表 value_wide = df.pivot(index='ID', columns='Rec', values='value').add_prefix('Value_') # 提取每个ID对应的Qnt值(取第一个) qnt_df = df.groupby('ID')['Qnt'].first().reset_index() # 合并所有数据 merged_df = qnt_df.merge(rec_wide, on='ID').merge(value_wide, on='ID') # 计算总乘积 merged_df['output'] = merged_df['Qnt'] * merged_df.filter(like='Rec_').prod(axis=1) * merged_df.filter(like='Value_').prod(axis=1) # 调整列名与顺序以匹配需求 merged_df.columns = ['ID', 'Qnt', 'Rec', 'Rec', 'Value', 'Value', 'output'] merged_df = merged_df[['ID', 'Qnt', 'Rec', 'Value', 'Rec', 'Value', 'output']] print(merged_df)
后续如果新增Rec条目,pivot会自动生成对应列,无需手动修改列构造逻辑。
内容的提问来源于stack exchange,提问作者arawind73
相关产品推荐
相关产品推荐

