如何在Pandas分组聚合结果中补充对应行数据
问题描述
我有如下结构的Pandas DataFrame:
import pandas as pd df = pd.DataFrame([[1,'A','X','1/2/22 12:00:00AM','1/1/22 12:00:00 AM'], [1,'A','X','1/1/22 1:00:00AM','1/1/22 12:00:00 AM'], [1,'A','Y','1/3/22 12:00:00AM','1/2/22 12:00:00 AM'], [1,'B','X','1/1/22 1:00:00AM','1/1/22 12:00:00 AM'], [2,'A','X','1/2/22 12:00:00AM','1/1/22 12:00:00 AM'], [2,'A','X','1/1/22 1:00:00AM','1/1/22 12:00:00 AM']], columns = ['ID','Category','Site','Task Completed','Access Completed'])
对应的表格:
| ID | Category | Site | Task Completed | Access Completed |
|---|---|---|---|---|
| 1 | A | X | 1/2/22 12:00:00AM | 1/1/22 12:00:00 AM |
| 1 | A | Y | 1/3/22 12:00:00AM | 1/2/22 12:00:00 AM |
| 1 | A | X | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
| 1 | B | X | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
| 2 | A | X | 1/2/22 12:00:00AM | 1/1/22 12:00:00 AM |
| 2 | A | X | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
注意:每个ID/Site/Category组合对应的Access Completed日期是一致的,不受实例数量影响。
我需要计算每个ID/Category/Site组合的Access Completed与首次Task Completed之间的时间差(小时),同时在结果中保留首次Task Completed日期和Access Completed日期。
现有代码如下:
df[['Task Completed','Access Completed']] = \ df[['Task Completed','Access Completed']].apply(lambda x: pd.to_datetime(x)) res = df.sort_values('Task Completed').groupby(['ID','Category','Site']).first() res = res['Task Completed'].sub(res['Access Completed'])\ .dt.total_seconds().div(3600).reset_index(drop=False).rename( columns={0:'Time Difference'})
当前输出:
ID Category Site Time Difference 0 1 A X 1.0 1 1 A Y 24.0 2 1 B X 1.0 3 2 A X 1.0
期望结果:
| ID | Category | Site | Time Difference | First Task Completed | Access Completed |
|---|---|---|---|---|---|
| 1 | A | X | 1 | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
| 1 | A | Y | 24 | 1/3/22 12:00:00AM | 1/2/22 12:00:00 AM |
| 1 | B | X | 1 | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
| 2 | A | X | 1 | 1/1/22 1:00:00AM | 1/1/22 12:00:00 AM |
解决方案
不需要丢弃分组后的其他列,直接在分组结果上计算时间差,同时保留需要的日期列即可:
import pandas as pd # 转换时间列为datetime类型 df[['Task Completed','Access Completed']] = df[['Task Completed','Access Completed']].apply(pd.to_datetime) # 按分组键聚合,保留首次任务完成时间和对应访问完成时间 grouped = df.sort_values('Task Completed').groupby(['ID','Category','Site']).agg( First_Task_Completed=('Task Completed', 'first'), Access_Completed=('Access Completed', 'first') ).reset_index() # 计算小时级时间差 grouped['Time Difference'] = (grouped['First_Task_Completed'] - grouped['Access_Completed']).dt.total_seconds() / 3600 # 调整列顺序为期望格式 result = grouped[['ID', 'Category', 'Site', 'Time Difference', 'First_Task_Completed', 'Access_Completed']] # 可选:将时间列格式化为原字符串样式 result['First_Task_Completed'] = result['First_Task_Completed'].dt.strftime('%m/%d/%y %I:%M:%S%p') result['Access_Completed'] = result['Access_Completed'].dt.strftime('%m/%d/%y %I:%M:%S %p') # 可选:将时间差转为整数 result['Time Difference'] = result['Time Difference'].astype(int) print(result)
运行后输出:
ID Category Site Time Difference First_Task_Completed Access_Completed 0 1 A X 1 01/01/22 01:00:00AM 01/01/22 12:00:00 AM 1 1 A Y 24 01/03/22 12:00:00AM 01/02/22 12:00:00 AM 2 1 B X 1 01/01/22 01:00:00AM 01/01/22 12:00:00 AM 3 2 A X 1 01/01/22 01:00:00AM 01/01/22 12:00:00 AM
说明
- 使用
agg方法明确指定需要保留的列,避免丢失日期信息; - 计算时间差时直接基于保留的日期列操作;
- 最后可根据需求格式化时间列的显示样式,以及调整时间差的类型;
- 因为每个分组的
Access Completed日期一致,用first/max/min都能得到正确值。
内容的提问来源于stack exchange,提问作者CowboyCoder
相关产品推荐
相关产品推荐

