执行groupby操作后,如何从DataFrame中获取其他列?
解决Pandas Groupby后丢失关键列的问题
核心问题分析
你原来的代码存在两个关键问题:
- 用
x.day分组会把不同月份的同一天(比如1月1日和2月1日)错误归为一组,逻辑不严谨; grouping.apply(...)返回的是单个布尔值,无法携带recipient_id和完整日期这类字段,自然会丢失信息。
改进方案(直接保留所需字段)
通过agg()方法直接提取分组后的关键信息,既能避免分组逻辑错误,又能完整保留需要的列:
import pandas as pd # 转换日期格式为datetime类型 caller_history['date_called'] = pd.to_datetime(caller_history['date_called'], format='%Y-%m-%d %H:%M:%S') # 按「呼叫者ID+完整自然日」分组,提取每组的首次/末次通话信息 grouped_data = caller_history.groupby( ['caller_id', caller_history['date_called'].dt.date], as_index=False ).agg( recipient_id=('recipient_id', 'first'), # 首次和末次相同,取任意一个即可 first_call_time=('date_called', 'first'), last_call_time=('date_called', 'last') ) # 筛选首次与末次通话对象一致的记录 final_result = grouped_data[ grouped_data['recipient_id'] == grouped_data.groupby(['caller_id', 'date_called'])['recipient_id'].transform('last') ] # 整理成要求的输出格式 final_output = final_result[['caller_id', 'recipient_id', 'date_called']] print(final_output)
关键细节说明
- 分组逻辑修正:用
date_called.dt.date替代x.day,确保同一个自然日的通话才会被分到一组,避免跨月日期混淆; - 保留字段技巧:使用
agg()方法直接指定要提取的字段和规则,相比apply()返回单个值,能完整保留分组后的关键信息; - 筛选逻辑简化:因为首次和末次
recipient_id相同,所以直接用first提取的值和last提取的值对比即可,完全匹配需求。
另一种思路(对齐你原有的排序逻辑)
如果你更倾向于先排序再处理,可以用标记首次/末次通话的方式实现:
import pandas as pd caller_history['date_called'] = pd.to_datetime(caller_history['date_called'], format='%Y-%m-%d %H:%M:%S') # 按呼叫者ID和通话时间排序 caller_history = caller_history.sort_values(by=['caller_id', 'date_called']) # 标记每个呼叫者每天的首次和末次通话 caller_history['is_first'] = caller_history.groupby(['caller_id', caller_history['date_called'].dt.date]).cumcount() == 0 caller_history['is_last'] = caller_history.groupby(['caller_id', caller_history['date_called'].dt.date]).cumcount(ascending=False) == 0 # 提取首次和末次通话记录,合并后筛选匹配项 first_calls = caller_history[caller_history['is_first']][['caller_id', 'recipient_id', 'date_called']] last_calls = caller_history[caller_history['is_last']][['caller_id', 'recipient_id', 'date_called']] merged = pd.merge(first_calls, last_calls, on=['caller_id', 'date_called'], suffixes=('_first', '_last')) final_output = merged[merged['recipient_id_first'] == merged['recipient_id_last']][['caller_id', 'recipient_id_first', 'date_called']] final_output.rename(columns={'recipient_id_first': 'recipient_id'}, inplace=True) print(final_output)
内容的提问来源于stack exchange,提问作者Jgl
相关产品推荐
相关产品推荐

