How do I create a new column based on conditions in pandas?
Short answer
Use np.where for a two-way choice and np.select for several conditions. Both are vectorised, so they are faster and cleaner than looping or using apply with an if statement.
The short version
For a simple either-or, use numpy.where. For several bands, use numpy.select, which takes a list of conditions and a matching list of results plus a default. Both work on whole columns at once, so they beat a row loop or apply with an if for both speed and clarity.
Two-way choice with np.where
import pandas as pd
import numpy as np
df = pd.DataFrame({"score": [45, 70, 90]})
df["result"] = np.where(df["score"] >= 50, "pass", "fail")
print(df)
np.where(condition, value_if_true, value_if_false) reads naturally and returns a full column.
Several bands with np.select
When there are more than two outcomes, chaining np.where becomes unreadable. np.select is the right tool.
conditions = [df["score"] < 50, df["score"] < 80]
choices = ["fail", "pass"]
df["grade"] = np.select(conditions, choices, default="distinction")
print(df["grade"].tolist()) # ['fail', 'pass', 'distinction']
The conditions are checked in order, and the first match wins, so put the narrowest or lowest band first. Anything matching none of the conditions gets the default.
The mistake to avoid
A common attempt is a Python if inside apply:
df["grade"] = df["score"].apply(
lambda s: "fail" if s < 50 else "pass" if s < 80 else "distinction"
)
This gives the right answer but runs a Python function per row, so it is slow on large frames and harder to read once the rules grow. Prefer np.select.
Beware overlapping conditions
Because np.select takes the first matching condition, order matters. If you wrote df["score"] < 80 before df["score"] < 50, every failing score would be labelled "pass", because the wider condition catches it first. List conditions from the most specific to the least specific, and test the boundaries (a score of exactly 50 and exactly 80) to confirm each lands in the band you intended.