Anomaly Detection

Machine Learning Notes · unsupervised 2 of 2 · Anomaly detection ← Clustering and k-means Collaborative filtering →

Clustering asked which unlabelled points belong together. This note asks the opposite question of the same unlabelled data: which point does not belong at all?

An aircraft engine comes off the line and is measured — heat generated, vibration intensity, a dozen other numbers. Thousands of engines have been measured before it, and almost all of them were fine. Nobody has labelled which of the earlier engines were faulty, and nobody can list the ways a new engine might fail. What is available is a cloud of points that represents normal, and one new point that is either in it or outside it.

In one line. Fit a probability model $p(\vec{x})$ to data you believe is normal, then flag any new example whose probability falls below a threshold: $p(\vec{x}) < \epsilon$ means anomaly. With one Gaussian fitted per feature and the features treated as independent, $p(\vec{x})$ is just the product of $n$ one-dimensional bell curves — and $\epsilon$ is chosen on a cross-validation set that does contain a few labelled failures.

Contents
  1. The question, and where it is asked
  2. Density estimation
  3. The Gaussian
  4. Fitting the parameters
  5. From one feature to many
  6. The algorithm
  7. A worked example
  8. Evaluating it, and choosing $\epsilon$
  9. Anomaly detection or supervised learning?
  10. Where this goes next

The question, and where it is asked

The setup is always the same shape. You have ${\vec{x}^{(1)}, \ldots, \vec{x}^{(m)}}$ — examples that are mostly normal — and a new $\vec{x}_{\text{test}}$, and you must decide whether the new one is unusual enough to act on. Three standard settings:


Density estimation

The method is to model how the normal data is distributed and then read off how likely the new point is under that model:

$$ p(\vec{x}_{\text{test}}) \;\ge\; \epsilon \;\Rightarrow\; \text{normal}, \qquad p(\vec{x}_{\text{test}}) \;<\; \epsilon \;\Rightarrow\; \text{anomaly}. \tag{1} $$
Equation 1: The decision rule. A new example is normal when its probability under the fitted model clears the threshold $\epsilon$ and an anomaly when it falls below — the whole method is this one comparison, and everything else in the note is how to compute $p(\vec{x})$ and how to choose $\epsilon$.

Picture the training points as a cloud with contour rings drawn around its centre. Points inside the inner rings sit where the data is dense and get a high probability; points out past the last ring get a small one. $\epsilon$ is where you decide to draw the line, and it is a genuine design choice — §8 is about how to make it. Figure 4 draws that picture for real once the parameters are in hand, and the thing worth noticing in advance is that choosing $\epsilon$ is choosing one of the rings.


The Gaussian

The formula and its two parameters

For a single number $x$, the model is the normal (Gaussian, bell-shaped) distribution:

$$ p\left(x; \mu, \sigma^2\right) = \frac{1}{\sqrt{2\pi}\,\sigma}\, \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right). \tag{2} $$
Equation 2: The Gaussian density. $\mu$ is the mean — where the bell is centred — and $\sigma$ the standard deviation, which sets its width; $\sigma^2$ is the variance. The $1/(\sqrt{2\pi}\sigma)$ in front is exactly what makes the total area under the curve equal to 1.

Two things follow from that normalisation and are worth holding on to. The area under the whole curve is $1$, because $x$ has to take some value. And the curve is a density, not a probability — its height at a point can exceed 1, as it does below for $\sigma = 0.5$.

What $\mu$ and $\sigma$ do to the curve

Figure 1: One family, four settings. Halving $\sigma$ from 1 to 0.5 doubles the peak to 0.798 and pulls the mass into a narrow spike; doubling it to 2 flattens the peak to 0.199 and spreads the mass out. All three keep area 1 — that is the trade. Changing $\mu$ from 0 to 3 slides the identical curve sideways without changing its shape at all.

Fitting the parameters

Given the training data, $\mu$ and $\sigma^2$ are estimated the obvious way — the mean of the data and the mean squared deviation from it:

$$ \mu = \frac{1}{m}\sum_{i=1}^{m} x^{(i)}, \qquad \sigma^2 = \frac{1}{m}\sum_{i=1}^{m}\left(x^{(i)} - \mu\right)^2 . \tag{3} $$
Equation 3: Maximum-likelihood estimates for one feature. These are not a heuristic: they are the exact values of $\mu$ and $\sigma^2$ that make the observed training data most probable under the Gaussian model.

$\frac{1}{m}$ or $\frac{1}{m-1}$? Statistics texts divide the variance by $m-1$ to make the estimator unbiased; maximum likelihood gives $m$. For anomaly detection it makes no practical difference — $m$ is in the thousands, the two differ by a factor of $m/(m-1) \approx 1.0002$, and any effect is absorbed when you tune $\epsilon$ anyway.


From one feature to many

The independence product

Each example is a vector now, and the model treats the features as statistically independent, which turns the joint density into a product of the individual ones:

