
本文介绍如何对形如 "M1/2023"、"M10/2024" 的混合字符串列名,按“年份优先、会议序号次之”进行自然排序(natural sort),避免 "M10/2023" 错排在 "M2/2023" 之前的问题。
本文介绍如何对形如 "m1/2023"、"m10/2024" 的混合字符串列名,按“年份优先、会议序号次之”进行**自然排序(natural sort)**,避免 "m10/2023" 错排在 "m2/2023" 之前的问题。
在处理时间序列或分组标识类列名(如会议编号 M1/2023、M10/2024)时,直接使用 sorted(df.columns) 或 df.sort_values() 无法满足业务需求——因为默认字典序会将 "M10/2023" 排在 "M2/2023" 之前('M10' < 'M2' 为 True)。正确做法是:先按年份(/ 后部分)升序,再按会议序号(/ 前的数字部分)做自然排序(即 M1, M2, ..., M10 顺序)。
✅ 推荐方案:使用 natsort + str.split 构建排序索引
需先安装 natsort(轻量级、专为自然排序设计):
pip install natsort
然后执行以下代码重排列顺序:
from natsort import natsort_key
# 将列名转为 Series,按 '/' 拆分为两列:[会议标识, 年份]
col_series = df.columns.to_series()
split_df = col_series.str.split('/', expand=True)
# 按第1列(年份)升序、第0列(如 M1、M10)自然排序,并获取原始列名索引
sorted_index = split_df.sort_values(by=[1, 0], key=natsort_key).index
# 用新顺序重排 DataFrame 列
df_sorted = df[sorted_index]? 关键点说明:
- expand=True 确保 str.split('/') 返回 DataFrame,便于按列(by=[1, 0])多级排序;
- key=natsort_key 使 M1, M2, M10 按数值大小而非字符串比较,解决“M10 < M2”的陷阱;
- sort_values(...).index 返回的是原始列名的重排位置索引,可安全用于 df[...] 切片,不会丢失数据或产生 NaN。
⚠️ 注意事项与常见误区
- ❌ 不要尝试用 df.rename() 或字典映射后 reindex() —— 若新列名不在原 df.columns 中,reindex() 会补 NaN;
- ❌ 避免手动拼接年份前缀(如 '2023_M1')再排序:虽可行,但冗余且易出错,且未解决 M10 的自然序问题;
- ✅ 若无法安装第三方库,可用 re 提取数字 + sorted(..., key=lambda x: (int(x.split('/')[1]), int(re.search(r'\d+', x).group()))) 替代,但可读性与健壮性下降。
? 总结
列头重排序本质是对列名字符串进行结构化解析 + 多级自然排序。pandas 本身不内置自然排序,但借助 natsort 可以简洁、可靠地实现:先按年份分组,再在每组内按会议序号数值升序排列。该方法适用于任何含嵌套编号的列名场景(如 "Q1-2023", "v2.1.0", "item_100"),是数据清洗与报表准备中的实用技巧。

















