如何实现Pandas DataFrame MultiIndex多层级自定义排序
问题核心原因
你之前的自定义排序在第二个层级失效,本质是对sort_index的key参数的工作机制存在误解:
key函数的输入,是对应索引层级上、和当前DataFrame行顺序完全对齐的原始值序列- 要求
key的返回值必须和输入长度完全一致、逐位置一一对应,返回值是每个位置元素对应的排序权重,供pandas全局匹配行的先后顺序 - 你之前的
do_sort实现,是把传入的整个序列做全局重排后返回新的索引对象,直接打乱了逐行对应的映射关系,因此只有第一层级的排序能偶然符合预期,第二层级的权重值已经和行位置完全错位,自然无法达到预期效果。
正确实现方案
方案一:修正key函数的返回逻辑
你原本定义的low/medium/high排序权重映射逻辑是完全正确的,只需要调整key函数的返回内容,不要做全局重排,只做逐元素的权重映射即可:
def do_sort(s): # 定义排序权重,数值越小排序优先级越高 mapping = { 'low': 0, 'medium': 1, 'high': 2 } # 逐元素映射为权重值,保持和输入s等长、位置完全对齐 return s.map(mapping)
调用排序时,直接指定要排序的两个索引层级即可:
sorted_data = data.sort_index( level=['score', 'grade'], key=do_sort )
执行后得到的结果会严格遵循你要的排序规则:
- 所有
score=low的行排在最前面,组内按照grade的low、medium、high顺序排列 - 后续依次是
score=medium的行,组内同样按grade的自定义顺序排列 - 最后是
score=high的行,组内按grade的自定义顺序排列
方案二:使用有序分类索引
这是Pandas处理自定义离散值排序的推荐原生方式,一旦设置完成,后续所有涉及索引的排序、分组操作都会自动遵循定义的顺序,不需要每次重复传入自定义逻辑:
# 定义全局统一的排序优先级 priority_order = ['low', 'medium', 'high'] # 将两个索引层级都转换为有序分类类型 data.index = data.index.set_levels( [pd.Categorical(level, categories=priority_order, ordered=True) for level in data.index.levels], level=[0, 1] ) # 直接调用默认排序即可,无需额外传key sorted_data = data.sort_index()
注意:如果你的两个索引层级的取值范围不完全一致,也可以分别为两个层级定义独立的优先级列表,逻辑是完全相同的。
内容的提问来源于stack exchange,提问作者Jane Wayne
相关产品推荐
相关产品推荐