$$ p(\vec{x}) = p\left(x_1; \mu_1, \sigma_1^2\right)\,p\left(x_2; \mu_2, \sigma_2^2\right)\cdots p\left(x_n; \mu_n, \sigma_n^2\right) = \prod_{j=1}^{n} p\left(x_j; \mu_j, \sigma_j^2\right). \tag{4} $$
Equation 4: The density for $n$ features. Each factor is its own one-dimensional Gaussian with its own mean and variance, fitted from that feature's column of the training data.

The independence assumption is, strictly, false — heat and vibration in an engine are correlated. It is made anyway, and it works, because what matters is the ranking of points by probability rather than the probability being right.

Why a product catches things a single feature cannot

Multiplying is what makes the method sensitive. Suppose an engine's heat is on the high side — something one engine in ten does — and its vibration is high too, one in twenty. Neither number is alarming alone. Together:

$$ p(x_1)\,p(x_2) = \tfrac{1}{10} \times \tfrac{1}{20} = \tfrac{1}{200}, $$

and a one-in-two-hundred engine is worth looking at. Each additional feature multiplies another number below 1 into the product, so a point that is mildly unusual in several respects at once ends up with a very small $p(\vec{x})$ — which is exactly the kind of failure a human inspector would miss.

Figure 2: Why multiplying is what makes the method sensitive. Each curve is an example sitting the same modest distance from the mean on every one of $n$ independent features, and the $y$-axis is how many times less dense it is than the peak — so a value of 403 means a 1-in-403 example. Because the factors multiply, every line is straight on a log axis, gaining a constant factor $e^{k^2/2}$ per feature. One standard deviation out on twelve features is 1 in 403; one and a half on twelve is 1 in 729,416; two on eight is already 1 in 8.9 million. No single feature in any of these cases is remarkable enough on its own to raise an eyebrow.

The algorithm

Figure 3: The whole procedure. Only the last box is a decision, and only the last box uses $\epsilon$ — everything before it is fitting means and variances, which is a single pass over the data.
  1. Choose $n$ features $x_j$ that you think might be indicative of anomalous examples.
  2. Fit the parameters $\mu_1, \ldots, \mu_n$ and $\sigma_1^2, \ldots, \sigma_n^2$ from the training set. Vectorized, the means are just $\vec{\mu} = \frac{1}{m}\sum_i \vec{x}^{(i)}$.
  3. Given a new example, compute $p(\vec{x}) = \prod_j p(x_j; \mu_j, \sigma_j^2)$ and declare an anomaly if $p(\vec{x}) < \epsilon$.

There is no iteration and no gradient descent anywhere — step 2 is closed-form.


A worked example

Two features, with parameters already fitted, and the threshold set at $\epsilon = 0.02$:

$$ \mu_1 = 5,\; \sigma_1 = 2 \qquad\text{and}\qquad \mu_2 = 3,\; \sigma_2 = 1 . $$

test example$p(x_1; 5, 2^2)$$p(x_2; 3, 1^2)$$p(\vec{x})$verdict at $\epsilon = 0.02$
$\vec{x}^{(1)}_{\text{test}} = (4, 4)$$0.1760$$0.2420$$0.0426$normal — $0.0426 \ge 0.02$
$\vec{x}^{(2)}_{\text{test}} = (9, 1)$$0.0270$$0.0540$$0.0015$anomaly — $0.0015 < 0.02$
Table 1: Two test engines through the same model. The first is a little off-centre in both features and survives; the second is two standard deviations high on feature 1 and two low on feature 2, and the product of two modest numbers lands it an order of magnitude below the threshold.

Neither individual factor looks damning — $0.027$ and $0.054$ are small but not absurd. It is their product, $0.001458$, that is thirteen times below the threshold. That is the mechanism of §5.2 doing its job on real numbers.

Figure 4: The model of section 7 drawn in the plane it lives in. The rings are contours of constant $p(x)$ — ellipses, not circles, because $\sigma_1 = 2$ is twice $\sigma_2 = 1$, so the model tolerates twice as much deviation horizontally. The thick red ring is the decision boundary itself: setting $\epsilon = 0.02$ picks out the ellipse centred on $(5,3)$ with semi-axes $3.32$ and $1.66$, and the whole algorithm reduces to asking which side of it a point falls on. The first test engine at $(4,4)$ is comfortably inside; the second at $(9,1)$ is outside on both axes at once, which is what drove its $p$ an order of magnitude under the threshold.

Evaluating it, and choosing $\epsilon$

The importance of a single number

So far nothing has said whether the system is any good, or where $\epsilon$ should sit. Developing any learning algorithm — choosing features, tuning thresholds — is far easier when each change produces one number you can compare. That requires some labelled data, which seems to contradict the whole premise; the resolution is that you need very few labels, and only for evaluation, never for fitting.

Label the examples you do know about: $y = 1$ for anomalous, $y = 0$ for normal. Then:

How to split data you have almost none of

