如何对Pandas DataFrame按多列排序且首列实现自然排序?
问题分析与解决
你的代码错误原因
你之前的sort_values调用中,key参数的用法完全错误:
- Pandas的
key参数在处理多列排序时,要么是对by中的每一列单独应用对应函数,要么是接收by指定列组成的DataFrame,返回用于排序的键DataFrame。 - 你的代码里
lambda x: np.argsort(index_natsorted(inFrame['Col_Arg']))直接返回了一个固定的索引数组,这个数组是基于原始DataFrame的Col_Arg列生成的,完全忽略了Col_Step列的存在。排序时只会按照这个固定索引数组重新排列行,导致Col_Step的排序规则完全失效,相同Col_Arg的行只会保留原始数据中的相对顺序。
正确的多列自然排序实现
方法一:使用字典形式指定各列的key(Pandas 1.4.0+支持)
针对Col_Arg列应用自然排序,Col_Step列使用默认数值排序,直接用字典为每列指定对应的处理函数:
import natsort import pandas as pd # 示例输入数据 inFrame = pd.DataFrame({ 'Col_Arg': ['1 First', '2 Second', '1 First'], 'Col_Step': [20, 10, 10] }) # 多列排序:Col_Arg自然排序,Col_Step升序 sortedFrame = inFrame.sort_values( by=['Col_Arg', 'Col_Step'], key={'Col_Arg': lambda s: natsort.index_natsorted(s), 'Col_Step': lambda s: s} )
执行后得到的正确结果:
| Col_Arg | Col_Step |
|---|---|
| 1 First | 10 |
| 1 First | 20 |
| 2 Second | 10 |
方法二:兼容低版本Pandas的写法
如果你的Pandas版本低于1.4.0,不支持字典形式的key,可以构造包含排序键的DataFrame作为返回值:
sortedFrame = inFrame.sort_values( by=['Col_Arg', 'Col_Step'], key=lambda df: pd.DataFrame({ 'Col_Arg': natsort.index_natsorted(df['Col_Arg']), 'Col_Step': df['Col_Step'] }) )
这个lambda函数接收by指定的两列组成的DataFrame,返回一个新的DataFrame,其中Col_Arg列是自然排序的索引,Col_Step列保留原数值,Pandas会按这个新DataFrame的列顺序完成排序。
后续需求:设置初始为10、步长10的索引
排序完成后,你可以通过以下代码设置新的索引:
# 先重置原索引(避免保留原始行号) sortedFrame = sortedFrame.reset_index(drop=True) # 设置从10开始,每次递增10的索引 sortedFrame.index = pd.RangeIndex(start=10, stop=10 + len(sortedFrame)*10, step=10)
执行后,sortedFrame的索引会是[10, 20, 30](对应示例中的3行数据)。
内容的提问来源于stack exchange,提问作者airjabus
相关产品推荐
相关产品推荐

