Courses
您从公司的数据库拉取了最新的 CSV,运行 df.head(),看到 CUST_ID_NBR、txn_amt_usd_2、Unnamed: 7,或者一个名为 Customer Name (Full) 的列,后面还带着一个不容易发现的空格,直到一个 KeyError 毁掉您整个下午。杂乱的列名是实际数据工作中的小摩擦之一,而在 pandas 中重命名列通常是您在任何真正的分析之前会做的第一步。
在这篇关于如何在 pandas 中重命名列的教程中,您将学到:
-
使用
.rename()重命名单个或多个列 -
使用
df.columns或.set_axis()一次性替换所有列名 -
应用函数批量转换列名
-
使用
.str访问器清理杂乱的列名 -
在
pd.read_csv()载入时重命名列 -
在 Polars 中处理相同任务
-
避免遇到
KeyError和ValueError: Length mismatch
本教程假定您会导入 pandas 并创建一个 DataFrame。我们将贯穿使用贴近真实的数据集,如客户记录、销售导出和传感器读数,让这些范式可以直接映射到您实际处理的数据上。
应选择哪种 Pandas 重命名方法?
选择与任务范围匹配的方法:定向重命名、完全替换,或对每个名称应用统一规则。
|
您的目标 |
方法 |
适用场景 |
|
重命名单个或少数特定列 |
|
其他列保持不变;可安全用于方法链中 |
|
替换所有列名 |
|
比逐个映射更快;当需要链式调用时使用 |
|
按规则重命名(小写、snake_case、去空格) |
|
只需表达一次规则,而非逐列列出 |
|
在加载时重命名 |
|
当您可控模式并且不想要单独步骤时 |
|
在 Polars 中实现以上任意方式 |
|
不可变且链式优先,因此没有 |
如何使用 .rename() 重命名列?
.rename() 方法是执行 pandas DataFrame 列重命名最灵活的方式,也是您最常用的方法。
它接收一个将旧名称映射到新名称的字典,不在字典中的列保持不变,并且默认返回一个新的 DataFrame 而不是修改原始对象。这使得 .rename() 可以安全地用于方法链中,也更便于调试时理解行为。
该字典模式如下所示:
sales_data.rename(columns={"old_name": "new_name"})
如果您对字典不熟悉,建议回顾我们的 Python 字典方法教程。
关于旧版 copy 参数的说明
在看示例前先说明一点。Pandas 3.0 废弃了 copy 参数,并将 Copy-on-Write 设为默认行为。实际效果是,您不再需要担心 .rename() 是否会对数据进行昂贵的复制。pandas 会在底层按需惰性处理。主要需要考虑的参数只剩下 inplace,我们会在第三小节介绍。
重命名单个列
想象您刚加载了一个从旧版 CRM 导出的客户记录。列名的缩写在 2008 年设计数据库的人看来有意义,但对您并不直观。这是最简单的 pandas 重命名操作:一个旧名、一个新名,放进字典中:
import pandas as pd
customers = pd.DataFrame({
"cust_id_nbr": [4521, 4522, 4523, 4524],
"first_nm": ["Abe", "Rick", "Pat", "Kim"],
"signup_dt": ["2008-03-12", "2008-03-15", "2008-03-18", "2008-03-21"]
})
print(customers)

现在,将 cust_id_nbr 重命名为更易读的名称:
customers_renamed = customers.rename(columns={"cust_id_nbr": "customer_id"})
print(customers_renamed)

原始的 customers DataFrame 未被修改。.rename() 返回了一个新的 DataFrame,我们将其赋给 customers_renamed。另外两列(first_nm、signup_dt)保持不变。
重命名多个列
该字典可以自然扩展。要处理 pandas 的多列重命名任务,只需在映射中添加更多键值对:
customers_clean = customers.rename(columns={
"cust_id_nbr": "customer_id",
"first_nm": "first_name",
"signup_dt": "signup_date"
})
print(customers_clean)

