Pandas按Cus_ID分组并保留Owner类型数据的优化方案问询
问题与优化方案
问题背景
现有如下DataFrame:
| Cus_ID | Cus_Type | Cost | birthdate |
|---|---|---|---|
| 123 | Owner | 50 | 01 Jan 1980 |
| 123 | Spouse | 50 | 10 Feb 1982 |
| 123 | Father | 300 | 01 Dec 1950 |
| 125 | Owner | 20 | 30 Jan 1990 |
| 125 | Spouse | 30 | 15 Jul 1994 |
| 125 | Mother | 100 | 06 Sep 1970 |
需要实现:按Cus_ID分组求和Cost,同时保留对应Cus_ID中Cus_Type为Owner的记录的Cus_Type和birthdate,最终结果如下:
| Cus_ID | Cus_Type | Cost | birthdate |
|---|---|---|---|
| 123 | Owner | 400 | 01 Jan 1980 |
| 125 | Owner | 150 | 30 Jan 1990 |
当前临时方案为:分组求和Cost后新增Cus_Type列并填充Owner,再通过Cus_ID和Cus_Type左连接原DataFrame获取birthdate,寻求更优实现方式。
更优实现方式
方法1:分组聚合时直接指定各列逻辑
通过groupby.agg一次性完成求和、提取Owner类型和生日的操作,无需额外连接:
import pandas as pd # 构造示例数据 df = pd.DataFrame({ 'Cus_ID': [123, 123, 123, 125, 125, 125], 'Cus_Type': ['Owner', 'Spouse', 'Father', 'Owner', 'Spouse', 'Mother'], 'Cost': [50, 50, 300, 20, 30, 100], 'birthdate': ['01 Jan 1980', '10 Feb 1982', '01 Dec 1950', '30 Jan 1990', '15 Jul 1994', '06 Sep 1970'] }) # 分组聚合 result = df.groupby('Cus_ID').agg( Cus_Type=('Cus_Type', lambda x: x[x == 'Owner'].iloc[0]), Cost=('Cost', 'sum'), birthdate=('birthdate', lambda x: x[df.loc[x.index, 'Cus_Type'] == 'Owner'].iloc[0]) ).reset_index() print(result)
方法2:提取Owner记录后合并求和结果
先筛选出所有Owner的基础信息,再和分组求和的Cost结果合并,逻辑直观:
# 提取Owner记录 owner_info = df[df['Cus_Type'] == 'Owner'].copy() # 按Cus_ID计算总Cost total_cost = df.groupby('Cus_ID')['Cost'].sum().reset_index(name='Cost') # 合并数据 result = owner_info.merge(total_cost, on='Cus_ID').drop(columns='Cost_x').rename(columns={'Cost_y': 'Cost'}) print(result)
方法3:用transform添加总Cost后筛选Owner
通过transform给每条记录添加对应Cus_ID的总Cost,再直接筛选Owner记录即可:
# 添加总Cost列 df['Total_Cost'] = df.groupby('Cus_ID')['Cost'].transform('sum') # 筛选Owner记录并整理列 result = df[df['Cus_Type'] == 'Owner'][['Cus_ID', 'Cus_Type', 'Total_Cost', 'birthdate']].rename(columns={'Total_Cost': 'Cost'}).reset_index(drop=True) print(result)
方案优势
以上三种方法均避免了临时方案中的左连接操作,逻辑更简洁,在大数据量场景下性能更优(连接操作通常会带来更高的内存和时间开销)。
内容的提问来源于stack exchange,提问作者Yusuf
相关产品推荐
相关产品推荐

