Pular para o conteúdo principal

Renaming Columns in Pandas: A Complete Guide With Examples

Learn how to rename columns in pandas with .rename(), df.columns, and .set_axis(), plus Python functions for snake_case and fixes for KeyError and ValueError.
17 de ago. de 2026  · 13 min lido

Explorar com IA

ChatGPTClaudePerplexity

You pull a fresh CSV from your company's database, run df.head(), and see CUST_ID_NBR, txn_amt_usd_2, Unnamed: 7, or a column called Customer Name (Full) with a trailing space you won't notice until a KeyError ruins your afternoon. Messy column names are one of the small frictions of real data work, and a pandas rename column step is usually the first thing you'll do before any real analysis begins.

In this tutorial on how to rename columns in pandas, you'll learn:

  • renaming one or many columns with .rename()

  • replacing all column names at once with df.columns or .set_axis()

  • applying functions to transform names in bulk

  • cleaning messy names with the .str accessor

  • renaming columns at load time inside pd.read_csv()

  • handling the same tasks in Polars

  • avoiding running into KeyError and ValueError: Length mismatch

This tutorial assumes you can import pandas and create a DataFrame. We'll use realistic datasets throughout, like customer records, sales exports, and sensor readings, so the patterns map directly onto the kind of data you actually work with.

Which Pandas Rename Method Should You Choose?

Pick the method that matches the scope of your task: a targeted rename, a full replacement, or a rule applied to every name.

Your goal

Method

When it fits

Rename one or a few specific columns

df.rename(columns={"old": "new"})

Leaves the other columns untouched; safe inside method chains

Replace every column name

df.columns = [...] or df.set_axis([...], axis=1)

Faster than mapping each name; use .set_axis() when you need to chain

Rename by a rule (lowercase, snake_case, strip)

df.rename(columns=func) or df.columns.str....

Express the rule once instead of listing every column

Rename at load time

pd.read_csv(..., header=0, names=[...])

You control the schema and want no separate step

Any of the above in Polars

df.rename({"old": "new"}), .alias() in a select

Immutable and chain-first, so there's no inplace

Learn Python From Scratch

Master Python for data science and gain in-demand skills.
Start Learning for Free

How Do I Rename Columns With .rename()?

The .rename() method is the most flexible way to perform a pandas DataFrame rename column operation, and the one you'll reach for most often. 

It takes a dictionary that maps old names to new names, leaves any columns you don't mention untouched, and by default returns a new DataFrame instead of modifying the original. This makes .rename() safe to use inside method chains and easy to reason about when debugging.

The dictionary pattern looks like this:

sales_data.rename(columns={"old_name": "new_name"})

If you're new to dictionaries, I recommend going through our Python dictionary methods tutorial for a refresher.

Note on the old copy parameter

One quick note before the examples. Pandas 3.0 deprecated the copy parameter and made Copy-on-Write the default behavior. In practice, this means you no longer need to worry about whether .rename() is making an expensive copy of your data. Pandas handles that lazily under the hood. The main parameter left to think about is inplace, which we'll cover in the third subsection.

Renaming a single column

Imagine you've just loaded customer records exported from a legacy CRM. The column names are abbreviated in a way that made sense to whoever designed the database in 2008, but not to you. This is the simplest pandas rename column operation, one old name, one new name, in a dictionary:

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)

Python DataFrame

Now, rename cust_id_nbr to something more readable:

customers_renamed = customers.rename(columns={"cust_id_nbr": "customer_id"})
print(customers_renamed)

Python DataFrame

The original customers DataFrame is unchanged. .rename() returned a new DataFrame, which we assigned to customers_renamed. The two columns we didn't mention (first_nm, signup_dt) came along unchanged.

Renaming multiple columns

The dictionary scales naturally. To handle a pandas rename multiple columns task, just add more key-value pairs to the mapping:

customers_clean = customers.rename(columns={
    "cust_id_nbr": "customer_id",
    "first_nm": "first_name",
    "signup_dt": "signup_date"
})