还有一种替代语法,使用 mapper 和 axis 参数而不是 columns 关键字:
customers.rename(mapper={"cust_id_nbr": "customer_id"}, axis=1)
axis=1 告诉 pandas 您要操作的是列(相对地,axis=0 针对行索引标签)。两种形式产生相同结果。大多数实战代码使用 columns={...},因为一眼更易读,所以余下教程我们将坚持这种写法。
一个实用细节是,如果传入的键不匹配任何现有列,.rename() 默认会静默忽略。这在编写可复用函数、可能处理略有不同模式的 DataFrame 时很方便,但也可能隐藏拼写错误。若要在未知列名时让 pandas 抛出错误,请传入 errors='raise'。
使用 inplace 与返回新 DataFrame
默认情况下,.rename() 会返回一个新的 DataFrame,并保持原对象不变。如果您希望直接修改现有 DataFrame,请传入 inplace=True:
# 返回一个新的 DataFrame(默认)
customers_v2 = customers.rename(columns={"first_nm": "first_name"})
# 直接修改 customers,本方法返回 None
customers.rename(columns={"first_nm": "first_name"}, inplace=True)
print(customers)

那么该用哪种?多数情况下,默认返回新 DataFrame 更优。调试时也更容易,因为当出现问题时,您仍可检查原始 DataFrame。这也避开了在旧代码中产生 SettingWithCopyWarning 的别名问题。
性能也不再是偏好 inplace 的理由。随着 pandas 3.0+ 中 Copy-on-Write 成为默认,非 inplace 版本使用惰性复制。只有在发生修改时才真正复制数据。inplace=True 节省内存的老观点已大不如前。
唯一仍然自然使用 inplace=True 的场景,是在简短的探索性脚本中,您按步骤清理单个 DataFrame,且不关心链式调用。对于生产代码或日后会回看的内容,优先选择默认方式。
如何一次性重命名 pandas 中的所有列?
有时您并不想把旧名映射到新名,只是想一次性替换所有列名。这种情况比您想象得更常见,比如无表头的 CSV,pandas 会将 0, 1, 2 作为列名;或者表头是其他语言的数据集;又或系统生成的导出,列名像 Field1、Field2、Field3。
常见做法有两种:直接给 df.columns 赋值,或使用 .set_axis()。它们产生相同结果,权衡点在于简洁与可链式调用之间。
给 df.columns 赋值列表
最直接的方法是给 columns 属性赋一个新列表。看这个 DataFrame,由无表头的信息(类似读取无表头 CSV 时的情形)构建。pandas 退化为使用整数列名:
import pandas as pd
sensor_readings = pd.DataFrame([
[1.2, 22.5, 1013],
[1.5, 22.7, 1012],
[1.3, 22.6, 1013]
])
print(sensor_readings)

这些 0、1、2 列名对分析毫无用处。通过给 columns 属性赋一个新列表来替换它们:
sensor_readings.columns = ["wind_speed", "temperature_c", "pressure_hpa"]
print(sensor_readings)

关于这种方法有两点需要注意:
-
列表长度必须完全匹配。若为四列的 DataFrame 仅传三列名,pandas 会抛出
ValueError: Length mismatch(我们稍后将详细讲解)。 -
它会就地修改 DataFrame。这里没有
inplace参数,因为赋值本身就是修改。如果您想得到一个新副本,先用.copy(),或使用下方的.set_axis()。
使用 .set_axis() 进行方法链式调用
.set_axis() 方法做的是同一件事,但会返回新的 DataFrame,因此可以与其他操作链式调用。看一个类似的无表头 DataFrame,这次数据更杂,比如多余的小数位和缺失读数:
raw_sensor = pd.DataFrame([
[1.234, 22.567, 1013],
[1.512, 22.789, 1012],
[None, 22.601, 1013],
[1.345, 22.612, 1013]
])
sensor_clean = (
raw_sensor
.set_axis(["wind_speed_mps", "temp_celsius", "pressure_hpa"], axis=1)
.round(1)
.dropna()
)
print(sensor_clean)

