🧬 Section 4 · Unsupervised Learning 🟡 Intermediate MODULE 19

Anomaly Detection

⏱️ 24 min read
📖 Z-Score, IQR, IsolationForest & OneClassSVM
🧩 4 Quiz Questions
🏗️ 1 Challenge · 3 tasks
Your progress in Section 475%
🎯 What you'll learn: Lesson 17's DBSCAN briefly introduced the idea of a "noise" point that doesn't belong to any cluster — this lesson makes finding those points the ENTIRE job. You'll cover two quick statistical approaches (z-score and the IQR method), then two real scikit-learn models built specifically for this task: sklearn.ensemble.IsolationForest and sklearn.svm.OneClassSVM. By the end you'll understand how isolation-based detection actually works, and why anomaly detection has a practical evaluation problem that supervised learning doesn't: there's usually little or no labeled anomaly data to check your work against.

What Anomaly Detection Is Used For

An anomaly (or outlier) is a data point that deviates so much from the rest of the dataset that it looks like it was generated by a different process entirely. Finding them automatically matters across a wide range of practical problems — always framed here generically, without claiming any specific real-world benchmark or company result.

💳
Fraud Detection
A transaction wildly out of line with a customer's normal spending pattern.
🔒
Network Intrusion
Traffic patterns that don't resemble any typical user or system behavior.
🏭
Manufacturing Defects
A sensor reading on the production line that falls outside the normal operating range.

What unites all three: the "normal" cases vastly outnumber the anomalies, the anomalies are the whole point of building the system, and — as Section 5 covers in depth — there's rarely a clean, complete set of labeled anomaly examples to train a normal classifier on.

Statistical Approaches — Z-Score and IQR

The simplest anomaly detectors don't need scikit-learn at all — they're direct applications of the descriptive statistics an introductory stats or data-science course already covers: the mean, standard deviation, and quartiles of a single column.

The Z-Score Method

Z-score for a single value x z  =  (x - μ) / σ μ = the column's mean, σ = the column's standard deviation. z measures how many standard deviations x sits from the mean. A common rule of thumb flags |z| > 3 as an outlier.
zscore_outliers.py
PYTHON
import numpy as np

z_scores = (df["amount"] - df["amount"].mean()) / df["amount"].std()
outliers = df[np.abs(z_scores) > 3]

print(f"Outliers found via z-score: {len(outliers)}")
# Outliers found via z-score: 7

The IQR (Interquartile Range) Method

IQR fences IQR = Q3 - Q1  ·  lower = Q1 - 1.5·IQR  ·  upper = Q3 + 1.5·IQR Q1/Q3 are the 25th/75th percentiles. Anything below the lower fence or above the upper fence is flagged. The same "1.5×IQR" rule a box plot uses to draw its whiskers.
iqr_outliers.py
PYTHON
Q1 = df["amount"].quantile(0.25)
Q3 = df["amount"].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR

outliers = df[(df["amount"] < lower) | (df["amount"] > upper)]
print(f"Outliers found via IQR: {len(outliers)}")
# Outliers found via IQR: 11
Why IQR often wins on skewed data
Z-score relies on the MEAN and STANDARD DEVIATION — both of which are themselves sensitive to extreme values, exactly like MAE vs. RMSE in Lesson 15. A handful of huge outliers can inflate the standard deviation enough to make those same outliers look less extreme in z-score terms, sometimes hiding them. IQR is built from QUARTILES (the median-based statistics a box plot uses), which barely move even with several extreme values present — making IQR the more robust default on skewed, real-world numeric columns.

sklearn.ensemble.IsolationForest

Z-score and IQR only work one column at a time. Real anomalies are often only visible across MULTIPLE features at once — a transaction amount that's fine on its own, at a time of day that's fine on its own, but the COMBINATION is unusual. IsolationForest handles multiple features natively, and works on a genuinely different principle than every other model in this course.