print(customers_clean)

Python DataFrame

There's also an alternative syntax that uses the mapper and axis arguments instead of the columns keyword:

customers.rename(mapper={"cust_id_nbr": "customer_id"}, axis=1)

The axis=1 tells pandas you're targeting columns (as opposed to axis=0 for row index labels). Both forms produce the same result. Most code in the wild uses columns={...} because it reads more clearly at a glance, so we'll stick with that pattern for the rest of the tutorial.

One useful detail is that if you pass a key that doesn't match any existing column, .rename() silently ignores it by default. That's convenient when you're writing a reusable function that might handle DataFrames with slightly different schemas, but it can also hide typos. To make pandas raise an error on unknown column names, pass errors='raise'.

Using inplace vs. returning a new DataFrame

By default, .rename() returns a new DataFrame and leaves the original alone. If you want it to modify the existing DataFrame directly, pass inplace=True:

# Returns a new DataFrame (default)
customers_v2 = customers.rename(columns={"first_nm": "first_name"})

# Modifies customers directly, returns None
customers.rename(columns={"first_nm": "first_name"}, inplace=True)

print(customers)

Python DataFrame

So which should you use? In most cases, the default, returning a new DataFrame, is the better choice. It's also easier to debug, since you still have the original DataFrame to inspect when something goes wrong. And it sidesteps the aliasing problems that produce a SettingWithCopyWarning in older code.

Performance isn't really a reason to prefer inplace anymore either. With Copy-on-Write, it is now the default in pandas 3.0+, the non-inplace version uses lazy copying. It doesn't actually duplicate your data until something is modified. The old argument that inplace=True saves memory is much weaker than it used to be.

The one place inplace=True still feels natural is in short, exploratory scripts where you're cleaning a single DataFrame step by step and don't care about chaining. For production code or anything you'll revisit later, prefer the default.

How Do I Rename All Columns at Once in Pandas?

Sometimes you don't want to map old names to new names. You just want to replace every column name at once. This comes up more often than you'd expect, like headerless CSVs where pandas assigned 0, 1, 2 as column names, datasets where the header row is in a different language, or system-generated exports with names like Field1, Field2, Field3.

There are two common ways to do this. Either assigning directly to df.columns, or using .set_axis(). They produce the same result. The trade-off is between brevity and chainability.

Assigning a list to df.columns

The most direct approach is to assign a new list to the columns attribute. Take this DataFrame, built from a list of lists with no header information, like the kind of thing you get when reading a headerless CSV. Pandas falls back to integer column names:

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)

Python DataFrame

Those 0, 1, and 2 column names are useless for analysis. Replace them by assigning a new list of names to the columns attribute:

sensor_readings.columns = ["wind_speed", "temperature_c", "pressure_hpa"]
print(sensor_readings)

Python DataFrame

Two things to know about this approach. 

  1. The list length must match exactly. Pass three names for a four-column DataFrame, and pandas raises ValueError: Length mismatch (we'll cover this error in detail later). 

  2. It modifies the DataFrame in place. There's no inplace parameter here because the assignment is the modification. If you want a fresh copy, use .copy() first or reach for .set_axis() below.

Using .set_axis() for method chaining

The .set_axis() method does the same thing, but returns a new DataFrame so you can chain it with other operations. Take a similar headerless DataFrame, but this time with some messier data like extra decimal places and a missing reading:

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)

Python DataFrame

The axis=1 argument tells pandas you're setting column labels (use axis=0 to set the row index instead). Because .set_axis() returns a new DataFrame, it fits naturally into the kind of chained transformation pipelines you'll write in real ETL or analysis code. That's the main reason to prefer it over direct assignment in production.

How Do I Rename Columns Using Functions in Pandas?

Instead of mapping each old name to a new one, you can pass a function to .rename(), and pandas will apply it to every column name. This is the right tool when you have a rule rather than a list.  For example, "lowercase everything" or "replace every space with an underscore."

