Time Series Anomaly Detection
Why time series anomalies are a distinct problem
Detecting an anomaly in a static dataset (an outlier row in a table) and detecting an anomaly in a time series are different problems. A time series value can be perfectly normal in isolation but anomalous given its recent history (a sudden spike), or normal in trend but anomalous relative to a seasonal pattern (unusually low sales for a Saturday, even if that absolute value would be normal for a Tuesday). Effective time series anomaly detection has to account for trend, seasonality, and temporal dependency — not just the raw value's distribution.
Statistical baselines: decompose, then flag residuals
A common and surprisingly strong baseline decomposes a series into trend, seasonal, and residual components (e.g. via STL decomposition — Seasonal-Trend decomposition using LOESS), then treats large deviations in the residual component as anomalies, typically flagged via a threshold on z-score or a robust equivalent like the median absolute deviation (MAD), which is less sensitive to the very outliers you're trying to detect than the mean/standard deviation would be:
$$\text{MAD} = \text{median}(|x_i - \text{median}(x)|)$$
A point is flagged when its residual's deviation from the median exceeds some multiple of the MAD, scaled by a constant (commonly 1.4826) to make it comparable to a standard deviation under normality.
import numpy as np
def flag_anomalies_mad(residuals, threshold=3.5):
median = np.median(residuals)
mad = np.median(np.abs(residuals - median))
scaled_mad = mad * 1.4826 # make MAD comparable to a normal-distribution std dev
modified_z_scores = (residuals - median) / (scaled_mad + 1e-9)
return np.abs(modified_z_scores) > threshold
# Works on the RESIDUAL after removing trend/seasonality -- never on raw values directly,
# since raw values legitimately swing with trend and season.Forecasting error as an anomaly signal
Deep learning approaches: autoencoders and beyond
Autoencoder-based methods train a network to reconstruct normal sequences through a compressed bottleneck, learning only on data assumed to be anomaly-free (or mostly so). At inference, points with high reconstruction error are flagged as anomalous, on the theory that the autoencoder has only learned to accurately reconstruct the patterns it saw during training. LSTM and transformer variants extend this to capture longer temporal dependencies than a simple feedforward autoencoder would. More recent approaches frame detection as self-supervised contrastive learning — learning representations where normal windows cluster together and anything that falls far from that cluster at inference time is flagged.
Approach comparison
| Approach | Needs labeled anomalies? | Handles seasonality well? | Typical use case |
|---|---|---|---|
| STL + MAD threshold | No | Yes, if decomposition is accurate | Metrics dashboards, simple and interpretable |
| Forecast-error based | No | Yes, if forecaster models it | Infra/ops monitoring, sensor data |
| Autoencoder reconstruction error | No (unsupervised) | Depends on training data coverage | Complex multivariate sensor/IoT data |
| Supervised classifier | Yes | Only as well as labels reflect it | Fraud/rare-event detection with labeled history |
Labeled anomalies are rare, and that breaks naive evaluation
What's Next?
The reconstruction-error and forecast-surprise principles used here generalize directly to out-of-distribution detection for any model type — the same core idea, 'flag inputs the model finds surprising relative to what it learned,' reappears well beyond time series whenever a system needs to know when it's operating outside its training distribution.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.