📝
The core idea: anomalies are easier to isolate
Instead of modeling what "normal" looks like, IsolationForest builds many random decision trees, each splitting the data on random features at random thresholds. A NORMAL point, packed in close among many similar points, typically takes many random splits to separate from everyone else. An ANOMALY, sitting off on its own, gets isolated into its own tiny region after just a few random splits — its average PATH LENGTH across all the trees is short. IsolationForest turns that average path length into an anomaly score directly, with no need to first define what "normal" density or distance even means.
isolation_forest.py
PYTHON
from sklearn.ensemble import IsolationForest

iso = IsolationForest(n_estimators=100, contamination=0.05, random_state=42)
iso.fit(X)

preds = iso.predict(X)              # 1 = normal, -1 = anomaly
scores = iso.decision_function(X)  # higher = more normal

n_anomalies = (preds == -1).sum()
print(f"Anomalies flagged: {n_anomalies} of {len(X)}")
# Anomalies flagged: 25 of 500
⚠️
contamination is an assumption, not a discovered fact
contamination tells IsolationForest roughly what PROPORTION of the data you expect to be anomalous (here, 5%) — it directly controls the decision threshold on the anomaly score. Set it too high and normal points get flagged; too low and real anomalies slip through. Unlike a hyperparameter tuned by GridSearchCV against a known metric (Lesson 11), contamination usually has to be estimated from domain knowledge or a small amount of labeled data — which is precisely Section 5's challenge.
Illustrative IsolationForest result on 2 features
A dense normal region (blue) with a handful of isolated anomalies (red) flagged out on the fringes.
Normal (predict = 1)
Anomaly (predict = -1)

sklearn.svm.OneClassSVM

OneClassSVM takes yet another approach — it adapts the SVM idea from Lesson 16 to a setting with only ONE class ("normal") and no clean negative examples to draw a boundary against. Instead, it tries to learn a boundary that wraps tightly around the region where normal data lives, treating anything outside that boundary as anomalous.

one_class_svm.py
PYTHON
from sklearn.svm import OneClassSVM
from sklearn.preprocessing import StandardScaler

X_scaled = StandardScaler().fit_transform(X)

oc_svm = OneClassSVM(kernel="rbf", nu=0.05, gamma="scale")
oc_svm.fit(X_scaled)

preds = oc_svm.predict(X_scaled)  # 1 = normal, -1 = anomaly
print(f"Anomalies flagged: {(preds == -1).sum()} of {len(X_scaled)}")
🎛️
nu
Roughly caps the fraction of training points allowed to fall outside the learned boundary — plays a similar role to IsolationForest's contamination.
🌀
kernel & gamma
Same RBF kernel machinery as regular SVM/SVR — gamma controls how tightly the learned boundary can curve around the normal region.
📝
Requires scaling, and can be slower on large datasets
Like every kernel-based SVM variant, OneClassSVM is distance-sensitive, so features need to be scaled first — exactly as in the code above. It also tends to scale less gracefully to very large datasets than IsolationForest, which is why IsolationForest is often reached for first on bigger tabular problems, with OneClassSVM as an alternative worth comparing, especially on smaller or lower-dimensional data.
IsolationForest vs. OneClassSVM — a quick comparison
AspectIsolationForestOneClassSVM
Core ideaAnomalies isolate faster in random treesLearn a tight boundary around normal data
Key parametercontaminationnu
Needs scaling?No — tree-basedYes — distance/kernel-based
Scales to large n?Generally yesCan be slower

The Practical Challenge — Little or No Labeled Anomaly Data

Every classifier in Section 2 of this course was trained and evaluated with y_test — real labels to check predictions against, and a precision/recall/F1 report (Lesson 13) to summarize results. Anomaly detection usually doesn't have that luxury.

1
Anomalies are rare by definition
Even in a huge dataset, there may only be a handful of confirmed anomalous examples — often not enough to train or reliably evaluate a supervised classifier.
2
Many "anomalies" are simply never confirmed
A flagged transaction or sensor reading might never get manually reviewed, so its TRUE label often stays unknown.
3
New anomaly types keep appearing
A model trained only on past known anomaly patterns can miss a genuinely new kind of anomaly it's never seen before.