Using built-in string functions

The simplest case is a standardizing case. Pass str.lower, str.upper, or str.title directly to the columns argument:

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())

Python column list

Note that we're passing the function itself (str.lower), not calling it (str.lower()). Pandas applies it to each column name one at a time. This is a clean shortcut for case standardization, but it doesn't handle spaces or special characters. For that, you'll want a lambda or a custom function.

Using lambda and custom functions

For anything beyond case changes, a lambda gives you a quick way to express the transformation inline. If you haven't used lambdas before, our Python lambda functions beginner's guide is a good starting point.

A common pattern is to lowercase and replace spaces with underscores in one step. We use the previous example:

orders_snake = orders.rename(columns=lambda col: col.lower().replace(" ", "_"))
print(orders_snake.columns.tolist())

Python column list

When the logic gets more involved, lift it out into a named function. Consider this helper that converts camelCase or PascalCase column names to 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())

Python column list

A named function like this is easier to test, reuse across notebooks, and document than a clever one-liner. Reach for lambdas when the logic fits on one line, and custom functions when it doesn't.

How Do I Clean Messy Column Names in Bulk in Pandas?

When data arrives from spreadsheets, third-party APIs, or hand-edited CSVs, column names often have problems that .rename() alone can't fix gracefully. I’m talking about problems such as:

  • Trailing whitespace
  • Mixed casing
  • Parentheses
  • Hyphens
  • Special characters
  • Invisible Unicode characters

For these situations, the cleanest approach is to operate directly on df.columns using the .str accessor, which exposes vectorized string methods (including regex) across all column names at once. This is also the foundation of solid data cleaning in Python. Cleaning column names makes every downstream step (filtering, merging, plotting) less error-prone.

Stripping whitespace and special characters

Take this DataFrame, with the kind of names you'd get from an Excel export touched by too many hands:

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())

Python column list

Leading and trailing spaces are the most common and most frustrating issues, because they're invisible. Strip them in one line:

raw_export.columns = raw_export.columns.str.strip()
print(raw_export.columns.tolist())

Python column list

For special characters, .str.replace() accepts a regex pattern. The pattern below keeps letters, numbers, underscores, and spaces, and drops everything else:

raw_export.columns = raw_export.columns.str.replace(r"[^a-zA-Z0-9_ ]", "", regex=True)
print(raw_export.columns.tolist())

Python column list

The hyphen, parentheses, and dollar sign are gone. Notice that Total Amount now has a trailing space (from where ($) used to be), and OrderDate lost its hyphen entirely. That's exactly why we strip again at the end of a cleaning pipeline.

Standardizing to snake_case

A common best practice is to convert all column names to snake_case before you start any analysis, like lowercase, words separated by underscores, no special characters. Chain the .str methods together to get there in a single expression:

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()                                  # remove leading/trailing whitespace
    .str.lower()                                  # lowercase everything
    .str.replace(r"[^a-z0-9]+", "_", regex=True)  # collapse non-alphanumerics into underscores
    .str.strip("_")                               # remove any leading/trailing underscores
)

print(raw_export.columns.tolist())

Python column list

Four lines, and your column names are predictable, lowercase, and underscore-separated. This pattern is worth saving as a utility function. Once you have it, you can throw it at every messy DataFrame that comes through the door. 

You'll often want to combine renaming with column removal, too. For that, the drop columns in pandas tutorial covers the next step.

How Do I Rename Columns When Loading Data in Pandas?

If you already know you want different column names before you even load the file, you can do the renaming directly inside pd.read_csv(). Pass a list of names to the names parameter and set header=0 to tell pandas to skip the existing header row and use your names instead:

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)

Python DataFrame

This is a useful shortcut when you control the schema and don't want a separate .rename() step cluttering your loading code. If the file has no header row at all, omit header=0 and just use names=[...] to assign column names from scratch. For a deeper look at the loading dataset options, I’d recommend the pandas read_csv() tutorial.