axis=1 参数表示您在设置列标签(使用 axis=0 则设置行索引)。由于 .set_axis() 返回一个新的 DataFrame,它很自然地融入您在实际 ETL 或分析代码中会写的链式转换流水线中。这也是在生产环境更偏好它而非直接赋值的主要原因。
如何在 pandas 中使用函数重命名列?
与其把每个旧名映射到新名,您可以向 .rename() 传入一个函数,pandas 会将其应用到每个列名上。当您有一条规则而不是一个列表时,这正是合适工具。例如“全部小写”或“将空格全部替换为下划线”。
使用内置字符串函数
最简单的情况是标准化大小写。将 str.lower、str.upper 或 str.title 直接传给 columns 参数:
import pandas as pd
orders = pd.DataFrame({
"Order ID": [1001, 1002, 1003],
"Customer Name": ["Abe", "Rick", "Pat"],
"Total Amount": [49.99, 120.00, 75.50]
})
orders_lower = orders.rename(columns=str.lower)
print(orders_lower.columns.tolist())
![]()
注意我们传入的是函数本身(str.lower),而不是调用它(str.lower())。pandas 会逐个将其应用于每个列名。这是大小写标准化的简洁捷径,但它不处理空格或特殊字符。要处理这些,您需要 lambda 或自定义函数。
使用 lambda 与自定义函数
对于超出大小写变换的需求,lambda 提供了在一行内表达转换的便捷方式。如果您未使用过 lambda,可以先阅读我们的 Python lambda 函数入门指南。
常见模式是一步完成小写化和空格替换为下划线。沿用上一个例子:
orders_snake = orders.rename(columns=lambda col: col.lower().replace(" ", "_"))
print(orders_snake.columns.tolist())
![]()
当逻辑更复杂时,将其提炼为具名函数。看这个帮助函数,它将 camelCase 或 PascalCase 列名转换为 snake_case:
import re
def to_snake_case(name: str) -> str:
"""Convert camelCase or PascalCase to snake_case."""
s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name)
s2 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1)
return s2.lower()
api_response = pd.DataFrame({
"userId": [1, 2, 3],
"firstName": ["Abe", "Rick", "Pat"],
"accountCreatedAt": ["2024-01-01", "2024-01-02", "2024-01-03"]
})
api_clean = api_response.rename(columns=to_snake_case)
print(api_clean.columns.tolist())
![]()
像这样的具名函数比精巧的一行式更易于测试、在不同笔记本间复用、并进行文档化。逻辑能在一行表达时用 lambda,否则用自定义函数。
如何在 pandas 中批量清理杂乱的列名?
当数据来自电子表格、第三方 API 或手工编辑的 CSV 时,列名往往存在 .rename() 难以优雅修复的问题,比如:
- 末尾空白
- 大小写混用
- 括号
- 连字符
- 特殊字符
- 不可见的 Unicode 字符
在这些情况下,最干净的做法是使用 .str 访问器直接对 df.columns 操作,它提供了向量化的字符串方法(包括正则),可一次性作用于所有列名。这也是高质量Python 数据清洗的基础。清理列名会让下游每一步(筛选、合并、绘图)更不易出错。
去除空白和特殊字符
看这个 DataFrame,列名类似那种被太多人改动过的 Excel 导出的样子:
import pandas as pd
raw_export = pd.DataFrame({
" Order ID ": [1001, 1002, 1003],
"Customer Name (Full)": ["Abe", "Rick", "Pat"],
"Total Amount ($)": [49.99, 120.00, 75.50],
"Order-Date": ["2024-03-12", "2024-03-15", "2024-03-18"]
})
print(raw_export.columns.tolist())
![]()
前后空格是最常见也最令人挠头的问题,因为它们不可见。用一行代码去掉它们:
raw_export.columns = raw_export.columns.str.strip()
print(raw_export.columns.tolist())
![]()
对于特殊字符,.str.replace() 可接受正则模式。下面的模式保留字母、数字、下划线和空格,去掉其他所有字符:
raw_export.columns = raw_export.columns.str.replace(r"[^a-zA-Z0-9_ ]", "", regex=True)
print(raw_export.columns.tolist())
![]()
连字符、括号和美元符号都没了。请注意,Total Amount 现在末尾带了一个空格(原先 ($) 所在的位置),而 OrderDate 则完全丢失了连字符。这正是为什么我们会在清洗流水线末尾再进行一次 strip。
标准化为 snake_case
一个常见的最佳实践是在开始分析前,将所有列名转换为 snake_case:即全部小写、以下划线分隔单词、不含特殊字符。将 .str 方法串联起来,一条表达式即可达成:
raw_export = pd.DataFrame({
" Order ID ": [1001, 1002, 1003],
"Customer Name (Full)": ["Abe", "Rick", "Pat"],
"Total Amount ($)": [49.99, 120.00, 75.50],
"Order-Date": ["2024-03-12", "2024-03-15", "2024-03-18"]
})
raw_export.columns = (
raw_export.columns
.str.strip() # 移除首尾空白
.str.lower() # 全部小写
.str.replace(r"[^a-z0-9]+", "_", regex=True) # 将非字母数字字符压缩为下划线
.str.strip("_") # 移除首尾下划线
)
print(raw_export.columns.tolist())
![]()
四行代码,列名就变得可预测、全小写并用下划线分隔。值得将这一模式保存为一个工具函数。一旦有了它,来多少“脏” DataFrame 都能应对自如。
您也常会把重命名与删除列结合使用。有关这一步的内容,请参阅pandas 删除列教程。
如何在 pandas 加载数据时重命名列?
如果在加载文件之前您就已经知道需要不同的列名,可以直接在 pd.read_csv() 中进行重命名。向 names 参数传入一个名称列表,并设置 header=0 以告知 pandas 跳过现有表头,改用您的列名:
import pandas as pd
from io import StringIO
# Simulating a CSV file for demonstration
csv_data = """txnId,custId,amt,date
1001,C01,49.99,2024-01-15
1002,C02,125.00,2024-01-16
1003,C01,79.50,2024-01-17"""
# Renames columns at load time, skipping the original header
transactions = pd.read_csv(
StringIO(csv_data),
header=0,
names=["transaction_id", "customer_id", "amount_usd", "transaction_date"]
)
print(transactions)

