Pandas实现自定义多规则排序并封装为可复用函数
pandas按自定义规则排序分组列实现方案
问题背景
现有如下结构的pandas DataFrame:
PLAYER GRP Mike F3.03 Max F2.01 El G7.99 Billy G7.09 Steve B13.99 Vecna F3.03
需要按grp列做升序排序,排序优先级从高到低为:
- 字段开头的字母
- 小数点前的数字
- 小数点后的数字
当grp取值完全相同时,按player列升序排列。实际场景中小数点后的数字存在前导零,小数点前的数字无前导零,期望排序结果如下:
PLAYER GRP Steve B13.99 Max F2.01 Mike F3.03 Vecna F3.03 Billy G7.09 El G7.99
要求将排序逻辑封装为可复用函数,适配所有包含同结构分组列的DataFrame。
示例数据初始化代码:
import pandas as pd df = pd.DataFrame({'player': ['Mike', 'Max', 'El', 'Billy', 'Steve', 'Vecna'], 'grp': ['F3.03', 'F2.01', 'G7.99', 'G7.09', 'B13.99', 'F3.03']})
实现代码
核心思路是通过正则拆分grp列的三个排序维度,数字部分转为整数解决前导零比较问题,再调用pandas原生sort_values完成多键排序,封装为通用函数:
import re import pandas as pd def sort_grp_df(df: pd.DataFrame, grp_col: str = 'grp', name_col: str = 'player') -> pd.DataFrame: """ 按自定义规则对带分组列的DataFrame排序 参数: df: 待排序原始DataFrame grp_col: 分组列列名,默认值为'grp' name_col: 分组重复时用于排序的名称列列名,默认值为'player' 返回: 排序完成、结构与原表一致的DataFrame """ def _parse_grp(grp_val: str): # 正则匹配拆分首字母、小数点前数字、小数点后数字 parts = re.match(r'([A-Za-z]+)(\d+)\.(\d+)', grp_val) if not parts: raise ValueError(f"值 {grp_val} 不符合分组列格式要求") letter, num_pre, num_post = parts.groups() # 数字转整数,自动处理前导零的数值比较逻辑 return letter, int(num_pre), int(num_post) df_work = df.copy() # 生成三个临时排序键 df_work[['_sort_letter', '_sort_pre', '_sort_post']] = df_work[grp_col].apply(_parse_grp).tolist() # 按优先级排序后删除临时列 df_res = df_work.sort_values( by=['_sort_letter', '_sort_pre', '_sort_post', name_col], ascending=True, ignore_index=True ).drop(columns=['_sort_letter', '_sort_pre', '_sort_post']) return df_res # 测试调用 if __name__ == "__main__": df = pd.DataFrame({'player': ['Mike', 'Max', 'El', 'Billy', 'Steve', 'Vecna'], 'grp': ['F3.03', 'F2.01', 'G7.99', 'G7.09', 'B13.99', 'F3.03']}) print(sort_grp_df(df))
说明
- 正则匹配逻辑兼容首字母长度大于1的场景,后续如果出现类似
AB12.03格式的分组值也能正常排序 - 数字部分统一转为整数类型比较,无需额外处理前导零,比如
G7.09和G7.99比较时,9<99,排序结果符合预期 - 函数支持自定义列名传入,如果实际表中分组列叫
Group、人员列叫PLAYER,直接调用sort_grp_df(df, grp_col='Group', name_col='PLAYER')即可复用 - 测试运行输出结果和期望完全一致:
player grp 0 Steve B13.99 1 Max F2.01 2 Mike F3.03 3 Vecna F3.03 4 Billy G7.09 5 El G7.99
内容的提问来源于stack exchange,提问作者DJC
相关产品推荐
相关产品推荐

