Anomaly Detection

Reviewed & published by Brayan K

Find the rare points that don't belong — the fraud, the defect, the intrusion. Learn statistical rules plus Isolation Forest, One-Class SVM, and Local Outlier Factor.

Part of the free AI & Machine Learning course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

🎯 Real-World Analogy: The Odd One Out

Picture a bank watching thousands of card transactions an hour. Almost all are ordinary — coffee, groceries, fuel. Then one charges $9,000 in a foreign country at 3am. It doesn't fit the pattern, so it gets flagged for review. That is anomaly detection.

The challenge is that fraud is rare: you mostly have examples of 'normal' and very few of 'weird'. So instead of learning to tell two balanced classes apart, anomaly detectors learn what normal looks like and flag whatever sits far outside it.

1 What Makes Anomalies Hard

An anomaly (or outlier) is a point that differs markedly from the rest. The difficulty is rarity and missing labels: anomalies might be 0.1% of the data and often nobody has tagged them. That makes the classes wildly imbalanced — a lazy classifier could call everything "normal" and score 99.9% while catching nothing useful.

So most anomaly detection is unsupervised: learn the shape of "normal" and flag what falls outside it. The methods range from simple statistical rules to dedicated algorithms.

2 Statistical Rules: Z-Score & IQR

The simplest detectors work on a single feature. The z-score rule measures how many standard deviations a point is from the mean and flags anything beyond a threshold (often 3). It assumes the data is roughly bell-shaped. The IQR rule is more robust: it uses quartiles and flags points beyond Q1 - 1.5*IQR or Q3 + 1.5*IQR.

Run both on a series with one obvious outlier and compare.

# Two statistical outlier rules by hand (plain Python): z-score and IQR.

values = [10, 11, 9, 10, 12, 11, 95]    # 95 is the obvious anomaly

# 1) Z-SCORE: how many standard deviations from the mean?  |z| > 3 = outlier.
def z_scores(data):
    n = len(data)
    mean = sum(data) / n
    std = (sum((v - mean) ** 2 for v in data) / n) ** 0.5
    return [round((v - mean) / std, 2) for v in data]

zs = z_scores(values)
print("z-scores:", zs)
print("outliers:", [v for v, z in zip(values, zs) if abs(z) > 2])

