推荐用 rename() 批量改列名:安全(只改存在的键)、灵活(支持字典映射和函数式重命名,如加前缀或转小写),并兼容索引、multiindex;set_axis() 适用于全量覆盖且长度严格匹配的场景。

用 rename() 批量改列名,别直接赋值 columns
直接写 df.columns = ["a", "b", "c"] 看似快,但容易出错:列数不匹配时会报 ValueError: Length mismatch,且无法按条件筛选重命名(比如只改含"price"的列)。rename() 更安全、更灵活。
推荐用字典映射:df.rename(columns={"old1": "new1", "old2": "new2"})。它只改存在的键,缺失键被忽略,不报错;也支持函数式重命名,比如统一加前缀:df.rename(columns=lambda x: f"col_{x}")。
- 注意:默认返回新 DataFrame,原地修改要加
inplace=True(但建议链式调用,少用inplace) - 若列名含空格或特殊字符,字典键必须严格匹配原始字符串(区分大小写、空格)
- 重命名后若需验证,可检查
df.columns.tolist(),别只看print(df)—— Jupyter 有时显示截断
重命名索引标签用 rename() 的 index 参数
和列名一样,索引标签也能批量改,只是参数名换成 index:df.rename(index={0: "row_a", 1: "row_b"})。常见场景是把数字索引替换成业务 ID,或修复读取 CSV 时误把首行当列名导致的脏索引。
函数式用法同样有效,比如把所有索引转小写:df.rename(index=str.lower);或者用 range 重置为连续整数(但这时更适合用 reset_index(drop=True))。
- 如果索引是
DatetimeIndex,rename(index=...)不起作用——它只对 label 生效,不对时间戳本身做转换 - 想批量替换索引中某段子串?先转成列表处理再赋回:
df.index = df.index.astype(str).str.replace("OLD", "NEW") -
rename()对 MultiIndex 也支持,但字典键必须是元组,例如{("A", "X"): ("B", "Y")}
用 set_axis() 替换整套列名或索引,适合“全量覆盖”场景
当你确定要完全替换全部列名(不保留任何旧名),set_axis() 比 rename() 更直白:df.set_axis(["a", "b", "c"], axis=1)(axis=1 表示列);axis=0 则对应索引。
它的优势是语义清晰、不依赖旧名匹配,适合从外部配置读取新列名列表的场景(如对接不同数据源的字段映射表)。但风险也明显:长度必须严格一致,否则抛 ValueError: Length mismatch。
- 它不接受字典或函数,只接受 list/tuple/Index 类型
- 如果新名称里有重复值,Pandas 不报错,但后续按标签选取(如
df["col"])会出问题——务必提前去重 - 和
rename()一样,默认返回新对象;若配合copy=False,在某些视图场景下可能触发SettingWithCopyWarning,慎用
别忽略链式操作中的重命名时机
在 groupby().agg() 或 pd.concat() 后,列名常被自动改造(比如变成多级索引或带聚合函数后缀),这时再用 rename(columns=...) 可能失效——因为目标列名已不是字符串,而是元组或 frozenset。
典型例子:df.groupby("cat").sum().rename(columns={"val": "total"}) 在单列聚合时有效,但多列时列名是元组,得写成 {("val", "sum"): ("total", "sum")},或者先用 droplevel() 扁平化。
- 不确定当前列类型?查
type(df.columns)—— 是Index还是MultiIndex - 用
df.columns.map(str)强制转字符串再 rename,适用于简单扁平化,但会丢失结构信息 - 最稳妥的做法:在链式操作早期就固定列名,比如读取后立刻
rename(),避免后期“猜”列名格式
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











