How do I detect outliers in a column using the IQR method in pandas?
Short answer
Compute the interquartile range, then flag values more than 1.5 times the IQR below the first quartile or above the third. This is robust to the outliers themselves, unlike a mean-and-standard-deviation rule.
The short version
Find the first and third quartiles, take their difference (the interquartile range, or IQR), and flag any value more than 1.5 times the IQR below the first quartile or above the third. This rule is robust because quartiles are barely moved by the very outliers you are trying to find, unlike the mean and standard deviation.
The calculation
import pandas as pd
x = pd.Series([10, 11, 12, 13, 100])
q1 = x.quantile(0.25)
q3 = x.quantile(0.75)
iqr = q3 - q1
lower = q1 - 1.5 * iqr
upper = q3 + 1.5 * iqr
outliers = x[(x < lower) | (x > upper)]
print(outliers.tolist()) # [100]
The value 100 sits far above the upper bound, so it is flagged, while the clustered values are not.
Why not use mean and standard deviation
A common alternative flags values more than three standard deviations from the mean. The problem is that a large outlier inflates both the mean and the standard deviation, dragging the threshold towards itself and hiding the very value you want to catch. The IQR uses quartiles, which a single extreme value barely shifts, so it stays reliable even when outliers are present. For skewed or messy data, prefer the IQR rule.
The 1.5 multiplier is a convention, not a law
The factor 1.5 is the usual choice (it corresponds to the whiskers on a box plot), but it is a convention you can adjust. Use a larger multiplier like 3 to flag only extreme outliers, or a smaller one to be stricter. There is no single correct value; pick one that matches how aggressive you want to be, and state it.
Detecting outliers within groups
If groups have different typical ranges, compute the bounds per group so a normal value in one group is not flagged against another group's range.
def flag(s):
q1, q3 = s.quantile(0.25), s.quantile(0.75)
iqr = q3 - q1
return (s < q1 - 1.5 * iqr) | (s > q3 + 1.5 * iqr)
df["is_outlier"] = df.groupby("city")["value"].transform(flag)
Flag, do not silently delete
Detecting an outlier is not a licence to remove it. An outlier can be a data error, or it can be a real and important event. Flag them, inspect them, and decide case by case. Automatically dropping flagged rows can quietly discard exactly the observations that matter most, so treat detection and removal as separate decisions.