# 2) IQR: robust rule using quartiles (not distorted by the outlier).
ordered = sorted(values)
q1 = ordered[len(ordered) // 4]
q3 = ordered[3 * len(ordered) // 4]
iqr = q3 - q1
high = q3 + 1.5 * iqr
print("IQR flags above:", high, "->", [v for v in values if v > high])

# Expected output:
# z-scores: [-0.45, -0.41, -0.49, -0.45, -0.37, -0.41, 2.58]
# outliers: [95]
# IQR flags above: 13.5 -> [95]

3 Model-Based Detectors

When you have many features, dedicated algorithms shine:

🌍 Worked Example: The Real Tools (scikit-learn)

Here are all three model-based detectors side by side. Study it (it isn't runnable in the in-browser sandbox) and notice the contamination / nu parameter, which tells each one roughly how many anomalies to expect.

# WORKED EXAMPLE — what the real tools look like (scikit-learn).
# You don't run this here; study it so the library code feels familiar.
from sklearn.ensemble import IsolationForest
from sklearn.svm import OneClassSVM
from sklearn.neighbors import LocalOutlierFactor

X = [[10], [11], [9], [10], [12], [11], [95]]   # 95 is the anomaly

# Isolation Forest: anomalies isolate in fewer random splits.
# contamination = expected fraction of anomalies (~1 in 7 here).
iso = IsolationForest(contamination=0.15, random_state=0)
print("IsolationForest:", iso.fit_predict(X))   # -1 = anomaly, 1 = normal

# One-Class SVM: learns a boundary around the normal points.
ocsvm = OneClassSVM(nu=0.15, gamma="scale")
print("OneClassSVM:", ocsvm.fit_predict(X))

# Local Outlier Factor: compares local density to neighbours.
lof = LocalOutlierFactor(n_neighbors=2, contamination=0.15)
print("LOF:", lof.fit_predict(X))

# Expected output (the 95 is flagged -1 by each):
# IsolationForest: [ 1  1  1  1  1  1 -1]
# OneClassSVM:     [ 1  1  1  1  1  1 -1]
# LOF:             [ 1  1  1  1  1  1 -1]

All three flag the value 95 as -1. In practice you'd tune the contamination from how often anomalies really occur.

4 The Contamination Parameter

Most detectors need to know roughly how many anomalies to expect — the contamination (or nu) parameter. It sets the threshold between the normal scores and the anomalous ones. Set it from domain knowledge: if about 1% of transactions are fraudulent, contamination is roughly 0.01.

🎯 Your Turn 1: Z-Score Flag

Fill in the blank so is_outlier() compares the absolute z-score to the threshold. The expected output is in the comments.

# 🎯 YOUR TURN — finish the z-score outlier flag.
# z = (value - mean) / std.  Flag points with |z| greater than a threshold.

values = [50, 52, 49, 51, 200]      # 200 is the anomaly
mean = sum(values) / len(values)
std = (sum((v - mean) ** 2 for v in values) / len(values)) ** 0.5

def is_outlier(v, threshold=2.0):
    z = (v - mean) / std
    return abs(z) > ___             # 👉 compare |z| to 'threshold'

print([v for v in values if is_outlier(v)])

# ✅ Expected output:
# [200]

🎯 Your Turn 2: Read the Label

Detectors return -1 for anomalies and 1 for normal. Fill in the two blanks to translate the label into words.

# 🎯 YOUR TURN — interpret the scikit-learn anomaly label.
# These detectors return -1 for an anomaly and 1 for a normal point.

def label_to_text(label):
    if label == -1:
        return ___        # 👉 return "anomaly"
    else:
        return ___        # 👉 return "normal"

for lab in [1, 1, -1, 1]:
    print(label_to_text(lab))

# ✅ Expected output:
# normal
# normal
# anomaly
# normal

🎯 Mini-Challenge: Build the IQR Rule

Implement the robust IQR outlier rule from scratch and flag the outlier. Only a comment outline is provided.

# 🎯 MINI-CHALLENGE: build the IQR outlier rule from scratch
# The IQR rule is robust because it uses quartiles, not the mean.
#
# 1. data = [4, 5, 6, 5, 4, 6, 5, 40]
# 2. Sort it, then estimate Q1 (25th pct) and Q3 (75th pct) by index
# 3. iqr = Q3 - Q1 ; lower = Q1 - 1.5*iqr ; upper = Q3 + 1.5*iqr
# 4. print() any value below 'lower' or above 'upper'
#
# ✅ Expected: 40 is flagged as the outlier

# your code here

5 Common Errors (And How to Fix Them)

These are the traps that catch anomaly-detection beginners. Watch for them.

❌ Judging an imbalanced detector by accuracy

With 0.1% anomalies, calling everything "normal" scores 99.9% accuracy and catches nothing.

accuracy = (correct / total)   # ❌ misleading on rare events

✅ Fix: use precision, recall, and F1 on the anomaly class:

precision_recall_fscore_support(y_true, y_pred)

❌ Using z-score on heavily skewed data

The mean and std are themselves distorted by the very outliers you're hunting.

flag if abs(z_score(v)) > 3   # ❌ unreliable on skewed data

✅ Fix: use the robust IQR rule (quartile-based):

flag if v < Q1 - 1.5*IQR or v > Q3 + 1.5*IQR

❌ Guessing the contamination blindly

A wildly wrong contamination floods you with false alarms or hides real anomalies.

IsolationForest(contamination=0.5)   # ❌ flags half the data

✅ Fix: set it from the real anomaly rate:

IsolationForest(contamination=0.01)   # ~1% fraud expected

📋 Quick Reference

ConceptWhat It IsKey Point
AnomalyRare, very different pointOften unlabelled
Z-scoreStd-devs from the meanAssumes bell-shaped data
IQR ruleBeyond 1.5*IQR of quartilesRobust to skew
Isolation ForestRandom isolation treesShort path = anomaly
One-Class SVMBoundary around normalOutside = anomaly
LOFLocal density vs neighboursCatches local outliers
contaminationExpected anomaly fractionSets the threshold
Use caseFraud, intrusion, defectsRare events matter most

🎉 Lesson Complete!

You can now flag outliers with the z-score and robust IQR rules, and reach for Isolation Forest, One-Class SVM, or Local Outlier Factor on richer data — tuning contamination to the real anomaly rate.

Practice quiz

What is anomaly detection?

  • Predicting a continuous value
  • Finding rare points that differ markedly from the rest
  • Grouping similar points
  • Reducing dimensions

Answer: Finding rare points that differ markedly from the rest. Anomaly (outlier) detection flags the unusual points that don't fit the normal pattern of the data.

Why are anomalies usually hard to learn with ordinary classification?

  • They are too common
  • They are rare and often unlabelled, so classes are highly imbalanced
  • They have too many features
  • They never repeat

Answer: They are rare and often unlabelled, so classes are highly imbalanced. Anomalies are rare and frequently unlabelled, so the data is extremely imbalanced and standard classifiers struggle.

How does the z-score method flag an outlier?

  • By clustering
  • By tree depth
  • By how many standard deviations a point is from the mean
  • By the median only

Answer: By how many standard deviations a point is from the mean. A z-score measures distance from the mean in standard deviations; points beyond a threshold (e.g. |z| > 3) are flagged.

The IQR method flags points that fall outside:

  • The mean plus 1
  • 1.5 times the interquartile range beyond Q1 or Q3
  • The first value
  • Any negative value

Answer: 1.5 times the interquartile range beyond Q1 or Q3. The IQR rule flags values below Q1 - 1.5*IQR or above Q3 + 1.5*IQR; it is robust because it uses quartiles, not the mean.

How does Isolation Forest detect anomalies?

  • By averaging trees' votes for a label
  • Anomalies are isolated in fewer random splits than normal points
  • By computing distances to centroids
  • By gradient descent

Answer: Anomalies are isolated in fewer random splits than normal points. Isolation Forest randomly partitions data; outliers get isolated with very few splits, giving short path lengths.

What does One-Class SVM learn?

  • A boundary around the normal data, flagging anything outside as anomalous
  • Two balanced classes
  • A regression line
  • A cluster count

Answer: A boundary around the normal data, flagging anything outside as anomalous. One-Class SVM fits a tight boundary around the 'normal' training points; new points outside that boundary are anomalies.

Local Outlier Factor (LOF) measures anomalies based on:

  • Global mean only
  • A point's local density compared with its neighbours' density
  • Tree depth
  • The label distribution

Answer: A point's local density compared with its neighbours' density. LOF compares a point's density to that of its neighbours; a point in a much sparser region than its neighbours is an outlier.

Statistical methods like z-score assume the data is roughly:

  • Uniformly random
  • Normally distributed (bell-shaped)
  • All identical
  • Categorical

Answer: Normally distributed (bell-shaped). The z-score rule relies on a roughly normal distribution; on skewed data the robust IQR method is usually safer.

Which is a classic real-world use case for anomaly detection?

  • Image resizing
  • Credit-card fraud detection
  • Sorting a list
  • Spell-checking

Answer: Credit-card fraud detection. Fraud detection is a flagship use case: fraudulent transactions are rare anomalies hidden among many normal ones.

In scikit-learn, what does a contamination parameter set?

  • The learning rate
  • The number of features
  • The tree depth
  • The expected proportion of anomalies in the data

Answer: The expected proportion of anomalies in the data. contamination tells the detector roughly what fraction of points to expect as anomalies, setting the decision threshold.

Continue this course

Frequently asked questions

What is anomaly detection and where is it used?

Anomaly detection finds the rare points that look very different from the rest of the data — the outliers. It powers fraud detection, network intrusion alerts, manufacturing defect spotting, and health monitoring. The unifying theme is that the interesting events are rare and you mostly only have examples of 'normal'.

Why can't I just use a normal classifier?

Anomalies are rare and often unlabelled, so the dataset is extremely imbalanced — you might have 0.1% fraud and 99.9% normal. A standard classifier can score 99.9% accuracy by always predicting 'normal' and catch nothing. Anomaly-detection methods are designed for this imbalance, often learning only what 'normal' looks like.

How do the statistical methods (z-score and IQR) work?

The z-score method measures how many standard deviations a point sits from the mean; anything beyond a threshold like 3 is flagged. It assumes the data is roughly bell-shaped. The IQR method uses quartiles: it flags points below Q1 - 1.5*IQR or above Q3 + 1.5*IQR. IQR is more robust because the mean and standard deviation are themselves distorted by outliers.

What is Isolation Forest and why is it popular?

Isolation Forest builds many random trees that split the data on random features at random thresholds. Anomalies, being different, get separated from the rest in very few splits — they have short 'path lengths'. Averaging these path lengths across the forest gives an anomaly score. It is fast, scales well, and works in high dimensions.

When would I use One-Class SVM or Local Outlier Factor?

One-Class SVM learns a tight boundary around the normal data; anything that falls outside is an anomaly. It works well when you have mostly clean normal data. Local Outlier Factor compares each point's local density with that of its neighbours, so it catches outliers that sit in a sparse region even if they aren't globally extreme — good for clusters of varying density.

What does the contamination parameter do?

Many scikit-learn detectors (Isolation Forest, LOF, One-Class SVM) take a contamination value, the expected fraction of anomalies. It sets where the threshold lands between normal and anomalous scores. Set it from domain knowledge — if you expect about 1% fraud, contamination is roughly 0.01.