当您可控模式并不想让单独的 .rename() 步骤使加载代码变得杂乱时,这是一个很有用的捷径。如果文件根本没有表头行,省略 header=0,直接用 names=[...] 从零指定列名。若想更深入了解数据加载选项,建议阅读 pandas read_csv() 教程。
但需注意:这是一个全或无的方式。names 参数会替换每个列名,因此列表长度必须与文件中的列数完全一致。如果您只想重命名少数列,请先加载文件,然后使用 .rename()。
若想在引导式演练中将这些模式与其他常见清理任务结合起来学习,推荐参加我们的 Cleaning Data in Python 课程。
在 Polars 与 Pandas 中重命名列
如果您在 pandas 和 Polars 之间切换,或有此预期,了解它们各自如何处理列重命名是值得的。高层 API 相似,但细节有所不同,第一次会有些出乎意料。Polars 是一个以 Rust 为后端的高速 DataFrame 库,在现代数据栈中越来越常见,而您在 pandas 中形成的肌肉记忆并不总能无缝迁移。
核心思路是相同的:用字典将旧名映射到新名。差别在细节上。Polars 设计为不可变(无 inplace),链式调用是惯用风格,且在 select 中进行列级重命名时使用 .alias(),而不是单独的重命名步骤。
并排比较
|
任务 |
Pandas |
Polars |
|
重命名特定列 |
|
|
|
替换所有列名 |
|
|
|
在选择时重命名 |
先选择,再用 |
|
|
就地修改 |
支持 |
不支持。始终返回新的 DataFrame |
|
惯用风格 |
|
始终链式调用 |
两种库中的相同重命名
做个对比,以下是在两个库中的简单重命名。
Pandas:
# Pandas
import pandas as pd
orders_pd = pd.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
orders_pd = orders_pd.rename(columns={"ord_id": "order_id", "cust_nm": "customer_name"})
print(orders_pd)

Polars:
# Polars
import polars as pl
orders_pl = pl.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
orders_pl = orders_pl.rename({"ord_id": "order_id", "cust_nm": "customer_name"})
print(orders_pl)

可以注意到两点小差异。Polars 的 .rename() 直接接收字典,没有 columns= 关键字,因为 Polars 只支持重命名列(无行索引)。并且您必须重新赋值结果,Polars 中没有 inplace=True,每个操作都会返回新的 DataFrame。
Polars 的输出还会内联显示 dtypes(i64、str)以及顶部的形状信息,这是许多人切换过去后会喜欢的小便利之一。
在选择时重命名列
在转换过程中进行重命名时,Polars 在 .select() 或 .with_columns() 中使用 .alias():
# Polars
import polars as pl
orders_pl = pl.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
# Select and rename in one expression
renamed = orders_pl.select(
pl.col("ord_id").alias("order_id"),
pl.col("cust_nm").alias("customer_name")
)
print(renamed)