One caveat: This is an all-or-nothing approach. The names parameter replaces every column name, so the list length must match the number of columns in the file exactly. If you only want to rename a few columns, load the file first and use .rename() afterward.

For a guided walkthrough of these patterns alongside other common cleanup tasks, I recommend you go through our Cleaning Data in Python course.

Renaming Columns in Polars vs. Pandas

If you work across both pandas and Polars, or expect to, it's worth knowing how each one handles column renaming. The high-level API is similar, but the details diverge in ways that catch you out the first few times. Polars is a fast, Rust-backed DataFrame library that's increasingly common in modern data stacks, and the muscle memory you build in pandas doesn't always transfer cleanly.

The main idea is identical. You map old names to new names with a dictionary. The differences are in the details. Polars is immutable by design (no inplace), method chaining is the idiomatic style, and column-level renaming during a select uses .alias() rather than a separate rename step.

Side-by-side comparison

Task

Pandas

Polars

Rename specific columns

df.rename(columns={"old": "new"})

df.rename({"old": "new"})

Replace all column names

df.columns = [...] or df.set_axis([...], axis=1)

df.rename(dict(zip(df.columns, [...])))

Rename during a select

Select first, then .rename()

df.select(pl.col("old").alias("new"))

Modify in place

inplace=True supported

Not supported. Always returns a new DataFrame

Idiomatic style

inplace or chaining

Always chaining

The same rename in both libraries

For a comparison, here is a simple rename in each of the two libraries.

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)

Python DataFrame

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)

Python DataFrame

Two small differences to notice. Polars' .rename() takes the dictionary directly. There's no columns= keyword because Polars only supports renaming columns (no row index). And you have to reassign the result. There is no inplace=True in Polars. Every operation returns a new DataFrame.

The Polars output also shows dtypes inline (i64, str) and the shape up top, which is one of the small quality-of-life things people tend to like once they switch. 

Renaming columns during a select

For renaming during a transformation, Polars uses .alias() inside .select() or .with_columns():

# 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)

Python DataFrame

In pandas, the equivalent would be a .rename() after a column selection. Neither approach is better. They reflect each library's design philosophy. 

If you want a deeper comparison of the two, I'd recommend the pandas versus polars performance tutorial. And if you'd like to add polars to your kit, I recommend taking our Introduction to Polars course. 

Common Errors and How to Fix Them

Two errors come up repeatedly when renaming pandas columns. Here's what they look like, why they happen, and how to fix them.

KeyError: column name not found

By default, .rename() silently ignores keys that don't match any existing column. But if you pass errors='raise' to catch typos, you'll get a KeyError when a key doesn’t exist:

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")

KeyError

The most common cause is a case-sensitivity slip (Order_ID versus order_id) or an invisible trailing space ("order_id " versus "order_id"). When you hit a KeyError, check three things in order:

  1. Exact spelling and case
  2. Hidden whitespace
  3. Whether the column was already renamed earlier

To verify the actual column names:

print(orders.columns.tolist())

# Use repr() as an alternative
print([repr(c) for c in orders.columns])

Python column list

Once you see the exact strings pandas is holding, the typo is usually obvious. Then fix the spelling and re-run:

orders = orders.rename(columns={"order_id": "Order_ID"}, errors="raise")
print(orders.columns.tolist())

Python column list

Now the question is, when to use errors='raise' versus the default errors='ignore'

  • The default is forgiving. It is handy in scripts that process DataFrames with varying schemas, where a missing column shouldn't crash anything. 

  • Flip to errors='raise' when you want typos to surface loudly during development, especially in notebooks where silent failures cause hours of confused debugging downstream.

ValueError: length mismatch with df.columns

When you assign a list to df.columns or use .set_axis(), the list length must match the number of columns exactly. If it doesn't, pandas raises a 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"]

ValueError

