多列排序按by列表顺序逐级嵌套:先排首列,相同时再排次列;ascending必须用等长布尔列表指定各列方向,na_position统一控制NaN位置,升序时NaN默认排末尾。

sort_values 里多列排序的写法和顺序怎么定
多列排序不是简单把列名堆一起,by 参数传列表,但顺序决定优先级:靠前的列先排,相同时再按后一列排。比如 df.sort_values(by=['city', 'age']) 先按 city 升序,同城市内再按 age 升序。
常见错误是以为列顺序无关,结果发现排序结果不符合预期——其实是第一列还没分出先后,第二列根本没机会“发力”。
-
by必须是列表,不能是字符串('col1, col2'会报错) - 每列默认升序,降序需用
ascending参数配合布尔值或列表 - 如果只对某几列降序,
ascending得传布尔列表,长度必须和by一致,比如ascending=[True, False]
ascending=False 只影响一列?那多列不同方向怎么设
单独写 ascending=False 是全局生效,所有排序列都变降序。真要混合方向,必须用布尔列表,位置一一对应 by 中的列。
比如想按 region 升序、sales 降序:df.sort_values(by=['region', 'sales'], ascending=[True, False])。漏掉一个值或长度不匹配,直接抛 ValueError: Length of ascending must match length of by。
立即学习“Python免费学习笔记(深入)”;
- 布尔列表里写
0/1不行,必须是True/False - 用变量存方向时注意类型,
bool(0)是False,但显式写更安全 - Python 3.8+ 支持海象运算符,但这里没必要,可读性反而下降
空值(NaN)在多列排序里到底排哪去
默认情况下,NaN 在升序中排最后,降序中排最前。这个行为对每列独立生效,不是整体“把含 NaN 的行踢到最后”。
比如两列都有 NaN:df.sort_values(['a', 'b']),先看 a 列,NaN 行被归为一组排末尾;这组内部再按 b 排,此时 b 的 NaN 又在该子组末尾。结果就是“全 NaN 行”不一定扎堆,可能被拆开。
- 统一控制 NaN 位置用
na_position='first'或'last'(默认) -
na_position是全局参数,不能 per-column 设置 - 如果业务要求“含任意 NaN 的行置顶”,得先构造辅助列,比如
df['has_na'] = df[['a','b']].isna().any(axis=1),再参与排序
性能和链式调用里 sort_values 容易被忽略的点
大表排序很慢,sort_values 默认不修改原 DataFrame,返回新对象。但如果后续还接 .loc 或赋值,容易误以为原数据已排序,实际查的是旧视图。
另一个坑是链式调用:写成 df.sort_values(...).reset_index(drop=True) 没问题,但若中间穿插了 .assign() 或条件筛选,要注意索引是否连续、是否触发 SettingWithCopyWarning。
- 就地排序加
inplace=True,但 Pandas 2.0+ 已弃用,别用 - 排序后重置索引常用,但
reset_index(drop=True)不是必须的,除非下游逻辑依赖连续整数索引 - 真正影响性能的是
kind参数,默认'quicksort'不稳定(相同值相对顺序可能变),要稳定排序改用'mergesort',但内存多耗 20%–30%
多列排序本身不复杂,难的是理解“逐列嵌套比较”的逻辑,以及 NaN 和空字符串混在一起时,不同列的缺失值行为并不协同。实操中建议先用 head(10) 看排序片段,比盯着参数猜靠谱得多。


