This is exactly why the models in Sections 3 and 4 are UNSUPERVISED (or "semi-supervised" at best) — they never require a full set of labeled anomalies to train on, only an assumption about roughly what fraction of the data is anomalous (contamination / nu). In practice, teams often combine several signals: an unsupervised score from IsolationForest or OneClassSVM, simple statistical rules (Section 2) as a sanity check, and — whenever even a SMALL set of confirmed labels exists — spot-checking the model's top-ranked anomalies against them.

⚠️
"No labels" doesn't mean "no evaluation at all"
If even a small labeled sample exists (say, a handful of transactions a human confirmed as fraudulent), it can still be used as a rough sanity check — how many of those known anomalies did the model actually flag, even without enough data to compute a stable precision/recall report. When there are truly zero labels, evaluation often falls back to domain-expert review of the flagged cases: does a human reviewer agree the top-ranked anomalies genuinely look unusual? That qualitative check, imperfect as it is, is frequently the only evaluation available.

Lesson Summary

Z-score (|z| > 3) and the IQR method (1.5×IQR fences) are quick, single-column statistical outlier checks; IQR is more robust to skew.
IsolationForest isolates anomalies with random splits — they need FEWER splits to separate, giving them a short average path length.
OneClassSVM learns a tight boundary around the normal region using the same kernel machinery as regular SVM.
contamination and nu are assumptions about the expected anomaly rate, not values discovered by the algorithm.
Little or no labeled anomaly data is the field's core practical challenge — models here are built to work WITHOUT full supervision.
🧩 Knowledge Check — Lesson 19
4 questions on statistical outliers, IsolationForest, OneClassSVM, and evaluation without labels.
1. Why does the IQR method often handle skewed data more reliably than the z-score method?
2. What is the core idea behind how IsolationForest scores a point as anomalous?
3. What does the contamination parameter in IsolationForest (and nu in OneClassSVM) actually represent?
4. Why is anomaly detection often described as having a bigger evaluation challenge than typical supervised classification?
💪
Try It Yourself — Lesson 19
Find outliers four different ways and compare · Intermediate Level

Use any numeric column or dataset from this course — Lesson 12's house-price data works well for the statistical methods, and any multi-feature dataset works for IsolationForest/OneClassSVM.

Task 1: Flag outliers with z-score and IQR 📏

Pick one numeric column and compute outliers both ways from Section 2. Do the two methods flag the same rows, or different ones? Which method flags more?
Task 2: Tune contamination on IsolationForest 🌲

Fit IsolationForest with a couple of different contamination values (e.g. 0.02, 0.05, 0.10). How does the number of flagged anomalies change? If you have any rows you suspect are genuinely unusual, do they get flagged consistently across all three settings?
Task 3: Compare IsolationForest and OneClassSVM 🔍

Fit both models on the same scaled multi-feature data with a comparable contamination/nu setting. Using pd.crosstab (or simply comparing the two prediction arrays), how much do the two models agree on which points are anomalies? Write 2–3 sentences on what you found.
💡 Show hints if you're stuck
  • Task 1: set(zscore_outliers.index) & set(iqr_outliers.index) gives you the overlap between the two flagged sets directly.
  • Task 2: A higher contamination value will always flag MORE points as anomalies — that's a direct effect of the threshold, not new information about the data.
  • Task 3: pd.crosstab(iso_preds, svm_preds) — a large diagonal (both -1 or both 1) means the two models broadly agree; a large off-diagonal means they disagree on many points.
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 19 Complete!

You can now flag outliers with z-score and IQR, fit and interpret IsolationForest and OneClassSVM, and reason about anomaly detection's core practical challenge: little or no labeled data to check work against. One lesson left in Section 4 — the capstone project, putting K-Means to work on a real segmentation task.

Module 19 of 24 Section 4 — Unsupervised Learning