Pandas DataFrame:分组、排序并扁平化(无聚合)实现方案
高效实现运动员数据按队分组并转宽表
问题背景
现有运动员DataFrame,包含AthleteID、TeamID、Name、Score字段,每队最多20名运动员:
原数据:
AthleteID TeamID Name Score 1 2 Bob 4.9 2 1 Pete 4.6 3 2 Steve 4.5 4 1 Jim 3.6 5 3 Frank 4.2
需将数据处理为每队一行,按Score降序排序后生成带排名后缀的列,目标格式:
TeamID AthleteID_1 Name_1 Score_1 AthleteID_2 Name_2 Score_2 1 2 Pete 4.6 4 Jim 3.6 2 1 Bob 4.9 3 Steve 4.5 3 5 Frank 4.2 None None None
高效实现方案(无需迭代)
用Pandas的分组、排序、透视组合操作替代迭代逻辑,代码简洁且性能更优:
- 分组排序并生成组内排名
先按TeamID分组,每组内按Score降序排序,为每个运动员分配组内排名(从1开始):
import pandas as pd # 构造原数据 df = pd.DataFrame({ 'AthleteID': [1,2,3,4,5], 'TeamID': [2,1,2,1,3], 'Name': ['Bob','Pete','Steve','Jim','Frank'], 'Score': [4.9,4.6,4.5,3.6,4.2] }) # 分组排序后生成组内排名 df_sorted = df.sort_values(['TeamID', 'Score'], ascending=[True, False]) df_sorted['rank'] = df_sorted.groupby('TeamID').cumcount() + 1
- 透视转宽表
使用pivot将长表转为宽表,把排名作为列的后缀:
# 透视生成带排名后缀的列 df_wide = df_sorted.pivot( index='TeamID', columns='rank', values=['AthleteID', 'Name', 'Score'] ) # 调整列名格式(如AthleteID_1、Name_1) df_wide.columns = [f'{col[0]}_{col[1]}' for col in df_wide.columns] # 重置索引,让TeamID回到列中 df_wide = df_wide.reset_index() # 填充缺失值为None,限制最多20列(对应每队最多20人) max_athletes = 20 for i in range(1, max_athletes+1): for col in ['AthleteID', 'Name', 'Score']: col_name = f'{col}_{i}' if col_name not in df_wide.columns: df_wide[col_name] = None df_wide = df_wide.fillna(value=None)
- 调整列顺序(可选)
按排名顺序排列列,让布局更贴近目标格式:
# 构造目标列顺序 cols_order = ['TeamID'] for i in range(1, max_athletes+1): cols_order.extend([f'AthleteID_{i}', f'Name_{i}', f'Score_{i}']) # 过滤存在的列(避免超出实际数据的列报错) cols_order = [col for col in cols_order if col in df_wide.columns] df_wide = df_wide[cols_order]
运行后得到的df_wide就是符合要求的目标数据,全程利用Pandas向量化操作,效率更高且更符合Python风格。
内容的提问来源于stack exchange,提问作者Irina
相关产品推荐
相关产品推荐

