使用pandas groupby()高效生成新DataFrame的方法
高效实现ID分组的宽表转换
针对你的需求,用pivot或pivot_table替代groupby.apply是最优解——这两个方法是Pandas内置的矢量化操作,完全避免了apply的Python级循环,处理大数据集时效率提升非常明显。
核心思路
- 保留每个ID对应的常量列(每个ID下值唯一)
- 将目标列按
duration作为后缀,从长表转换为宽表 - 合并常量列与转换后的目标列,得到最终结果
代码实现
1. 基础场景(常量列无脏数据)
假设你的常量列在每个ID下值完全一致,直接用pivot即可:
import pandas as pd # 示例数据 data = { 'id': [5321, 5321, 5321], 'const_field_1': ['a', 'a', 'a'], 'const_field_2': ['b', 'b', 'b'], 'duration': ['1min', '2min', '5min'], 'target_field_1': ['d1', 'd2', 'd3'], 'target_field_2': ['x1', 'x2', 'x3'] } df = pd.DataFrame(data) # 定义常量列和目标列 const_cols = ['const_field_1', 'const_field_2'] target_cols = ['target_field_1', 'target_field_2'] # 透视转换目标列 pivoted = df.pivot( index=['id'] + const_cols, # ID+常量列作为索引 columns='duration', # 用duration作为列的后缀来源 values=target_cols # 需要转换的目标列 ) # 合并多级列名为"目标列_时长"格式 pivoted.columns = [f'{col[0]}_{col[1]}' for col in pivoted.columns] # 重置索引得到最终结果 result = pivoted.reset_index()
运行后result的输出完全符合你的需求:
id const_field_1 const_field_2 target_field_1_1min target_field_1_2min target_field_1_5min target_field_2_1min target_field_2_2min target_field_2_5min 0 5321 a b d1 d2 d3 x1 x2 x3
2. 兼容脏数据场景(常量列可能存在不一致)
如果常量列在某些ID下有重复/不一致值,可以先单独提取每个ID的常量值,再和透视后的目标列合并:
# 提取每个ID的常量列(取第一个值,也可根据需求用mean/max等) const_df = df.groupby('id')[const_cols].first().reset_index() # 透视目标列(仅用ID作为索引) target_pivot = df.pivot( index='id', columns='duration', values=target_cols ) target_pivot.columns = [f'{col[0]}_{col[1]}' for col in target_pivot.columns] target_pivot = target_pivot.reset_index() # 合并常量列与目标列 result = pd.merge(const_df, target_pivot, on='id')
3. 处理重复的(ID+时长+目标列)组合
如果存在同一ID下相同duration对应多个目标值的情况,用pivot_table指定聚合函数:
pivoted = df.pivot_table( index=['id'] + const_cols, columns='duration', values=target_cols, aggfunc='first' # 可选:mean/last/max等,根据业务需求选择 )
为什么比groupby.apply高效?
groupby.apply会对每个分组调用自定义函数,涉及大量Python对象的创建和循环,属于解释型运算;而pivot/pivot_table是Pandas底层基于C实现的矢量化运算,直接对整列数据操作,速度能提升数倍甚至数十倍,尤其当数据量较大时差距更明显。
内容的提问来源于stack exchange,提问作者jzhu379
相关产品推荐
相关产品推荐

