Selecting & Adding Columns
Select one column (Series) or many (DataFrame), and create new or calculated columns with assignment, np.where, insert and assign.
Watch the lesson
1 video on CodeWithMunnaX
Most analysis is column work: pick the runs column, compute a strike_rate from runs and balls, flag players who crossed 700 runs. Because each column is a Series, everything you learned about vectorised Series maths applies directly.
Sample table for this topic:
text
player team runs balls
0 Shubman Gill GT 890 564
1 Faf du Plessis RCB 730 475
2 Virat Kohli RCB 639 457
3 Rinku Singh KKR 474 317Definition
Column selection returns one column as a Series (
df["col"]) or several columns as a DataFrame (df[["c1", "c2"]]). Adding a column means assigning a value, list, Series or expression to a new column name (df["new"] = ...); the values are aligned to the DataFrame's index.
- Single brackets, one name → Series. Double brackets (a list of names) → DataFrame.
- Aligned to the index — a Series you assign is matched by row label; a list or array must have exactly one value per row; a scalar is repeated for every row.
Syntax
python
df["col"] # one column -> Series
df.col # attribute shortcut (only for simple names)
df[["c1", "c2"]] # several columns -> DataFrame (in this order)
df["new"] = scalar | list | Series | expression
df.insert(loc, column, value, allow_duplicates=False)
df.assign(new_col=value_or_function, ...) # returns a NEW DataFrame| Function / parameter | Meaning | Default |
|---|---|---|
df["new"] = value | add (or overwrite) a column at the end | — |
insert(loc, ...) — loc | integer position for the new column | required |
column | name of the new column | required |
value | scalar, list, array or Series | required |
allow_duplicates | allow a name that already exists | False |
assign(**kwargs) | each keyword = new column; values can be functions of the DataFrame | — |
Example — one column vs many
python
print(df["runs"])
print(type(df["runs"]))
print(df[["player", "runs"]])text
0 890
1 730
2 639
3 474
Name: runs, dtype: int64
<class 'pandas.Series'>
player runs
0 Shubman Gill 890
1 Faf du Plessis 730
2 Virat Kohli 639
3 Rinku Singh 474How it works: df["runs"] gives a Series (one dimension, a Name, a dtype) — use it for maths like df["runs"].sum(). df[["player", "runs"]] passes a list, so you get a smaller DataFrame with the columns in the order you listed. df[["runs"]] (a list with one name) is a one-column DataFrame.
Tip:
df.runs(dot notation) also works, but only for names that are valid Python identifiers and do not clash with methods —df.countis a method,df.strike rateis impossible. Preferdf["col"].
Example — add constant and calculated columns
python
df["season"] = 2023
df["strike_rate"] = (df["runs"] / df["balls"] * 100).round(1)
df["sixes"] = [33, 36, 16, 29]
print(df)text
player team runs balls season strike_rate sixes
0 Shubman Gill GT 890 564 2023 157.8 33
1 Faf du Plessis RCB 730 475 2023 153.7 36
2 Virat Kohli RCB 639 457 2023 139.8 16
3 Rinku Singh KKR 474 317 2023 149.5 29How it works: a scalar (2023) is broadcast to every row. An expression of existing columns is computed row by row in one vectorised step — no loop. A list must have exactly one value per row. New columns are added at the end. Assigning to an existing name overwrites it: df["runs"] = df["runs"] + 10.
Example — conditional columns
python
import numpy as np
df["over_700"] = df["runs"] > 700
df["band"] = np.where(df["runs"] >= 700, "Elite", "Good")
print(df[["player", "runs", "over_700", "band"]])text
player runs over_700 band
0 Shubman Gill 890 True Elite
1 Faf du Plessis 730 True Elite
2 Virat Kohli 639 False Good
3 Rinku Singh 474 False GoodHow it works: a comparison creates a boolean column. np.where(condition, value_if_true, value_if_false) picks between two values for every row — the pandas version of an Excel IF. (For more than two categories, pd.cut and .map are covered in later chapters.)
Example — insert at a specific position
python
df2 = df[["player", "team", "runs", "balls"]].copy()
df2.insert(1, "rank", [1, 2, 3, 4])
print(df2)text
player rank team runs balls
0 Shubman Gill 1 GT 890 564
1 Faf du Plessis 2 RCB 730 475
2 Virat Kohli 3 RCB 639 457
3 Rinku Singh 4 KKR 474 317How it works: insert(1, ...) puts rank at position 1 (the second column). Unlike most methods, insert modifies the DataFrame in place and returns None. Inserting a name that already exists raises ValueError: cannot insert rank, already exists.
Example — assign (returns a new DataFrame)
python
df3 = df[["player", "runs", "balls"]].assign(
average_per_ball=lambda d: (d["runs"] / d["balls"]).round(2),
runs_k=lambda d: d["runs"] / 1000,
)
print(df3)text
player runs balls average_per_ball runs_k
0 Shubman Gill 890 564 1.58 0.890
1 Faf du Plessis 730 475 1.54 0.730
2 Virat Kohli 639 457 1.40 0.639
3 Rinku Singh 474 317 1.50 0.474How it works: assign never changes the original; it returns a new DataFrame with the extra columns. Each lambda d: receives the DataFrame being built, so you can chain several steps cleanly. This style fits well with Copy-on-Write.
Comparison — ways to add a column
| Way | Position | Changes df? | Returns |
|---|---|---|---|
df["new"] = ... | end | yes | — |
df.insert(i, "new", ...) | any position i | yes | None |
df.assign(new=...) | end | no | a new DataFrame |
Common mistakes
- ❌
df["player", "runs"]→KeyError: ('player', 'runs'). ✅ Use a list inside:df[["player", "runs"]]. - ❌
df["wickets"]for a column that doesn't exist →KeyError: 'wickets'. ✅ Checkdf.columns(names are case-sensitive and spaces matter). - ❌
df.new_col = 5to create a column. ✅ That sets a plain Python attribute, not a column —df.columnsis unchanged. Usedf["new_col"] = 5. - ❌ Assigning a list of the wrong length →
ValueError: Length of values (2) does not match length of index (4). ✅ One value per row. - ❌ Adding a column to a filtered subset and expecting the original to change. ✅ With Copy-on-Write the subset is independent — add to
dfitself.
Interview tip
Q: What is the difference between df["a"] and df[["a"]]?
A: df["a"] returns a Series (1D). df[["a"]] passes a list of column names and returns a DataFrame with one column (2D). The difference matters for methods and libraries that expect a 2D input, such as scikit-learn's feature matrix.
Key points to remember
- df['col'] returns a Series; df[['c1', 'c2']] (a list) returns a DataFrame.
- Prefer df['col'] over df.col — dot access fails for names with spaces or that clash with methods.
- df['new'] = value adds a column at the end; a scalar is repeated, a list needs one value per row.
- Calculated columns are vectorised: df['sr'] = df['runs'] / df['balls'] * 100.
- np.where(cond, a, b) creates a two-way conditional column.
- df.insert(pos, name, value) adds a column at a position, in place, and returns None.
- df.assign(...) returns a new DataFrame and is ideal for method chaining.
Try it yourself
Select one column vs many
Add constant, calculated and conditional columns
insert vs assign
Practice: build boundary stats
Revision Flashcards
Tap a card to flip it and see the answer.
