Skip to content

pandas assign

Add or replace columns inside a method chain, without mutating the original data frame.

assign is how a chain grows new columns. Writing df['millions'] = ... modifies the frame in place and cannot appear inside a chain; assign returns a new frame with the column added, so the chain keeps flowing.

Official documentation: DataFrame.assign

The forms worth knowing

# One new column
df.assign(millions=pd.col('Hours Viewed') / 1_000_000)

# Several at once -- evaluated in order, left to right
df.assign(millions=pd.col('Hours Viewed') / 1_000_000,
          rounded=pd.col('millions').round(0))

# Replace an existing column by assigning to its own name
df.assign(mag=pd.col('mag').round(1))

# A name that is not a valid Python identifier needs the ** form
df.assign(**{'Hours (millions)': pd.col('Hours Viewed') / 1_000_000})

That second form is worth pausing on: assign evaluates its keyword arguments in order, so a later column can refer to one created earlier in the same call. That is not true of a plain dictionary of columns, and it saves chaining two separate assign calls.

A worked example, on real data

Netflix published an engagement report listing every title watched over six months. Bamboo Weekly #45 used it.

Hours viewed run into the hundreds of millions, which is hard to read. Let's derive something friendlier, and a flag for worldwide availability:

import pandas as pd

url = ('https://www.bambooweekly.com/content/files/4cd45et68cgf/1HyknFM84ISQpeua6TjM7A/'
       '97a0a393098937a8f29c9d29c48dbfa8/'
       'what_we_watched_a_netflix_engagement_report_2023jan-jun.xlsx')

(
    pd.read_excel(url, skiprows=5,
                  usecols=['Title', 'Available Globally?', 'Hours Viewed'])
    .assign(millions=pd.col('Hours Viewed') / 1_000_000,
            worldwide=pd.col('Available Globally?') == 'Yes',
            rounded=pd.col('millions').round(0))
    .sort_values('millions', ascending=False)
    .head(4)
    [['Title', 'worldwide', 'millions', 'rounded']]
)

Which gives:

                         Title  worldwide  millions  rounded
     The Night Agent: Season 1       True     812.1    812.0
     Ginny & Georgia: Season 2       True     665.1    665.0
The Glory: Season 1 // 더 글로...       True     622.8    623.0
           Wednesday: Season 1       True     507.7    508.0

Three columns created in one call, and rounded is computed from millions, which did not exist a line earlier. The original data frame is untouched — nothing was assigned to a variable, and read_excel's result was never modified.

Three mistakes people make

Using df['new'] = ... inside what should be a chain. Bracket assignment returns None and mutates in place, so it cannot be chained and it destroys the original. assign exists precisely to avoid both.

Expecting assign to modify the original. It does not. df.assign(x=...) returns a new frame; if you do not keep the result, nothing happened. This surprises people coming from bracket assignment, and it is the whole point — the original stays clean.

Forgetting the ** form for awkward column names. Keyword arguments must be valid Python identifiers, so df.assign(Hours Viewed=...) is a syntax error and df.assign(2024=...) is too. Pass a dictionary instead: df.assign(**{'Hours Viewed': ...}).

Watch it

assign is one leg of the method-chaining style: Method chaining in Pandas: Cleaner queries with assign, loc, and lambda.

Practice it

Work through an assign exercise, with instant feedback and no signup required: practice.lernerpython.com/bamboo-weekly/assign/

Go deeper

Bamboo Weekly is the practice. If you want the structured version — full courses with downloadable Jupyter notebooks, plus live Pandas office hours when you get stuck — that is LernerPython+Data. A paid Bamboo Weekly subscription is included with it.

See it on real data

Below are the 111 Bamboo Weekly exercises that use assign on real-world data — try each one, then study the worked solution.

Part of the Pandas Methods Index. See also practice by skill.