PD-01-009-P · Primer — Adding Columns
The idea in one sentence
Adding a column means writing a new named series into your table — usually computed from columns you already have — with a single vectorized expression.
Why it exists
Raw data almost never arrives with every field you need. You have price and qty, but you want total. You have a birth year, but you want an age. Rather than looping row by row (slow and error-prone), pandas lets you describe the whole new column as one expression over existing columns, and it fills every row at once. This turns "compute a value for each of a million rows" into a single readable line. Derived columns are the everyday workhorse of data prep — they are how you enrich, flag, and reshape a table before analysis.
How it works
To add a column, assign to a new key with bracket notation: df['new'] = <expression>. When the right-hand side is an operation on existing columns (like df['price'] * df['qty']), pandas applies it element-wise across every row — this is a vectorized operation, and it's fast because it runs in optimized C rather than a Python loop. You can also build boolean columns from comparisons (df['total'] > 20), and the result aligns to the same index automatically. If you prefer a style that returns a new DataFrame instead of mutating in place, use .assign(), which is handy inside method chains. Both approaches accept scalars too: df['tax_rate'] = 0.1 broadcasts a single value to every row.
import pandas as pd
df = pd.DataFrame({
'name': ['Ava', 'Ben', 'Cy'],
'price': [10.0, 25.0, 8.0],
'qty': [3, 1, 5],
})
df['total'] = df['price'] * df['qty'] # vectorized: one expr, all rows
df['flag'] = df['total'] > 20 # boolean derived column
print(df)
# name price qty total flag
# 0 Ava 10.0 3 30.0 True
# 1 Ben 25.0 1 25.0 True
# 2 Cy 8.0 5 40.0 True
# .assign() returns a NEW DataFrame (great for chaining):
print(df.assign(net=df['total'] * 0.9))
# name price qty total flag net
# 0 Ava 10.0 3 30.0 True 27.0
# 1 Ben 25.0 1 25.0 True 22.5
# 2 Cy 8.0 5 40.0 True 36.0
The one gotcha
Reach for vectorized column expressions, not Python loops. Beginners often write for i in range(len(df)): df.loc[i, 'total'] = ... — this is slow and fragile. Do the whole column at once (df['total'] = df['price'] * df['qty']). Also note the two styles differ in effect: df['x'] = ... mutates df in place, while .assign() leaves the original untouched and hands you a new DataFrame — so remember to capture its return value (df = df.assign(...)) if you want to keep the change.
See it — one expression fills the whole new column
flowchart LR A["Before<br/>price | qty"] --> B["Vectorized expr<br/>price * qty"] B --> C["After<br/>price | qty | total"] D["Row Ava: 10 * 3"] --> E["total = 30"] F["Row Cy: 8 * 5"] --> G["total = 40"]
The one-line takeaway
df['new'] = <expression over existing columns> computes a derived column for every row at once — vectorized, fast, and readable.
Where you'll meet it
Every data-prep pipeline: computing revenue from price and quantity, deriving age from a date, flagging outliers with a boolean, or normalizing a score before you group and summarize.
Named concepts: assignment, derived column, vectorized ops, assign
