如何将Pandas多列分组聚合结果转为按id单行的宽表
问题描述
现有一段处理时间序列数据的代码:
# 把时间戳转成毫秒 relevant_data_pdf['milli'] = pd.to_datetime(relevant_data_pdf['timestamp']).astype(np.int64) / int(1e6) # 排序(inf_day取值1到7) relevant_data_pdf = relevant_data_pdf.sort_values(['id', 'inf_day', 'milli']) # 计算连续行的时间差 relevant_data_pdf['milli_diff'] = relevant_data_pdf.groupby(['id', 'inf_day'])['milli'].diff() # 多指标聚合 relevant_data_pdf = relevant_data_pdf.groupby(['id', 'inf_day']).agg(avg=('milli_diff', np.mean), median=('milli_diff', np.median), max=('milli_diff', np.max), min=('milli_diff', np.min))
运行后得到多层索引的DataFrame结果:
avg median max min id inf_day 1 1 8.060000e+06 7200000.0 16500000.0 480000.0 2 1.200333e+06 1771000.0 1800000.0 30000.0 3 5.400000e+06 5400000.0 7200000.0 3600000.0 2 0 1.800000e+06 1800000.0 3600000.0 0.0 2 0.000000e+00 0.0 0.0 0.0 3 0.000000e+00 0.0 0.0 0.0
需要将结果转换为每个id对应一行,列名格式为{inf_day}_{metric_name}(例如1_avg、2_median)的形式。
解决方案
可以通过pandas的unstack()方法调整索引层级,再合并列名实现需求:
# 将inf_day从行索引转成列的上层级 df_unstacked = relevant_data_pdf.unstack(level='inf_day') # 拼接列名为inf_day_metric的格式 df_unstacked.columns = [f'{day}_{metric}' for metric, day in df_unstacked.columns] # 可选:将id从索引转为普通列 result = df_unstacked.reset_index()
处理后得到的结果示例:
id 1_avg 1_median 1_max 1_min 2_avg 2_median 2_max 2_min 3_avg ... 0 1 8.06e+06 7200000.0 16500000.0 480000.0 1.2e+06 1771000.0 1800000.0 30000.0 5.4e+06 ... 1 2 NaN NaN NaN NaN 0.0 0.0 0.0 0.0 0.0 ...
如果需要填充缺失值(比如id=1没有inf_day=0的数据会显示NaN),可以追加fillna():
result = df_unstacked.reset_index().fillna(0)
关键逻辑说明
unstack(level='inf_day'):指定将inf_day这个行索引层级转换为列的层级,此时列名会变成(指标名, inf_day值)的元组形式- 列表推导式遍历列名元组,拼接成要求的
{inf_day}_{metric_name}格式 reset_index():按需将id从索引转为普通列,让结果更符合"每行对应一个id"的直观结构
内容的提问来源于stack exchange,提问作者nirkov
相关产品推荐
相关产品推荐