Ng's worked case: 10,000 good engines and 20 flawed ones.

splittrainingcross-validationtest
Standard6,000 good2,000 good + 10 anomalies2,000 good + 10 anomalies
No test set6,000 good4,000 good + 20 anomalies
Table 2: Two ways to split a badly skewed dataset. The first keeps an untouched test set and is the honest choice; the second exists because 20 anomalies split three ways is almost nothing, and it accepts a real risk in exchange for tuning on twice as many failures.

The second row is for when labelled anomalies are very few. It costs you the thing a test set buys: because $\epsilon$ and the features were tuned on the same 20 anomalies that report the score, the reported score is optimistic — a higher risk of overfitting, and you should say so when quoting the number.

Which metric

On the cross-validation set, turn the density into a prediction and score it:

$$ y = \begin{cases} 1 & \text{if } p(\vec{x}) < \epsilon \quad (\text{anomaly}) \\[4pt] 0 & \text{if } p(\vec{x}) \ge \epsilon \quad (\text{normal}) \end{cases} \tag{5} $$
Equation 5: The anomaly detector as a classifier. This is the only place $\epsilon$ enters, which is what makes it tunable after the fact: the model is fitted once, and sweeping $\epsilon$ costs nothing but a comparison.

Score it — but not with accuracy — with 2,000 normal engines and 10 flawed ones, predicting "normal" every time scores $99.5\%$ and catches nothing. The metrics that survive a skew like that are the ones from model development: true/false positives and negatives, precision and recall, and $F_1$. Sweep $\epsilon$ over a range, compute $F_1$ on the cross-validation set for each, and keep the best.

Figure 5: Sweeping $\epsilon$ over a simulated cross-validation set — 2,000 normal engines and 10 flawed ones, four features. Recall climbs with $\epsilon$ because a looser threshold flags more of everything; precision collapses for the same reason, and collapses hard, because there are 200 normal engines for every flawed one. $F_1$ is the compromise, and it peaks at $\epsilon = 1.5 \times 10^{-7}$, where 5 of the 10 anomalies are caught with no false alarms at all. Two things to read off the shape: the peak is a genuine interior optimum rather than an endpoint, and the curve is visibly jagged — with only 10 labelled anomalies each one moves recall by a tenth, which is exactly the fragility section 8.2 warned about.

Anomaly detection or supervised learning?

Both use labelled anomalies. The question of which to use is decided by how many you have and whether the future will look like the past:

Anomaly detectionSupervised learning
Positive examplesVery few ($0$–$20$ is common)Many
Negative examplesLarge number, used to model $p(\vec{x})$Large number, used as a class
What it learnsWhat normal looks likeWhat the positive class looks like
Kinds of anomalyMany different types; future ones may look like nothing seen so farEnough examples to learn the type; future positives resemble training ones
Typical useFraud, manufacturing defects, machine monitoringSpam, disease classification, weather prediction
Table 3: The choice. The deciding question is the last row: if the next failure will be a kind you have never seen, a classifier trained on the failures you have seen cannot recognise it — but a model of normality does not need to have seen it.

Fraud and spam are the pair worth remembering. Spam is supervised: there are millions of labelled spam messages and tomorrow's spam looks much like today's. Fraud is anomaly detection: the profitable frauds are the new ones, and a classifier trained on last year's schemes is trained on exactly the schemes that no longer work.

The one-line difference. Anomaly detection models $p(\vec{x})$ — the density of normal data — and thresholds it. Supervised learning models $p(y \mid \vec{x})$ — the boundary between labelled classes. One asks "is this like the data I have seen?", the other asks "which class is this?"

Beyond the independent Gaussians. The product model above assumes the features do not interact. When they do, the standard upgrade is a multivariate Gaussian, $\vec{x} \sim \mathcal{N}(\vec{\mu}, \Sigma)$ with a full covariance matrix, which scores a point by its Mahalanobis distance $D_M^2 = (\vec{x}-\vec{\mu})^{\mathsf{T}}\Sigma^{-1}(\vec{x}-\vec{\mu})$ and so can flag a point that is unremarkable in every single feature but sits far off the correlation ridge. Other variants replace the density model entirely — one-class SVM, isolation forest, or an autoencoder flagging large reconstruction error $\lVert \vec{x} - \hat{\vec{x}} \rVert^2$. All of them keep the same two-part shape: a score for normality, and a threshold tuned on a few labelled failures.


Where this goes next

That completes the unsupervised pair: k-means groups unlabelled data, anomaly detection models it densely enough to say what falls outside. Both take a cloud of $\vec{x}$ with no $y$ and extract something usable from its geometry alone.

The next subject in the course keeps the "no explicit labels" flavour but changes the object of study completely:

Backwards from here: model development has the precision/recall and $F_1$ machinery §8.3 leans on, and clustering is the other half of this track.

Machine Learning Notes · unsupervised 2 of 2 · Anomaly detection ← Clustering and k-means Collaborative filtering →