Adding, Modifying & Dropping Columns
Reviewed & published by Brayan K
Modifying columns means reshaping a DataFrame's structure — creating new columns from existing data, renaming them, and removing the ones you no longer need — so your table holds exactly the information your analysis requires.
Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Learn bracket assignment, derived columns, df.assign(), rename(), drop(), and insert() — the everyday toolkit for transforming tables.
What You'll Learn in This Lesson
- Add a column with df["new"] = ...
- Build columns from existing columns (vectorized math)
- Add columns without mutating using df.assign()
- Rename columns with df.rename(columns={...})
- Drop columns and rows with df.drop()
- Place a column at a specific position with df.insert()
1 Adding Columns — Bracket Assignment & Derived Columns
The simplest way to add a column is to assign to a new name: df["new"] = .... If the name doesn't exist yet, pandas creates it; if it does, pandas overwrites it. The right side can be a scalar, a list, or — most powerfully — a calculation over existing columns.
import pandas as pd
df = pd.DataFrame({
"price": [10.0, 20.0, 30.0],
"qty": [2, 1, 3],
})
df["currency"] = "USD" # same value for every row (scalar)
df["total"] = df["price"] * df["qty"] # derived from two columnsimport pandas as pd
df = pd.DataFrame({
"price": [10.0, 20.0, 30.0],
"qty": [2, 1, 3],
})
df["currency"] = "USD" # scalar -> same on every row
df["total"] = df["price"] * df["qty"] # derived column
print(df)
# ✅ Expected output:
# price qty currency total
# 0 10.0 2 USD 20.0
# 1 20.0 1 USD 20.0
# 2 30.0 3 USD 90.02 df.assign() and df.rename()
df.assign(new=...) returns a new DataFrame with the column added, leaving the original untouched — ideal for method chaining. df.rename(columns={...}) changes column names using an old-to-new mapping.
# assign returns a NEW frame (original unchanged)
df2 = df.assign(discounted=df["total"] * 0.9)
# rename one or more columns via a mapping dict
df3 = df.rename(columns={"qty": "quantity", "total": "amount"})import pandas as pd
df = pd.DataFrame({
"qty": [2, 1, 3],
"total": [20.0, 20.0, 90.0],
})
# assign -> brand-new DataFrame with an extra column
df2 = df.assign(after_tax=df["total"] * 1.2)
print(df2)
# qty total after_tax
# 0 2 20.0 24.0
# 1 1 20.0 24.0
# 2 3 90.0 108.0
# rename -> map old names to new names
df3 = df.rename(columns={"qty": "quantity", "total": "amount"})
print(df3.columns.tolist()) # ['quantity', 'amount']
# ✅ Expected output:
# qty total after_tax
# 0 2 20.0 24.0
# 1 1 20.0 24.0
# 2 3 90.0 108.0
# ['quantity', 'amount']3 Dropping Columns/Rows and df.insert()
df.drop(columns=[...]) removes columns; df.drop(index=[...]) removes rows by their index label. Both return a new DataFrame by default. Use df.insert(loc, name, values) when you need a new column at a specific position instead of the far right.
df.drop(columns=["currency"]) # remove a column -> new frame
df.drop(index=[0, 2]) # remove rows 0 and 2 -> new frame
df.insert(0, "id", [101, 102, 103]) # put "id" first (position 0)- columns= drops by column name; index= drops by row label.
- drop returns a copy — reassign or pass inplace=True to keep it.
- insert mutates in place and errors if the name already exists.
import pandas as pd
df = pd.DataFrame({
"name": ["Alice", "Bob", "Carol"],
"temp": [1, 2, 3],
"score": [90, 80, 70],
})
# Drop a column (returns a new frame -> reassign to keep it)
df = df.drop(columns=["temp"])
print(df.columns.tolist()) # ['name', 'score']
# Drop a row by index label
print(df.drop(index=[1]))
# name score
# 0 Alice 90
# 2 Carol 70
# Insert a column at position 0 (the front)
df.insert(0, "id", [101, 102, 103])
print(df.columns.tolist()) # ['id', 'name', 'score']
# ✅ Expected output:
# ['name', 'score']
# name score
# 0 Alice 90
# 2 Carol 70
# ['id', 'name', 'score']import pandas as pd
df = pd.DataFrame({
"item": ["Pen", "Notebook", "Eraser"],
"price": [1.50, 3.00, 0.75],
"qty": [10, 5, 20],
})
# 🎯 YOUR TURN:
# 1) Add a "revenue" column = price * qty.
# 2) Drop the "qty" column afterwards.
# Replace the ___ blanks.
df["revenue"] = df["price"] ___ df["qty"] # hint: multiply
df = df.drop(columns=[___]) # hint: the column name to remove
print(df)
# Expected output:
# item price revenue
# 0 Pen 1.50 15.0
# 1 Notebook 3.00 15.0
# 2 Eraser 0.75 15.0📋 Quick Reference
| Task | Syntax | Mutates? |
|---|---|---|
| Add / overwrite column | df["x"] = ... | Yes |
| Add (non-destructive) | df.assign(x=...) | No (returns copy) |
| Rename columns | df.rename(columns={...}) | No (returns copy) |
| Drop columns | df.drop(columns=[...]) | No (returns copy) |
| Drop rows | df.drop(index=[...]) | No (returns copy) |
| Insert at position | df.insert(0, "x", vals) | Yes |
🎯 Mini Challenge: Reshape an Orders Table
Transform an orders DataFrame using every tool from this lesson.
- Add subtotal = unit_price * units
- Add tax = subtotal * 0.2 with assign()
- Rename units to quantity
- Drop the note column
import pandas as pd
orders = pd.DataFrame({
"unit_price": [5.0, 8.0, 2.0],
"units": [3, 1, 10],
"note": ["", "rush", ""],
})
orders["subtotal"] = orders["unit_price"] * orders["units"]
orders = orders.assign(tax=orders["subtotal"] * 0.2)
orders = orders.rename(columns={"units": "quantity"})
orders = orders.drop(columns=["note"])
print(orders)
# ✅ Expected output:
# unit_price quantity subtotal tax
# 0 5.0 3 15.0 3.0
# 1 8.0 1 8.0 1.6
# 2 2.0 10 20.0 4.0❓ Frequently Asked Questions
Lesson complete — you can reshape any table!
You can add columns by assignment, derive them from existing data, use assign() for safe chaining, rename with a mapping, drop columns and rows, and place columns precisely with insert().
Practice quiz
What does df['new'] = ... do if 'new' does not exist yet?
- Raises a KeyError
- Creates the new column
- Returns a copy
- Renames a column
Answer: Creates the new column. Bracket assignment creates the column if the name is new, or overwrites it if it exists.
What does df['price'] * df['qty'] do?
- Multiplies row by row (vectorized), no loop
- Concatenates strings
- Needs a for loop
- Raises an error
Answer: Multiplies row by row (vectorized), no loop. Vectorized math multiplies the two columns element-wise automatically.
What does df.assign(new=...) return?
- None
- Just the new column
- A new DataFrame with the column added
- The original mutated frame
Answer: A new DataFrame with the column added. assign returns a new DataFrame and leaves the original untouched — great for chaining.
How do you rename columns with df.rename?
- rename(['a','b'])
- rename(new='old')
- rename(map='old:new')
- rename(columns={'old': 'new'})
Answer: rename(columns={'old': 'new'}). Pass a columns mapping dict of old name to new name.
What does df.drop(columns=['x']) return by default?
- A new DataFrame without column x
- None
- Only column x
- An error
Answer: A new DataFrame without column x. drop returns a new frame by default; the original is unchanged unless you reassign or use inplace.
Which argument drops rows by their index label?
- columns=
- axis='rows'
- index=
- subset=
Answer: index=. df.drop(index=[...]) removes rows by index label; columns=[...] removes columns.
When does df.insert() matter over plain bracket assignment?
- When you need the column at a specific position
- When mutating is forbidden
- When the column is numeric
- Never
Answer: When you need the column at a specific position. insert(loc, name, values) places a column at a chosen index; brackets always append at the far right.
Does df.insert(0, 'id', vals) mutate the DataFrame in place?
- No, it returns a copy
- Only if inplace=True
- Yes, it mutates in place
- It raises an error
Answer: Yes, it mutates in place. insert modifies the DataFrame in place and errors if the name already exists.
Why might a column from df.assign(...) seem to disappear?
- assign deletes columns
- The result wasn't captured (assign doesn't mutate)
- assign needs inplace
- Columns expire
Answer: The result wasn't captured (assign doesn't mutate). assign returns a copy; if you don't store it, the original df is unchanged.
If you do df['total'] = df['price'] * df['qty'], where does 'total' appear?
- At position 0
- It replaces 'price'
- It is hidden
- Appended at the far right
Answer: Appended at the far right. Plain bracket assignment always adds the new column at the right end.
Continue this course
- Previous: SettingWithCopyWarning: Explained & Fixed
- Next: Handling Missing Data (NaN, fillna, dropna) — Detect, fill, and drop missing values to clean real-world datasets
- Quick reference: Pandas cheat sheet › Transforming
Frequently asked questions
What is the difference between df.assign() and df["new"] = ...?
df["new"] = ... modifies the DataFrame in place and returns nothing. df.assign(new=...) returns a brand-new DataFrame with the column added and leaves the original untouched, which makes it perfect for method chaining.
Does df.drop() change the original DataFrame?
By default no — df.drop(columns=[...]) returns a new DataFrame and the original is unchanged. To modify in place, pass inplace=True, or reassign with df = df.drop(columns=[...]).
When should I use df.insert() instead of df["new"] = ...?
Use df.insert(loc, column, value) when the position of the new column matters. Plain bracket assignment always appends the column to the far right, whereas insert lets you place it at any index.