The DataFrame has three columns, but only two new names were provided. The fix is to check the column count before assigning:

print(len(products.columns))
products.columns = ["product_sku", "product_name", "product_price"]
print(products.columns.tolist())

Python column list

If you're working with DataFrames where the column count can vary, it's safer to use .rename() with a dictionary. It only touches the columns you name, so a missing or extra column won't crash your code.

Final Thoughts

Renaming columns in pandas comes down to picking the method that matches the scope of your task. Whichever approach you reach for, the biggest practical win is settling on a single naming convention and applying it as the first step in every analysis. snake_case is what most Python code uses. Clean column names cost a few seconds at the start and save you from KeyError surprises for the rest of the project.

Use .rename() with a dictionary for targeted renames. When every column needs a new name, assigning to df.columns or using .set_axis() is faster than building a dictionary of every old-to-new mapping. And if the renaming follows a rule like stripping whitespace, lowercasing everything, converting camelCase, then passing a function, or using the .str accessor lets you express the rule once instead of enumerating cases. Polars handles the same work with a similar API, but its immutable, chain-first style nudges you toward different habits. 

To keep building your DataFrame skills, I'd recommend the Data Manipulation with pandas course as a next step. If you want a structured learning path, the Data Analyst in Python career track covers DataFrame manipulation alongside the rest of the analyst toolkit.

FAQs for Renaming Columns in Pandas

How do I rename a column in pandas?

There are multiple methods, but the most straightforward is to use df = df.rename(columns={"old_name": "new_name"}). You can also pass the argument inplace=True to modify the DataFrame directly.

How do I rename multiple columns in pandas?

To rename multiple columns in pandas, pass all the renames in one dictionary: df.rename(columns={"old1": "new1", "old2": "new2"})

How do I rename all columns in a pandas DataFrame?

Assign a list of new names to df.columns. Attention: Make sure the list length matches the column count, because otherwise, you will get a ValueError.

Why is df.rename() not changing my DataFrame?

By default, .rename() returns a new DataFrame. Assign the result back with df = df.rename(...) or use inplace=True.

How do I rename columns to lowercase in pandas?

Use df.columns = df.columns.str.lower() to lowercase every column name in one step.


Author
Rajesh Kumar
LinkedIn

I am a data science content writer. I love creating content around AI/ML/DS topics. I also explore new AI tools and write about them.

Tópicos

Learn Python With DataCamp!

Curso

Manipulação de dados com pandas

4 h
559.2K
Saiba como importar, tratar dados, calcular estatísticas e criar visualizações com o pandas.
Ver detalhesRight Arrow
Iniciar Curso
Ver maisRight Arrow
Relacionado

cheat-sheet

Pandas Cheat Sheet for Data Science in Python

A quick guide to the basics of the Python data analysis library Pandas, including code samples.
Karlijn Willems's photo

Karlijn Willems

cheat-sheet

Pandas Cheat Sheet: Data Wrangling in Python

This cheat sheet is a quick reference for data wrangling with Pandas, complete with code samples.
Karlijn Willems's photo

Karlijn Willems

Tutorial

How to Drop Columns in Pandas Tutorial

Learn how to drop columns in a pandas DataFrame.
DataCamp Team's photo

DataCamp Team

Tutorial

Python Select Columns Tutorial

Use Python Pandas and select columns from DataFrames. Follow our tutorial with code examples and learn different ways to select your data today!
DataCamp Team's photo

DataCamp Team

data-frames-in-python-banner_cgzjxy.jpeg

Tutorial

Pandas Tutorial: DataFrames in Python

Explore data analysis with Python. Pandas DataFrames make manipulating your data easy, from selecting or replacing columns and indices to reshaping your data.
Karlijn Willems's photo

Karlijn Willems

Tutorial

Pandas Add Column Tutorial

You are never stuck with just the data you are given. Instead, you can add new columns to a DataFrame.
DataCamp Team's photo

DataCamp Team

Ver MaisVer Mais