在 pandas 中,等效做法是在列选择后再 .rename()。两者并无优劣,只是各自库的设计哲学所致。
如果您想更深入地比较二者,我推荐阅读 pandas 与 polars 性能 教程。若您想将 polars 纳入工具箱,推荐参加我们的 Introduction to Polars 课程。
常见错误及其修复方法
在重命名 pandas 列时,有两类错误反复出现。下面是它们的表现、原因以及修复方法。
KeyError:找不到列名
默认情况下,.rename() 会静默忽略与现有列不匹配的键。但如果您传入 errors='raise' 以捕捉拼写错误,那么当键不存在时,您会得到一个 KeyError:
import pandas as pd
orders = pd.DataFrame({
"order_id": [1001, 1002, 1003],
"customer_name": ["Abe", "Rick", "Pat"]
})
# This raises an error
orders.rename(columns={"Order_ID": "order_id"}, errors="raise")
![]()
最常见原因是大小写不一致(Order_ID 与 order_id)或不可见的尾随空格("order_id " 与 "order_id")。遇到 KeyError 时,按以下顺序检查三件事:
- 拼写与大小写是否完全一致
- 是否存在隐藏空白
- 该列是否已在更早步骤被重命名
要验证实际的列名:
print(orders.columns.tolist())
# Use repr() as an alternative
print([repr(c) for c in orders.columns])
![]()
一旦看到 pandas 实际持有的精确字符串,通常就能立刻发现拼写问题。然后修正并重跑:
orders = orders.rename(columns={"order_id": "Order_ID"}, errors="raise")
print(orders.columns.tolist())
![]()
问题在于,何时使用 errors='raise',何时使用默认的 errors='ignore'。
-
默认更宽容。适合在处理模式可变的 DataFrame 的脚本中使用,缺失列不应导致崩溃。
-
在开发时,尤其是笔记本环境中,为了让拼写错误尽早暴露,切换为
errors='raise',以免静默失败导致下游长时间困惑的调试。
ValueError:df.columns 长度不匹配
当您给 df.columns 赋列表或者使用 .set_axis() 时,列表长度必须与列数完全一致。否则 pandas 会抛出 ValueError:
import pandas as pd
products = pd.DataFrame({
"sku": ["A100", "A101", "A102"],
"name": ["Widget", "Gadget", "Gizmo"],
"price": [9.99, 14.99, 19.99]
})
# This raises an error
products.columns = ["product_sku", "product_name"]
![]()
DataFrame 有三列,但只提供了两个新名称。修复方法是在赋值前检查列数:
print(len(products.columns))
products.columns = ["product_sku", "product_name", "product_price"]
print(products.columns.tolist())
![]()
如果您处理的 DataFrame 列数可能变化,使用带字典的 .rename() 更安全。它只会触及您指明的列,因此多一列或少一列都不会让代码崩溃。
结语
在 pandas 中重命名列,核心在于选择与任务范围匹配的方法。无论选择哪种方式,最大的实际收益是确定并坚持一种命名规范,并在每次分析的一开始就应用它。snake_case 是多数 Python 代码采用的风格。干净的列名在开头多花几秒钟,却能为整个项目省去后续 KeyError 的惊喜。
针对性重命名请使用带字典的 .rename()。当每个列名都需要更换时,赋值给 df.columns 或使用 .set_axis() 比构建完整映射字典更快。而如果重命名遵循某种规则,比如去空白、全部小写、camelCase 转换,那么传入函数或使用 .str 访问器可以让您一次性表达规则而无需逐一列举。Polars 用类似的 API 完成相同工作,但其不可变、链式优先的风格会促使您形成不同的习惯。
若想继续提升您的 DataFrame 技能,建议下一步学习 Data Manipulation with pandas 课程。如果您想要结构化的学习路径,Data Analyst in Python 职业路径会在教授 DataFrame 操作的同时覆盖分析师工具包的其他部分。
在 pandas 中重命名列的常见问题
如何在 pandas 中重命名列?
方法有多种,但最直接的是 使用 df = df.rename(columns={"old_name": "new_name"})。您也可以传入 inplace=True 来直接修改 DataFrame。
如何在 pandas 中重命名多个列?
要在 pandas 中重命名多个列,将所有重命名放在一个字典中传入:df.rename(columns={"old1": "new1", "old2": "new2"})
如何一次性重命名 pandas DataFrame 的所有列?
将包含新名称的列表赋给 df.columns。注意:确保列表长度与列数匹配,否则会得到 ValueError。
为什么 df.rename() 没有改动我的 DataFrame?
默认情况下,.rename() 返回一个新的 DataFrame。请将结果重新赋回 df = df.rename(...),或者使用 inplace=True。
如何在 pandas 中将列名改为小写?
使用 df.columns = df.columns.str.lower() 一步将所有列名转换为小写。