Outlier Detection Cheat Sheet
Covers statistical and machine-learning methods for identifying outliers, including Z-score, IQR, Isolation Forest, and Local Outlier Factor, with runnable examples.
Detection Methods
Common approaches ranked from simple to model-based.
- Z-score- Flags points where |value - mean| / std exceeds a threshold (commonly 3); assumes roughly normal data
- IQR method- Flags points below Q1 - 1.5*IQR or above Q3 + 1.5*IQR; robust to non-normal distributions
- Isolation Forest- Isolates points by random recursive splitting; anomalies need fewer splits to isolate
- Local Outlier Factor (LOF)- Compares local density of a point to its neighbors' density; good for varying-density clusters
- Elliptic Envelope- Fits a robust Gaussian ellipse to the data; points outside it are outliers (assumes elliptical data)
- DBSCAN- Density-based clustering where points not assigned to any cluster are treated as outliers
IQR Method in Pandas
Flag outliers in a single column using the interquartile range.
Q1 = df['value'].quantile(0.25)Q3 = df['value'].quantile(0.75)IQR = Q3 - Q1lower, upper = Q1 - 1.5 * IQR, Q3 + 1.5 * IQRoutliers = df[(df['value'] < lower) | (df['value'] > upper)]print(f"Found {len(outliers)} outliers outside [{lower:.2f}, {upper:.2f}]")
Isolation Forest
Unsupervised outlier detection for multivariate data.
from sklearn.ensemble import IsolationForestclf = IsolationForest(n_estimators=100, contamination=0.05, random_state=42)clf.fit(X)# -1 = outlier, 1 = inlierlabels = clf.predict(X)scores = clf.decision_function(X) # Higher = more normal
Local Outlier Factor
Detect outliers based on local density deviation.
from sklearn.neighbors import LocalOutlierFactorlof = LocalOutlierFactor(n_neighbors=20, contamination=0.05)labels = lof.fit_predict(X) # -1 = outlier, 1 = inlierscores = lof.negative_outlier_factor_ # More negative = more anomalous
Mahalanobis Distance (Multivariate)
Flag points far from the data's centroid while accounting for covariance between features, unlike per-column Z-scores.
import numpy as npfrom scipy.stats import chi2cov = np.cov(X.T)inv_cov = np.linalg.inv(cov)mean = X.mean(axis=0)diff = X - meanmd = np.sqrt(np.einsum('ij,jk,ik->i', diff, inv_cov, diff))# Squared Mahalanobis distance ~ chi-squared with df = n_features under normalitythreshold = np.sqrt(chi2.ppf(0.975, df=X.shape[1]))outliers = X[md > threshold]
DBSCAN as an Outlier Detector
Points that DBSCAN cannot assign to any dense cluster (label -1) are treated as outliers, with no assumption on cluster shape or count.
from sklearn.cluster import DBSCANfrom sklearn.preprocessing import StandardScalerX_scaled = StandardScaler().fit_transform(X)db = DBSCAN(eps=0.5, min_samples=10).fit(X_scaled)outlier_mask = db.labels_ == -1print(f"{outlier_mask.sum()} / {len(X)} points flagged as noise")# eps: tune with a k-distance elbow plot; min_samples: rule of thumb >= 2 * n_features
Elliptic Envelope with Robust Covariance
Fit a minimum covariance determinant (MCD) estimator so a handful of extreme points don't distort the fitted ellipse itself.
from sklearn.covariance import EllipticEnvelopeee = EllipticEnvelope(contamination=0.05, support_fraction=0.75, random_state=42)ee.fit(X)labels = ee.predict(X) # -1 = outlier, 1 = inliermd_scores = ee.mahalanobis(X) # robust Mahalanobis distance per point
PyOD: Combining Multiple Detectors
Average normalized scores from several detectors to get an ensemble that is more robust than any single algorithm's assumptions.
from pyod.models.knn import KNNfrom pyod.models.iforest import IForestfrom pyod.models.ecod import ECODfrom pyod.models.combination import averagefrom pyod.utils.utility import standardizerimport numpy as npdetectors = [KNN(), IForest(random_state=42), ECOD()]raw_scores = np.column_stack([d.fit(X).decision_scores_ for d in detectors])norm_scores = standardizer(raw_scores)combined = average(norm_scores)threshold = np.percentile(combined, 95)outliers = X[combined > threshold]
Robust Statistics for Skewed Data
Alternatives to mean/std-based rules that resist distortion from the outliers themselves.
- Median Absolute Deviation (MAD)- Modified Z-score = 0.6745 * (x - median) / MAD; robust because median and MAD aren't pulled by extreme values
- Grubbs' test- Statistical test for a single outlier in an approximately normal sample; iterate and remove to catch multiple outliers
- Hampel filter- Sliding-window MAD-based filter for flagging outliers in time series without a global distribution assumption
- Tukey's fences (extreme)- Use 3x IQR instead of 1.5x to flag only extreme outliers versus mild ones, reducing false positives on skewed data
- Winsorizing- Caps extreme values at a percentile (e.g., 1st/99th) instead of removing rows, preserving sample size for downstream models
Z-score and the elliptic envelope both assume roughly Gaussian, single-cluster data -- with skewed distributions or multiple clusters, prefer IQR, Isolation Forest, or LOF instead.