<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
  <title>Tolga Ustunkok</title>
  <link>http://ustunkok.com.tr</link>
  <description>Personal blog by Tolga Ustunkok</description>
  <language>en</language>
  <lastBuildDate>Sat, 15 Aug 2026 09:18:26 +0000</lastBuildDate>
<item>
  <title>Cheap, Scalable Time-Series Anomaly Detection — 10M–150M Series, Online Training, Daily Batch OK</title>
  <link>http://ustunkok.com.tr/posts/cheap-scalable-time-series-anomaly-detection-10m150m-series-online-training-daily-batch-ok</link>
  <description>What anomaly-detection models/methodologies are (a) cheap, (b) highly extensible to **150M unique series** (or 10M if 150M is not possible), (c) support **online training**, and (d) can run in **batch (daily)** but not strictly?</description>
  <pubDate>Sat, 15 Aug 2026 09:18:26 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/cheap-scalable-time-series-anomaly-detection-10m150m-series-online-training-daily-batch-ok</guid>
  <content:encoded><![CDATA[<h2>0. TL;DR</h2>
<ol>
<li><strong>150M series is feasible — it is a solved problem at the storage/platform layer, and the cheap algorithms scale too.</strong> VictoriaMetrics single-node is documented for <strong>up to 100M active series</strong> and the cluster version for <strong>billions</strong> (<a href="https://docs.victoriametrics.com/faq/" rel="noopener noreferrer">VM FAQ</a>). Anodot ran anomaly detection over <strong>&gt;120M series, &gt;6B data points/day</strong> in production in 2017 (<a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot, PMLR 71</a>). So the target is within demonstrated practice — <strong>not</strong> a "downgrade to 10M" situation. 10M is trivially within range.</li>
<li><strong>The binding constraint is per-series <em>model state</em> and per-point compute, not raw storage.</strong> Keep per-series state in the <strong>hundreds of bytes to a few KB</strong> range (bounded sufficient statistics, seasonal coefficients, an anomaly threshold), and every series is cheap. This is exactly what the streaming/statistical methods do. Per-series deep networks or big forests break the budget at 150M.</li>
<li><strong>The cheap tier that dominates = "residual + adaptive threshold":</strong> model the <em>expected</em> value (EWMA / Holt-Winters / z-score / median-seasonal), flag points whose residual exceeds an <strong>adaptively learned threshold</strong> (Extreme-Value-Theory SPOT/POT, or online MAD/quantile/z-score). O(1) per point, tiny state, <strong>online by construction</strong>, no GPU.</li>
<li><strong>Online training is the default for these methods — it's an O(1) state update, not SGD.</strong> EWMA/CUSUM, Bayesian Online Changepoint Detection, SPOT/DSPOT, Random Cut Forest (streaming insert), and Holt-Winters recursive updates all update incrementally as points arrive. "Online" at 150M series must mean closed-form per-point state updates, not gradient descent per series.</li>
<li><strong>Daily batch is fully supported and is a valid operating point.</strong> VictoriaMetrics <code>vmanomaly</code> and Merlion/Greykite all let you schedule <code>fit_every: 1d</code> (batch refit) <strong>or</strong> run truly online models with exponential decay. You can mix: a cheap online scorer every point + a heavier model refit daily on a filtered subset.</li>
<li><strong>Recommended shape:</strong> a two-tier pipeline — (Tier 1) a cheap streaming statistical detector on every series/every point, (Tier 2) a heavier model (RRCF or shared/global model) escalated only on flagged windows. This is the same split Uber uses in production (outlier detector → outage detector) and is how you keep 150M-series cost bounded.</li>
</ol>
<hr>
<h2>1. Constraints restated</h2>
<ul>
<li><strong>150M unique series</strong> (10M fallback). Any per-series cost — parameters, state, compute, storage — is multiplied by ~1.5×10⁸.</li>
<li><strong>Cheap</strong> — CPU-only, low per-point cost, low memory, low ops overhead (no hand-tuning 150M models).</li>
<li><strong>Online training supported</strong> — the model must be able to learn/adapt incrementally as new data arrives.</li>
<li><strong>Batch (daily) acceptable but not strict</strong> — a daily refit/run cadence is fine; continuous streaming is a bonus, not a hard requirement.</li>
<li><strong>Highly extensible</strong> — pluggable model families, easy to add series and swap algorithms without re-architecting.</li>
</ul>
<hr>
<h2>2. Feasibility verdict (the "150M vs 10M" question)</h2>
<p><strong>Storage/platform layer — 150M is proven.</strong>
- VictoriaMetrics: single-node handles <strong>up to 100M active time series and 2M samples/s</strong>; the cluster version handles <strong>billions of active series and hundreds of millions of samples/s</strong> (based on real usage). — <a href="https://docs.victoriametrics.com/faq/#what-are-scalability-limits-of-victoriametrics" rel="noopener noreferrer">VictoriaMetrics FAQ, "scalability limits"</a>
- Anodot's commercial system (peer-reviewed description): <strong>"discovers anomalies today for about 50 different companies and over 120 million time series metrics"</strong>, processing <strong>"over 6 billion data points per day"</strong>, with <strong>~20M of those series found to have seasonal patterns</strong>. — <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Toledano et al., PMLR 71:56–65, 2018</a>
- Uber's Argos monitors <strong>"tens of millions of metrics"</strong> in real time. — <a href="https://www.uber.com/us/en/blog/argos-real-time-alerts/" rel="noopener noreferrer">Uber Engineering, "Identifying Outages with Argos"</a></p>
<p><strong>Model layer — this is where the 150M vs 10M distinction actually lives.</strong></p>
<table>
<thead>
<tr>
<th>Per-series state S</th>
<th>Live RAM for 150M series</th>
</tr>
</thead>
<tbody>
<tr>
<td>512 B</td>
<td>~77 GB</td>
</tr>
<tr>
<td>1 KB</td>
<td>~150 GB</td>
</tr>
<tr>
<td>4 KB</td>
<td>~600 GB</td>
</tr>
<tr>
<td>16 KB</td>
<td>~2.4 TB</td>
</tr>
<tr>
<td>400 KB (a small RRCF forest)</td>
<td>~60 TB</td>
</tr>
<tr>
<td>1 MB</td>
<td>~150 TB</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>10M series:</strong> you can afford ~1–100 KB of state per series (even a modest per-series forest or small adapter) within a few TB. Almost any "cheap" method fits.</li>
<li><strong>150M series:</strong> you are essentially restricted to <strong>O(1)-state statistical methods</strong> (EWMA/CUSUM, online mean/variance, seasonal coefficients, a single EVT/quantile threshold) unless you spill state to disk. VictoriaMetrics <code>vmanomaly</code> supports an <strong>on-disk model mode</strong> for exactly this reason: "dumped to disk … significantly decreases RAM usage, particularly useful for larger setups" (<a href="https://docs.victoriametrics.com/anomaly-detection/components/models/" rel="noopener noreferrer">vmanomaly models doc</a>).</li>
</ul>
<p><strong>Conclusion:</strong> 150M is achievable, but only if per-series state is bounded to statistical summaries. The methods below are ordered by that budget.</p>
<hr>
<h2>3. The "cheap" method hierarchy (what to pick, and why)</h2>
<h3>3.1 Statistical streaming detectors — O(1) state, O(1)/point, online by construction</h3>
<p>These are the cheapest and the ones that actually scale to 150M.</p>
<ul>
<li><strong>EWMA / CUSUM / control charts.</strong> Classical statistical process control; maintain a running level (and optionally variance), flag points when the deviation exceeds a control limit. Closed-form, incremental, no history retained. (Background: the same exponential-weighting idea is the default "exp_avg_detector" in LinkedIn's Luminol, with a smoothing factor controlling adaptation — <a href="https://github.com/linkedin/luminol" rel="noopener noreferrer">Luminol README</a>.)</li>
<li><strong>Online z-score / MAD / quantile.</strong> Running mean+std (or median+MAD for robustness) with a fixed multiple-of-sigma threshold. These are <strong>built-in first-class "online" models in VictoriaMetrics vmanomaly</strong> (<code>zscore_online</code>, <code>quantile_online</code>, online MAD), and vmanomaly's docs explicitly recommend them as the cheap default for stationary/light-tailed data. — <a href="https://docs.victoriametrics.com/anomaly-detection/components/models/" rel="noopener noreferrer">vmanomaly models doc</a></li>
<li><strong>Seasonality via online/forecast residual.</strong> Holt-Winters (triple exponential smoothing) / ETS forecast the expected value including daily/weekly seasonality; the anomaly score is the forecast residual. This is the core of:</li>
<li><strong>Yahoo EGADS</strong> — splits the problem into a Time-Series Model (forecaster: <code>OlympicModel</code>, <code>TripleExponentialSmoothingModel</code>, etc.) + an Anomaly Detection Model (KSigma, density-based, <code>SimpleThresholdModel</code> with adaptive sensitivity). EGADS's own README: "At Yahoo, our internal Yahoo Monitoring Service (YMS) processes <strong>millions of data-points every second</strong>." — <a href="https://github.com/yahoo/egads" rel="noopener noreferrer">EGADS README</a></li>
<li><strong>Anodot</strong> — per-series model chosen by a classifier (~40% of metrics are stationary; the rest sparse/step/discrete/multi-modal/irregular), parameters fit by MLE, then an online adaptive policy updates the model as points arrive. — <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot, PMLR 71</a></li>
<li><strong>Greykite (LinkedIn)</strong> — forecast with Silverkite, flag points outside the forecast confidence interval; "Simple Anomaly Detection" <strong>auto-tunes the interval</strong> (by expected alert rate / APE) instead of hand-setting it. — <a href="https://linkedin.github.io/greykite/docs/1.0.0/html/gallery/quickstart/0200_simple_anomaly_detection.html" rel="noopener noreferrer">Greykite simple AD docs</a></li>
</ul>
<h3>3.2 Adaptive thresholds (no manual threshold, no distribution assumption)</h3>
<ul>
<li><strong>SPOT / POT (Extreme Value Theory).</strong> SPOT adapts Peaks-Over-Threshold to streams: it fits a Generalized Pareto Distribution to the tail of the residual stream and computes a high quantile as the anomaly threshold, <strong>with no manual threshold and no distributional assumption</strong>, updating as data flows. The reference implementation, <strong>libspot</strong>, is a <code>C99</code>, <code>-nostdlib</code> library for "high-throughput streaming data," self-described as <strong>"the poor man's anomaly detector"</strong> and "a cheap algorithm that must be able to run on cheap systems." — <a href="https://asiffer.github.io/libspot/" rel="noopener noreferrer">libspot</a> · <a href="https://www.kdd.org/kdd2017/papers/view/anomaly-detection-in-streams-with-extreme-value-theory" rel="noopener noreferrer">SPOT, KDD 2017</a></li>
<li><strong>Bayesian Online Changepoint Detection (Adams &amp; MacKay).</strong> Derives an <strong>exact online</strong> inference of the most recent changepoint / run-length via a simple message-passing algorithm — a principled, fully-online alternative to fixed thresholds that detects both point anomalies and regime shifts. — <a href="https://arxiv.org/abs/0710.3742" rel="noopener noreferrer">arXiv:0710.3742</a></li>
</ul>
<h3>3.3 Robust Random Cut Forest (RRCF) — streaming, but a "heavier" second stage</h3>
<ul>
<li>RRCF is an <strong>unsupervised streaming</strong> detector: each tree scores a point by the expected change in tree complexity when inserted, and the model is updated incrementally (reservoir sampling, so it works on unbounded streams). <strong>"Inference time is proportional to the number of trees"</strong>; the docs recommend <strong>100 trees</strong> to start. — <a href="https://docs.aws.amazon.com/sagemaker/latest/dg/rcf_how-it-works.html" rel="noopener noreferrer">Amazon SageMaker, "How RCF works"</a> · <a href="https://proceedings.mlr.press/v48/guha16.html" rel="noopener noreferrer">Guha et al., ICML 2016</a></li>
<li><strong>Cost note:</strong> RRCF's per-series state is <code>num_trees × num_samples_per_tree</code> points — in Merlion's default config that's <code>n_estimators=100, max_n_samples=512</code> ≈ 51k points/series, i.e., <strong>~hundreds of KB per series</strong>, not bytes. At 150M series that is ~60 TB (see §2). So use RRCF as the <strong>escalated second stage</strong> on flagged windows, or with a very small sample size, not as the always-on 150M-series scorer. (Merlion's own default detector uses exactly this pattern — see §4.1.)</li>
</ul>
<h3>3.4 Subsequence/motif methods — note but don't default to them</h3>
<ul>
<li><strong>Matrix Profile / STUMPY</strong> finds <em>discords</em> (unusual subsequences) rather than point outliers. It is excellent for shape-based anomalies but is <strong>quadratic (or O(n log n) with SCRIMP-type approximations) per series and not "cheap" at 150M</strong>. Mentioned for completeness; not recommended as the 150M-series default. — <a href="https://www.cs.ucr.edu/~eamonn/MatrixProfile.html" rel="noopener noreferrer">UCR Matrix Profile page</a> · <a href="https://github.com/stumpy-dev/stumpy" rel="noopener noreferrer">STUMPY</a></li>
</ul>
<hr>
<h2>4. Turnkey / semi-turnkey options (primary sources)</h2>
<h3>4.1 VictoriaMetrics <code>vmanomaly</code> (built for high-cardinality metrics)</h3>
<ul>
<li>Built on VictoriaMetrics, which scales to 100M (single-node) / billions (cluster) series — the anomaly service is designed for exactly this cardinality regime. — <a href="https://docs.victoriametrics.com/faq/" rel="noopener noreferrer">VM FAQ</a></li>
<li><strong>Online models:</strong> <code>zscore_online</code>, <code>quantile_online</code> (online seasonal quantile), online MAD, and <code>temporal_envelope</code> (trend + calendar/holiday + seasonal patterns; the recommended online replacement for Prophet). — <a href="https://docs.victoriametrics.com/anomaly-detection/components/models/" rel="noopener noreferrer">vmanomaly models</a></li>
<li><strong>Online adaptation knob:</strong> the <code>decay</code> parameter gives an exponential forgetting factor to online models so they "adapt to new data" without full refits (e.g., <code>decay: 0.996</code> keeps ~1 day of data dominant at 1-min granularity). — <a href="https://docs.victoriametrics.com/anomaly-detection/components/models/#decay" rel="noopener noreferrer">vmanomaly models → Decay</a></li>
<li><strong>Batch/daily and hybrid scheduling:</strong> the scheduler defines <code>fit_every</code> / <code>fit_window</code> / <code>infer_every</code>. You can run <strong>offline models on a daily refit</strong> (<code>fit_every: 1d</code>) or <strong>online models with a bootstrap-only fit</strong> (<code>fit_every: 1000d</code> + <code>infer_every: 5m</code>) — i.e., daily batch <strong>and</strong> streaming are both first-class. — <a href="https://docs.victoriametrics.com/anomaly-detection/faq/" rel="noopener noreferrer">vmanomaly FAQ / scheduler</a></li>
<li>All models emit a unified <code>anomaly_score</code> (&gt;1 = anomalous), and alerting is decoupled via <code>vmalert</code>. <strong>Caveat:</strong> <code>vmanomaly</code> is an <strong>Enterprise-licensed</strong> component (free trial available). — <a href="https://docs.victoriametrics.com/anomaly-detection/faq/" rel="noopener noreferrer">vmanomaly FAQ</a></li>
</ul>
<h3>4.2 Salesforce Merlion (unified, AutoML, distributed)</h3>
<ul>
<li>A Python framework unifying forecasting / anomaly / changepoint detection with a shared interface, AutoML, and a <strong>PySpark distributed backend</strong> for industrial scale. — <a href="https://github.com/salesforce/merlion" rel="noopener noreferrer">Merlion README</a></li>
<li>Its <strong><code>DefaultDetector</code></strong> (the "balances efficiency with performance" default) is, in source, an <strong>ensemble</strong>: univariate = <code>AutoETS</code> (error/trend/seasonality forecaster) + <code>RandomCutForest</code> (<code>online_updates=True</code>, 100 trees, 512 max samples) + <code>ZMS</code> (z-score moving statistic); multivariate = <code>VAE</code> + RRCF. This is a concrete, production-grade realization of "cheap forecaster + streaming RRCF + z-score" with <strong>online updates enabled</strong>. — <a href="https://github.com/salesforce/merlion/blob/main/merlion/models/defaults.py" rel="noopener noreferrer">Merlion <code>models/defaults.py</code> source</a></li>
<li>Anomaly scores are <strong>calibrated to z-scores</strong> and passed through a trainable threshold/calibration post-rule to cut false positives. — <a href="https://opensource.salesforce.com/Merlion/latest/merlion.models.anomaly.html" rel="noopener noreferrer">Merlion anomaly docs</a></li>
</ul>
<h3>4.3 Yahoo EGADS (Java; forecasting + detection split, designed to scale)</h3>
<ul>
<li>Open-source Java library; "a scalable, accurate and automated anomaly detection" system compiled to "a single light-weight jar and deployed easily at scale," backing Yahoo's monitoring service that processes millions of points/sec. <strong>Extensible by design</strong>: you can drop your own model into either the time-series-model or anomaly-detection-module component. — <a href="https://github.com/yahoo/egads" rel="noopener noreferrer">EGADS README</a></li>
</ul>
<h3>4.4 LinkedIn Luminol (lightweight, score-based)</h3>
<ul>
<li>Lightweight Python AD+correlation lib; <strong>no predefined threshold</strong> — every point gets an anomaly score. Ships a default <strong>bitmap detector</strong> (good for large data) plus <code>exp_avg</code> (EWMA) and <code>derivative</code> detectors. Good as a reference for the "cheap, threshold-free" pattern. — <a href="https://github.com/linkedin/luminol" rel="noopener noreferrer">Luminol README</a></li>
</ul>
<h3>4.5 Greykite (LinkedIn; forecast-interval AD)</h3>
<ul>
<li>Forecast-based AD over Silverkite; auto-tuned confidence intervals for the alert rate you want. — <a href="https://linkedin.github.io/greykite/docs/1.0.0/html/gallery/quickstart/0200_simple_anomaly_detection.html" rel="noopener noreferrer">Greykite simple AD docs</a></li>
</ul>
<hr>
<h2>5. Online training — what it concretely means here</h2>
<p>"Online training" at 150M series must be <strong>O(1) closed-form state updates</strong>, not per-series SGD. The methods that satisfy this natively:</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Online update</th>
<th>Per-point cost</th>
<th>Per-series state</th>
<th>Primary source</th>
</tr>
</thead>
<tbody>
<tr>
<td>EWMA / CUSUM</td>
<td>closed-form</td>
<td>O(1)</td>
<td>a few floats</td>
<td><a href="https://github.com/linkedin/luminol" rel="noopener noreferrer">Luminol (exp_avg)</a></td>
</tr>
<tr>
<td>Online z-score / MAD / quantile</td>
<td>running stats (with <code>decay</code>)</td>
<td>O(1)</td>
<td>a few floats</td>
<td><a href="https://docs.victoriametrics.com/anomaly-detection/components/models/" rel="noopener noreferrer">vmanomaly models</a></td>
</tr>
<tr>
<td>Holt-Winters / ETS + residual</td>
<td>recursive level/trend/season update</td>
<td>O(1)</td>
<td>~few dozen floats</td>
<td><a href="https://github.com/yahoo/egads" rel="noopener noreferrer">EGADS</a> · <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot</a></td>
</tr>
<tr>
<td>SPOT / DSPOT (EVT threshold)</td>
<td>streaming tail update</td>
<td>O(1) amortized</td>
<td>bounded tail buffer</td>
<td><a href="https://asiffer.github.io/libspot/" rel="noopener noreferrer">libspot</a> · <a href="https://www.kdd.org/kdd2017/papers/view/anomaly-detection-in-streams-with-extreme-value-theory" rel="noopener noreferrer">KDD 2017</a></td>
</tr>
<tr>
<td>Bayesian Online Changepoint Detection</td>
<td>message passing (truncated)</td>
<td>O(n) → O(k) truncated</td>
<td>run-length posterior</td>
<td><a href="https://arxiv.org/abs/0710.3742" rel="noopener noreferrer">arXiv:0710.3742</a></td>
</tr>
<tr>
<td>Random Cut Forest</td>
<td>streaming insert/delete (reservoir)</td>
<td>O(#trees · log n)</td>
<td>#trees × sample</td>
<td><a href="https://docs.aws.amazon.com/sagemaker/latest/dg/rcf_how-it-works.html" rel="noopener noreferrer">SageMaker RCF</a></td>
</tr>
</tbody>
</table>
<p><strong>Key nuance — adapting without being poisoned by anomalies.</strong> Anodot describes the production policy: during an anomaly, <strong>temporarily reduce</strong> the model's learning-rate parameters (Holt-Winters α, β, γ) so the anomaly doesn't get absorbed into "normal," then restore them after the anomaly passes; a <em>persistent</em> change eventually gets learned. — <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot §3.3, PMLR 71</a>. Uber's Argos uses a <strong>median-based</strong> robust update for the same reason ("past outages and outliers must not affect the outlier score"). — <a href="https://www.uber.com/us/en/blog/argos-real-time-alerts/" rel="noopener noreferrer">Uber Argos</a></p>
<p><strong>Streaming evaluation is a real, benchmarked thing:</strong> the Numenta Anomaly Benchmark (NAB) is built specifically for detectors that "process data in real time (not batches)" and <strong>"learn while making predictions simultaneously."</strong> — <a href="https://arxiv.org/abs/1510.03336" rel="noopener noreferrer">NAB, arXiv:1510.03336</a> · <a href="https://github.com/numenta/nab" rel="noopener noreferrer">github.com/numenta/nab</a></p>
<hr>
<h2>6. Batch (daily) is a first-class operating mode — not a limitation</h2>
<ul>
<li><strong>vmanomaly scheduling:</strong> <code>fit_every</code> controls refit cadence. <code>fit_every: 1d</code> = a classic <strong>daily batch</strong> (fit on a <code>fit_window</code>, infer); <code>fit_every: 1000d</code> + <code>infer_every: 5m</code> = <strong>bootstrap-once + stream</strong>. You can even run <strong>backtesting schedulers</strong> over a historical period to validate a config before production. — <a href="https://docs.victoriametrics.com/anomaly-detection/faq/" rel="noopener noreferrer">vmanomaly FAQ</a></li>
<li><strong>Uber's hybrid cadence:</strong> thresholds are <strong>recomputed hourly</strong> (batch-ish) while the <em>online</em> part only compares incoming points against those precomputed thresholds — "extremely fast and scalable." — <a href="https://www.uber.com/us/en/blog/argos-real-time-alerts/" rel="noopener noreferrer">Uber Argos</a></li>
<li><strong>Implication for the requirement "online training, but daily batch OK":</strong> you do <strong>not</strong> need per-point SGD. A daily (or hourly) batch refit of a cheap statistical model, or a bootstrap-once + online-decay model, both satisfy it. The requirement is best met by <strong>stateful incremental models with a decay/forgetting factor</strong>, which are cheap and give you "online" behavior even when the heavy recompute is batched.</li>
</ul>
<hr>
<h2>7. Scaling to 150M series — the recommended architecture</h2>
<ol>
<li><strong>Tier 1 — cheap always-on scorer (every series, every point).</strong> Online z-score/MAD/quantile or EWMA/CUSUM + seasonal coefficients + an EVT (SPOT/DSPOT) or online-quantile adaptive threshold. O(1) state (bytes–KB/series), O(1)/point, CPU-only, horizontally shardable by series hash. This is the only stage that must run at 150M scale.</li>
<li><strong>Tier 2 — heavier model, escalated only on flagged windows.</strong> RRCF (small forest) or a shared/global model runs only on series/windows that Tier 1 flags. This is <strong>Uber's exact production split</strong> (fast per-series "outlier detector" → heavier "outage detector" on the small remainder) and Anodot's funnel (158k single-metric anomalies → ~910 significant → 147 grouped per 4M metrics/week). — <a href="https://www.uber.com/us/en/blog/argos-real-time-alerts/" rel="noopener noreferrer">Uber Argos</a> · <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot §6, PMLR 71</a></li>
<li><strong>Bound state to the budget.</strong> At 150M, keep Tier-1 state ≤ ~1 KB/series (~150 GB RAM, or spill to disk via the vmanomaly on-disk mode). At 10M you have ~15× headroom for richer per-series state.</li>
<li><strong>Make tuning <em>learned, not manual</em>.</strong> You cannot hand-tune 150M detectors. Anodot's answer: a <strong>classifier selects the best model type per metric</strong> (~40% stationary, else sparse/step/discrete/multi-modal/irregular) and fits parameters by MLE, fully unsupervised. EGADS's answer: an <code>AutoSensitivity</code>/adaptive-threshold mechanism. — <a href="https://proceedings.mlr.press/v71/toledano18a.html" rel="noopener noreferrer">Anodot §3.1</a> · <a href="https://github.com/yahoo/egads" rel="noopener noreferrer">EGADS</a></li>
<li><strong>Extensibility point = the scorer interface.</strong> EGADS (TSM/ADM split), Merlion (unified <code>ModelFactory</code> + custom models), and vmanomaly (custom model guide) all make adding a new algorithm a plug-in, not a rewrite — this is the "highly extensible" part. — <a href="https://github.com/yahoo/egads" rel="noopener noreferrer">EGADS</a> · <a href="https://github.com/salesforce/merlion" rel="noopener noreferrer">Merlion</a> · <a href="https://docs.victoriametrics.com/anomaly-detection/components/models/#custom-model-guide" rel="noopener noreferrer">vmanomaly custom model guide</a></li>
<li><strong>Where it runs with a metrics DB.</strong> If data is in InfluxDB/VictoriaMetrics/Prometheus: <code>vmanomaly</code> natively reads/writes VictoriaMetrics; for InfluxDB use a stream/batch processor (or InfluxData Kapacitor UDF) that applies Tier-1 scoring per point and writes <code>anomaly_score</code> back. (See the sibling note for the Kapacitor detail.)</li>
</ol>
<hr>
<h2>8. Options matrix</h2>
<table>
<thead>
<tr>
<th>Approach</th>
<th>Per-series state</th>
<th>Per-point cost</th>
<th>Online?</th>
<th>Batch?</th>
<th>Extensibility</th>
<th>Fit for 150M?</th>
</tr>
</thead>
<tbody>
<tr>
<td>EWMA/CUSUM + EVT threshold (SPOT/DSPOT)</td>
<td>bytes–KB</td>
<td>O(1)</td>
<td>yes</td>
<td>yes</td>
<td>high (plug thresholds)</td>
<td>✅ best</td>
</tr>
<tr>
<td>Online z-score / MAD / quantile (vmanomaly)</td>
<td>a few floats</td>
<td>O(1)</td>
<td>yes (decay)</td>
<td>yes</td>
<td>high (custom models)</td>
<td>✅ best</td>
</tr>
<tr>
<td>Holt-Winters / ETS forecast residual (EGADS/Anodot)</td>
<td>few dozen floats</td>
<td>O(1)</td>
<td>yes (adaptive policy)</td>
<td>yes</td>
<td>high (TSM/ADM split)</td>
<td>✅</td>
</tr>
<tr>
<td>BOCPD (Adams &amp; MacKay)</td>
<td>run-length posterior</td>
<td>O(n)→O(k)</td>
<td>yes</td>
<td>yes</td>
<td>medium</td>
<td>✅ (with truncation)</td>
</tr>
<tr>
<td>RRCF (streaming forest)</td>
<td>#trees × sample (~100s KB)</td>
<td>O(#trees·log n)</td>
<td>yes</td>
<td>yes</td>
<td>high</td>
<td>⚠️ tier-2 only</td>
</tr>
<tr>
<td>Greykite forecast-interval AD</td>
<td>forecaster params</td>
<td>moderate</td>
<td>no (refit)</td>
<td>yes (daily)</td>
<td>medium</td>
<td>⚠️ tier-2 / 10M</td>
</tr>
<tr>
<td>Matrix Profile / STUMPY (discord)</td>
<td>window buffer</td>
<td>O(n log n)</td>
<td>partial</td>
<td>yes</td>
<td>medium</td>
<td>❌ not cheap at scale</td>
</tr>
</tbody>
</table>
<hr>
<h2>9. Pragmatic recommendation</h2>
<ol>
<li><strong>Start with the cheap tier, not a fancy model:</strong> online z-score/MAD (or EWMA) + <strong>seasonal residual</strong> (Holt-Winters/ETS or the vmanomaly <code>temporal_envelope</code>/<code>quantile_online</code>) + an <strong>EVT/online-quantile adaptive threshold</strong>. This single combination satisfies cheap + 150M + online + batch-daily simultaneously and is exactly what the proven systems (Anodot, Uber, EGADS, vmanomaly online models) do.</li>
<li><strong>Run it daily-batch or streaming via a scheduler</strong> (<code>fit_every: 1d</code> for offline models, or bootstrap + <code>decay</code> for online models), writing a unified <code>anomaly_score &gt; 1</code> metric and alerting off it.</li>
<li><strong>Escalate with RRCF (small forest) or a shared model only on flagged windows</strong> — buys down compute at 150M while keeping precision.</li>
<li><strong>If 150M is truly needed, engineer the state budget first</strong> (~≤1 KB/series + horizontal sharding by series); if you land at 10M, you can afford richer per-series models (RRCF, Greykite, Merlion defaults) without special effort.</li>
<li><strong>Validate on a stratified sample</strong> (tens–hundreds of series) — you can never hand-inspect 150M — and use NAB-style streaming evaluation to measure "learn while predicting" behavior.</li>
</ol>
<hr>
<h2>10. Caveats on evidence</h2>
<ul>
<li><strong>Vendor claims vs. independent benchmarks:</strong> the scale numbers (VictoriaMetrics 100M/billions; Anodot 120M series; Uber "tens of millions"; Yahoo "millions of points/sec") are <strong>first-party statements</strong> — documented capabilities of the systems' owners, not independent third-party measurements. They are trustworthy as <em>existence proofs</em> ("this scale is operated in production") but not as apples-to-apples benchmarks.</li>
<li><strong>Anodot and Uber describe <em>architecture and design considerations</em>, not reproducible open code.</strong> They are strong primary sources for the <em>pattern</em> (cheap per-series scorer + heavier escalated stage + adaptive threshold + anomaly-aware learning-rate policy), but you'd reimplement the pieces.</li>
<li><strong>RRCF state estimates</strong> are computed from the documented defaults (<code>num_trees</code>≈100, <code>num_samples_per_tree</code>≈512) and are an order-of-magnitude illustration, not a vendor-stated per-series memory figure.</li>
<li><strong>SPOT is univariate</strong> (the paper is explicit); for multivariate/contextual anomalies you combine it with a forecaster residual or escalate to a multivariate model.</li>
<li><strong>Greykite's exact AD internals</strong> are lightly documented publicly (the docs describe <em>what</em> it auto-tunes, not the full statistical detail); cite it for the "auto-tuned forecast interval" capability, not for a specific algorithm.</li>
</ul>
<hr>
<h2>References (all primary sources, verified)</h2>
<p><strong>Algorithms / papers</strong>
- Robust Random Cut Forest: Guha, Mishra, Roy, Schrijvers, ICML 2016 — https://proceedings.mlr.press/v48/guha16.html
- RRCF mechanics (streaming, reservoir sampling, 100-tree guidance): https://docs.aws.amazon.com/sagemaker/latest/dg/rcf_how-it-works.html
- SPOT (EVT streaming threshold): Siffer et al., KDD 2017 — https://www.kdd.org/kdd2017/papers/view/anomaly-detection-in-streams-with-extreme-value-theory
- libspot (SPOT reference implementation, C99): https://asiffer.github.io/libspot/
- Bayesian Online Changepoint Detection: Adams &amp; MacKay 2007 — https://arxiv.org/abs/0710.3742
- Numenta Anomaly Benchmark (streaming/online evaluation): https://arxiv.org/abs/1510.03336 · https://github.com/numenta/nab
- Matrix Profile: https://www.cs.ucr.edu/~eamonn/MatrixProfile.html · https://github.com/stumpy-dev/stumpy</p>
<p><strong>Production systems / case studies</strong>
- Anodot (120M series, 6B points/day, seasonality + adaptive online model): Toledano et al., PMLR 71:56–65, 2018 — https://proceedings.mlr.press/v71/toledano18a.html
- Uber Argos (two-stage outlier/outage, hourly dynamic thresholds): https://www.uber.com/us/en/blog/argos-real-time-alerts/
- Yahoo EGADS (TSM/ADM split, scales to millions of points/sec): https://github.com/yahoo/egads
- LinkedIn Luminol (lightweight, score-based, no fixed threshold): https://github.com/linkedin/luminol</p>
<p><strong>Frameworks / platforms</strong>
- VictoriaMetrics vmanomaly models (online/offline, decay, on-disk mode): https://docs.victoriametrics.com/anomaly-detection/components/models/
- vmanomaly FAQ (schedulers, anomaly_score, batch/backtest): https://docs.victoriametrics.com/anomaly-detection/faq/
- VictoriaMetrics scalability (100M single-node / billions cluster): https://docs.victoriametrics.com/faq/
- Salesforce Merlion (framework + DefaultDetector): https://github.com/salesforce/merlion · default detector source: https://github.com/salesforce/merlion/blob/main/merlion/models/defaults.py
- LinkedIn Greykite simple anomaly detection: https://linkedin.github.io/greykite/docs/1.0.0/html/gallery/quickstart/0200_simple_anomaly_detection.html</p>]]></content:encoded>
</item>
<item>
  <title>Anomaly Detection at 150M Series — Online, Generalized, No Data Retention</title>
  <link>http://ustunkok.com.tr/posts/anomaly-detection-at-150m-series-online-generalized-no-data-retention</link>
  <description>A generalized anomaly-detection model that (a) is tuned per series quickly, (b) does not require storing the raw data beyond one &quot;kick-start,&quot; and (c) evolves online as new points arrive. Data lives in InfluxDB (~150M *unique series*, not rows).</description>
  <pubDate>Tue, 04 Aug 2026 18:46:16 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/anomaly-detection-at-150m-series-online-generalized-no-data-retention</guid>
  <content:encoded><![CDATA[<h2>0. TL;DR / Bottom Line</h2>
<ol>
<li>
<p><strong>The single most important finding:</strong> pretrained time-series <em>foundation models</em> (MOMENT, Chronos, TimesFM, Time-MoE, TSPulse) are <strong>weak at zero-shot anomaly detection</strong> — in independent benchmarks they do not beat trivial "one-liner" statistical baselines (moving-window variance / squared difference) (<a href="https://openreview.net/pdf?id=H27kvyG4qf" rel="noopener noreferrer">ONE-LINERS, ICLR 2026</a>; <a href="https://arxiv.org/html/2412.19286v1" rel="noopener noreferrer">arXiv 2412.19286</a>). Do <strong>not</strong> build the system around the hope that an off-the-shelf foundation model will detect anomalies well. Use it as a <strong>feature extractor / initializer</strong>, and get accuracy from <strong>per-series adaptation</strong>.</p>
</li>
<li>
<p><strong>Your two constraints are in tension if taken absolutely.</strong> Online anomaly detection <em>requires</em> a model of "normal." If you store no data, the model state itself becomes the only memory of normal. The resolution is: <strong>don't store raw series, but DO keep a small bounded per-series state</strong> (rolling sufficient statistics, seasonal coefficients, an anomaly threshold, and optionally a tiny adapter/embedding). Every detected anomaly is scored against that compressed summary.</p>
</li>
<li>
<p><strong>Recommended architecture = two tiers:</strong></p>
</li>
<li><strong>Tier 1 (generalization):</strong> a shared/global model pretrained <em>once</em> on the 150M-series kick-start — used as a representation extractor / meta-prior (the "generalized" part).</li>
<li>
<p><strong>Tier 2 (tuning + evolution):</strong> a per-series, online, bounded-memory detector with an <strong>adaptive threshold</strong> (Extreme Value Theory / SPOT-POT on the residual stream) that is updated incrementally as each new point arrives (the "tuned per series" + "evolves" part).</p>
</li>
<li>
<p><strong>150M per-series states is a feasibility problem.</strong> Keep per-series state tiny (hundreds of bytes to a few KB), prefer closed-form O(1) online updates, and use a <strong>tiered/filter stage</strong> (cheap statistical detector scores every point; a heavier model runs only on flagged windows).</p>
</li>
<li>
<p><strong>You cannot feasibly hand-tune 150M detectors.</strong> Tuning must be <em>learned</em>: the global model predicts/instantiates per-series detector parameters (a meta-learning / hypernetwork pattern), and online updates keep them fresh.</p>
</li>
</ol>
<hr>
<h2>1. Constraints restated</h2>
<ul>
<li><strong>150M unique series</strong> — the "many-series" regime. Any per-series cost (params, compute, state) is multiplied by ~1.5×10⁸.</li>
<li><strong>Kick-start only</strong> — full historical data available once (for the initial/training pass); afterwards the raw data should not be retained.</li>
<li><strong>Generalized model, tunable per series, quickly</strong> — want a single model family that adapts to each series cheaply, not 150M hand-built models.</li>
<li><strong>Evolves with new data</strong> — online/incremental (streaming) learning, not periodic offline retraining on stored history.</li>
</ul>
<hr>
<h2>2. Key finding: foundation models are not great anomaly detectors out of the box</h2>
<h3>2.1 The evidence</h3>
<ul>
<li>
<p><strong>ONE-LINERS (ICLR 2026), "When Foundation Models are One-Liners"</strong> evaluates MOMENT, Chronos, TimesFM, Time-MoE, and TSPulse on anomaly detection: <strong>zero-shot performance does not significantly differ from simple one-line baselines</strong> (moving-window variance for reconstruction-based, squared difference for forecasting-based). Regardless of family or size. Root cause identified: the assumption that <em>"anomalies are harder to reconstruct/forecast"</em> <strong>does not hold</strong> for these models.
  Source: <a href="https://openreview.net/pdf?id=H27kvyG4qf" rel="noopener noreferrer">OpenReview — One-Liners</a>; companion benchmark repo <a href="https://github.com/necdetduruk/tsfm-anomaly-bench" rel="noopener noreferrer">necdetduruk/tsfm-anomaly-bench</a>.</p>
</li>
<li>
<p><strong>arXiv 2412.19286</strong>, a separate critical evaluation across five manufacturing/space datasets: traditional statistical (weighted XGBoost) and deep (autoencoder) models <strong>match or outperform</strong> TSFMs on anomaly detection/prediction, while TSFMs are far more computationally expensive and do not help in few-/zero-shot.
  Source: <a href="https://arxiv.org/html/2412.19286v1" rel="noopener noreferrer">arXiv 2412.19286</a>.</p>
</li>
<li>
<p><strong>MOMENT</strong> is the notable positive counter-example, but modest and <em>adaptation-dependent</em>: zero-shot AD = "second best F₁", but with <strong>linear probing (fine-tuning the final layer) it reaches best F₁</strong> — i.e., the value shows up <em>after adaptation</em>, not zero-shot.
  Source: <a href="https://github.com/moment-timeseries-foundation-model/moment" rel="noopener noreferrer">MOMENT README</a> (ICML 2024, <a href="https://arxiv.org/abs/2402.03885" rel="noopener noreferrer">arXiv 2402.03885</a>).</p>
</li>
<li>
<p><strong>TimesFM</strong> (Google, 200M/2.5) is a <em>forecasting</em> model with <strong>no built-in anomaly detection</strong>; AD is done by flagging points outside quantile forecast bands. HuggingFace/PEFT (LoRA) fine-tuning example exists.
  Source: <a href="https://github.com/google-research/timesfm" rel="noopener noreferrer">google-research/timesfm</a>.</p>
</li>
</ul>
<h3>2.2 Implication</h3>
<p>The "generalized" value of foundation models here is <strong>transferable representation learning</strong>, not built-in detection. That strongly favors the two-tier split: a shared representation/encoder (pretrained on the kick-start) + a lightweight per-series detector that is actually where detection happens.</p>
<hr>
<h2>3. Recommended two-tier architecture</h2>
<h3>Tier 1 — the "generalized" model (pretrained once on the kick-start)</h3>
<p>Train/share one model over the full 150M-series kick-start. Candidate roles:</p>
<ol>
<li>
<p><strong>Representation/feature extractor</strong> — e.g., an autoencoder or a TSFM used as an encoder. Detection then operates on reconstruction/forecast error (anomaly score = residual magnitude). Demonstrated by the <strong>ChronosAD</strong> line of work ("Leveraging Time Series Foundation Models for Accurate Anomaly Detection") and <strong>CHARM</strong>, which use TSFMs specifically as feature extractors for AD.
   Sources: <a href="https://arxiv.org/html/2606.01300v1" rel="noopener noreferrer">ChronosAD, arXiv 2606.01300</a>; <a href="https://github.com/amazon-science/chronos-forecasting" rel="noopener noreferrer">Chronos repo</a>.</p>
</li>
<li>
<p><strong>Meta-learner / hypernetwork</strong> — the global model <em>outputs</em> the per-series detector's parameters or hyperparameters, so "tuning" becomes an inference call rather than a hand-rolled optimization. This is the pattern that scales "tuned per series quickly" to 150M.
   Sources: <a href="https://arxiv.org/abs/2504.04374" rel="noopener noreferrer">iADCPS — incremental meta-learning for evolving CPS time-series AD, arXiv 2504.04374</a>; <a href="https://proceedings.mlr.press/v224/navarro23a.html" rel="noopener noreferrer">Meta-Learning for Fast Model Recommendation, NeurIPS/HLMR 2023</a>.</p>
</li>
</ol>
<h3>Tier 2 — the per-series online detector (the "tunable" + "evolves" part)</h3>
<p>Per series, keep a tiny <strong>bounded</strong> state and update it O(1) per point:</p>
<ul>
<li><strong>Online mean/variance / EWMA</strong> control-chart anomaly detection (e.g., <strong>AnEWMA</strong>), adapted incrementally with no batch retraining and little history.
  Source: <a href="https://www.scitepress.org/Papers/2025/134378/134378.pdf" rel="noopener noreferrer">AnEWMA — SCITEPRESS paper</a>.</li>
<li><strong>Seasonality</strong> handled via online seasonal decomposition or per-series seasonal coefficients (e.g., Holt-Winters style), so contextual/seasonal anomalies are caught.</li>
<li><strong>Adaptive threshold via Extreme Value Theory (EVT)</strong> — <strong>SPOT / POT</strong> compute a high quantile from the <em>residual stream</em> to set the anomaly threshold dynamically, with <strong>no manual threshold and no strong distribution assumptions</strong>, and no meaningful historical retention.
  Sources: <a href="https://asiffer.github.io/libspot/" rel="noopener noreferrer">SPOT — libspot</a>; <a href="https://www.kdd.org/kdd2017/papers/view/anomaly-detection-in-streams-with-extreme-value-theory" rel="noopener noreferrer">Anomaly Detection in Streams with Extreme Value Theory, KDD 2017</a>.</li>
<li><strong>Continuous-learning streaming detectors</strong> as a more expressive drop-in, e.g., Numenta <strong>HTM</strong> (learns continuously, real-time, unsupervised) and streaming-first libraries (<strong>ABERRANT</strong>, <strong>StreamAD</strong>).
  Sources: <a href="https://www.numenta.com/resources/research-publications/papers/unsupervised-real-time-anomaly-detection-for-streaming-data/" rel="noopener noreferrer">Numenta HTM paper</a>; <a href="https://github.com/numenta/nab" rel="noopener noreferrer">NAB benchmark</a>; <a href="https://github.com/OliverHennhoefer/aberrant" rel="noopener noreferrer">ABERRANT</a>; <a href="https://github.com/Fengrui-Liu/StreamAD" rel="noopener noreferrer">StreamAD, GitHub</a>.</li>
</ul>
<p>The typical detection loop is: <code>score(point | state)</code> → compare to adaptive threshold → <code>update(state, point)</code> (assuming normal) — i.e., exactly an online "score-and-adapt," which matches "evolves whenever new data is available."</p>
<hr>
<h2>4. The "don't store data" constraint — what it really means</h2>
<ul>
<li><strong>You can't avoid <em>some</em> memory of normal.</strong> Online AD needs a model of normal; the model weights + compact sufficient statistics <em>are</em> that memory. What you can avoid is <strong>storing raw historical series</strong>. Keep each series' state bounded (e.g., a short in-memory rolling window + summary stats), not exhaustive history.</li>
<li><strong>Hard trade-off:</strong> the less history you retain, the worse you detect <strong>slow / concept-drift / regime</strong> anomalies versus <strong>point</strong> anomalies. Point anomalies are cheap (a threshold on a residual). Slow or seasonal-shift anomalies may need a longer implicit context (which is, effectively, stored data). Decide which type you actually care about. NAB (Numenta) explicitly notes AD is hard to benchmark precisely for exactly this reason (Source: <a href="https://arxiv.org/pdf/1510.03336" rel="noopener noreferrer">NAB, arXiv 1510.03336</a>).</li>
<li><strong>Catastrophic forgetting / drift:</strong> pure online learning without replay can forget older regimes. Literature handles this with incremental coresets / experience replay (e.g., <strong>ONER</strong>, <strong>CADIC</strong>). For point-anomaly detection a robust online estimator + adaptive threshold is fairly resilient, but if you must detect drift/regime change you'll want a drift detector or a <em>small</em> buffered normal profile. (Review of incremental/continual AD methods — arXiv preprints <a href="https://doi.org/10.48550/arxiv.2511.08634" rel="noopener noreferrer">2511.08634</a>, <a href="https://arxiv.org/html/2412.03907v2" rel="noopener noreferrer">2412.03907</a>, <a href="https://arxiv.org/abs/2201.06763" rel="noopener noreferrer">2201.06763</a>.)</li>
<li><strong>Key subtlety worth flagging:</strong> the phrase "the model should evolve whenever new data is available" + "don't store data" is internally coherent <strong>only if</strong> the evolution is <em>online state update</em>, not offline rebatching over stored history. All the recommended options above are online-state-update.</li>
</ul>
<hr>
<h2>5. Scaling to 150M series — feasibility math</h2>
<table>
<thead>
<tr>
<th>Per-series state S</th>
<th>Live memory for 150M series</th>
</tr>
</thead>
<tbody>
<tr>
<td>512 B</td>
<td>~77 GB</td>
</tr>
<tr>
<td>1 KB</td>
<td>~150 GB</td>
</tr>
<tr>
<td>4 KB</td>
<td>~600 GB</td>
</tr>
<tr>
<td>1 MB</td>
<td>~150 TB</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>State budget is the first design decision.</strong> With hundreds of bytes to a few KB per series you can hold all 150M detectors in ~100 GB–600 GB of distributed memory; anything larger (e.g., a per-series deep network) becomes infeasible at this count.</li>
<li><strong>Prefer O(1) closed-form updates</strong> (EWMA, seasonal coefficients, EVT quantile updates) so per-point cost is essentially constant and CPU-throughput-bound, not learning-bound.</li>
<li><strong>Two-stage filtering to keep compute bounded:</strong> run the cheap statistical detector on <em>every</em> point of every series; escalate to the heavier shared model (Tier 1) only on a window flagged as suspicious. This decouples the 150M-scale "always-on" cost from the expensive-model cost.</li>
<li><strong>Tuning at scale is not manual.</strong> 150M series can't be individually tuned by hand; the Tier-1 global model should <em>generate</em> per-series settings (meta-learning / fast model recommendation), with online updates refining them (Source: <a href="https://proceedings.mlr.press/v224/navarro23a.html" rel="noopener noreferrer">Meta-Learning for Fast Model Recommendation</a>).</li>
<li><strong>Where it runs with InfluxDB:</strong> InfluxDB's stack is batch/stream-oriented; <strong>Kapacitor</strong> is InfluxData's streaming engine with an <code>alert</code> node and <strong>User-Defined Functions (UDFs)</strong> for custom anomaly algorithms applied to incoming points — a natural host for the online per-series scorer if it must stay inside the Influx ecosystem. (Source: <a href="https://docs.influxdata.com/kapacitor/v1/" rel="noopener noreferrer">Kapacitor docs</a>.) Alternatively run a stream processor (Flink/RisingWave/etc.) that reads new points from InfluxDB, updates per-series state, and writes alerts back.</li>
</ul>
<hr>
<h2>6. Options matrix (complexity → expressiveness)</h2>
<table>
<thead>
<tr>
<th>Approach</th>
<th>Per-series state</th>
<th>Storage</th>
<th>Compute</th>
<th>Generalization</th>
<th>Best for</th>
</tr>
</thead>
<tbody>
<tr>
<td>Online stats + adaptive threshold (EWMA/seasonal + SPOT/POT)</td>
<td>tiny (bytes–KB)</td>
<td>none (raw)</td>
<td>O(1)/point</td>
<td>low (per-series params)</td>
<td>150M point-anomaly detection, cheapest</td>
</tr>
<tr>
<td>Shared autoencoder/TSFM encoder + online detector on residuals</td>
<td>small head + pretrained encoder</td>
<td>none (raw)</td>
<td>encoder is the cost</td>
<td>high (shared repr.)</td>
<td>generalizing "normal shape" across series</td>
</tr>
<tr>
<td>Foundation model + per-series LoRA/PEFT adapter</td>
<td>adapter (KBs) per series</td>
<td>accum. adapters</td>
<td>moderate–high</td>
<td>very high</td>
<td>best fidelity, but 150M adapters accumulate</td>
</tr>
<tr>
<td>Global meta-learner / hypernetwork emitting per-series params</td>
<td>tiny, params predicted</td>
<td>none (raw)</td>
<td>inference</td>
<td>high</td>
<td>automated per-series tuning at scale</td>
</tr>
</tbody>
</table>
<p>(Adapters/PEFT context: TimesFM ships a LoRA fine-tuning example — <a href="https://github.com/google-research/timesfm/tree/master/timesfm-forecasting/examples/finetuning" rel="noopener noreferrer">timesfm finetuning dir</a>; PEFT discussion for TSFMs — <a href="https://tsfm.ai/blog/lora-peft-time-series-foundation-models" rel="noopener noreferrer">tsfm.ai blog</a>.)</p>
<hr>
<h2>7. Recommendations (pragmatic path)</h2>
<ol>
<li><strong>Reframe the goal as reconstruction/forecast </strong>residual<strong> + adaptive threshold</strong>, not "a foundation model that detects anomalies." Accuracy comes from the residual stream and a good dynamic threshold.</li>
<li><strong>Use the kick-start to train one shared representation / meta-prior</strong> over the 150M series (a TSFM or autoencoder as an encoder, or a meta-learner). This is the only place full data is needed.</li>
<li><strong>Deploy a tiny online per-series detector</strong> (online stats + EVT adaptive threshold) with <strong>bounded in-memory state only</strong> — no raw-series retention. This satisfies "evolves with new data" and "no data stored."</li>
<li><strong>Buy down scale risk with the tiered/filter design</strong> so only suspicious windows hit the expensive shared model.</li>
<li><strong>Validate on a representative stratified sample</strong> of tens–hundreds of series — you can never hand-inspect 150M — and use that sample to set Tier-1 hyperparameters and the meta-tuning objective.</li>
<li><strong>Run it as a stream update</strong> (Kapacitor UDF or a stream processor) integrated with InfluxDB, rather than offline batch retraining.</li>
</ol>
<hr>
<h2>8. Caveats on evidence</h2>
<ul>
<li>The strongest claims (One-Liners; arXiv 2412.19286) are <strong>preprint / in-review</strong> sources; the vendor-documented workflows (MOMENT tutorial, BigQuery/TimesFM) present usage examples, not independent benchmark wins. Treat "foundation models beat baselines at AD" as <strong>not established</strong>; treat "foundation models are useful as feature extractors + after adaptation" as the safer claim.</li>
<li>Most comparison studies focus on <strong>zero-shot</strong>; <em>fine-tuned/adapted</em> TSFMs are consistently the more favorable regime — consistent with the two-tier recommendation.</li>
<li>Exact end-to-end systems <em>at 150M series, online, with no retention</em> were <strong>not</strong> found in the literature as a single turnkey product; the design above is assembled from the best-supported building blocks rather than one proven system.</li>
</ul>
<hr>
<h2>References</h2>
<ul>
<li>One-Liners (ICLR 2026): https://openreview.net/pdf?id=H27kvyG4qf · bench https://github.com/necdetduruk/tsfm-anomaly-bench</li>
<li>Critical TSFM-AD evaluation: https://arxiv.org/html/2412.19286v1</li>
<li>MOMENT: https://github.com/moment-timeseries-foundation-model/moment / https://arxiv.org/abs/2402.03885</li>
<li>TimesFM: https://github.com/google-research/timesfm · Chronos: https://github.com/amazon-science/chronos-forecasting / https://doi.org/10.48550/arxiv.2403.07815</li>
<li>ChronosAD (TSFMs as feature extractors): https://arxiv.org/html/2606.01300v1</li>
<li>iADCPS (incremental meta-learning, online update, dynamic threshold): https://arxiv.org/abs/2504.04374</li>
<li>Meta-Learning for Fast Model Recommendation: https://proceedings.mlr.press/v224/navarro23a.html</li>
<li>SPOT / Extreme Value Theory streaming AD: https://asiffer.github.io/libspot/ · KDD17: https://www.kdd.org/kdd2017/papers/view/anomaly-detection-in-streams-with-extreme-value-theory</li>
<li>AnEWMA: https://www.scitepress.org/Papers/2025/134378/134378.pdf</li>
<li>Numenta HTM (continuous online learning): https://www.numenta.com/resources/research-publications/papers/unsupervised-real-time-anomaly-detection-for-streaming-data/ · NAB: https://github.com/numenta/nab / https://arxiv.org/pdf/1510.03336</li>
<li>Streaming AD libraries: ABERRANT https://github.com/OliverHennhoefer/aberrant · StreamAD https://github.com/Fengrui-Liu/StreamAD</li>
<li>Continual/incremental AD (forgetting/drift): https://arxiv.org/abs/2201.06763 · https://arxiv.org/html/2412.03907v2 · https://doi.org/10.48550/arxiv.2511.08634</li>
<li>InfluxDB/Kapacitor (InfluxData streaming engine, alert + UDFs): https://docs.influxdata.com/kapacitor/v1/</li>
</ul>]]></content:encoded>
</item>
<item>
  <title>Ralph without Docker: opencode &amp; pi coding agent (Linux + Windows)</title>
  <link>http://ustunkok.com.tr/posts/ralph-without-docker-opencode-pi-coding-agent-linux-windows</link>
  <description>Ralph is a technique for running AI coding agents in a loop: you run the same prompt repeatedly, the AI picks its own tasks from a PRD, commits after each feature, and you come back later to working code.</description>
  <pubDate>Sat, 01 Aug 2026 18:41:21 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/ralph-without-docker-opencode-pi-coding-agent-linux-windows</guid>
  <content:encoded><![CDATA[<blockquote>
<p>Adapted from <a href="https://www.aihero.dev/getting-started-with-ralph" rel="noopener noreferrer">Getting Started with Ralph</a> (AI Hero).
The original uses Claude Code + Docker Desktop on Linux. This version swaps in two open-source
agents — <a href="https://opencode.ai" rel="noopener noreferrer">opencode</a> and <a href="https://pi.dev" rel="noopener noreferrer">pi coding agent</a> — drops Docker
entirely, and covers Linux <strong>and</strong> Windows. Shared concepts appear once; each OS/agent combo gets
its own section with only what's different.</p>
</blockquote>
<h2>What is Ralph?</h2>
<p>Ralph is a technique for running AI coding agents in a loop: you run the same prompt repeatedly,
the AI picks its own tasks from a PRD, commits after each feature, and you come back later to
working code. The loop stays the same no matter which agent or OS you use:</p>
<table>
<thead>
<tr>
<th>Piece</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>PRD.md</code></td>
<td>Defines the end state — a checklist, list of tasks, or prose the agent can pull individual tasks from</td>
</tr>
<tr>
<td><code>progress.txt</code></td>
<td>Tracks what's done between runs</td>
</tr>
<tr>
<td>One prompt</td>
<td>"Find the next task, implement it, commit" — the loop body</td>
</tr>
<tr>
<td>Completion sigil</td>
<td><code>&lt;promise&gt;COMPLETE&lt;/promise&gt;</code> — printed when the PRD is finished so the loop can stop</td>
</tr>
</tbody>
</table>
<blockquote>
<p>For tips on task sizing, prioritization, and feedback loops, see the
<a href="https://www.aihero.dev/tips-for-ai-coding-with-ralph-wiggum" rel="noopener noreferrer">11 tips for AI coding with Ralph</a>.</p>
</blockquote>
<h2>What changes without Docker</h2>
<p>Docker Desktop sandboxes gave you three things you now own yourself:</p>
<ol>
<li><strong>No sandbox.</strong> <code>docker sandbox run claude</code> isolated the agent. opencode and pi run directly
   with <em>your</em> user's permissions — they can install packages, run servers, and touch any file you
   can. Start in a disposable VM or a scratch folder, run the once-script a few times first, and
   review commits before going fully AFK.</li>
<li><strong>Git identity is on you.</strong> Sandboxes auto-injected git config for commit attribution. Without
   Docker, set it once:
   <pre class="highlight"><code class="language-bash">git config --global user.name "You"
git config --global user.email "you@example.com"</code></pre></li>
<li><strong>Credentials are yours to manage.</strong> No Docker volume — each agent stores auth in its own config
   directory. For scripted (headless) runs, prefer exporting a provider API key in your shell.</li>
</ol>
<h2>Step 1 — Write the PRD (identical for all four combos)</h2>
<p>Ask the agent for a plan, iterate until you're happy, then save it as <code>PRD.md</code>:</p>
<ul>
<li><strong>opencode:</strong> the TUI has a <strong>plan</strong> mode — press <code>Tab</code> to switch modes, iterate, then tell it to save the plan to <code>PRD.md</code>.</li>
<li><strong>pi:</strong> no built-in plan mode (by design). Ask pi interactively to draft a plan, iterate in chat, then have it write <code>PRD.md</code>.</li>
</ul>
<p>Create the empty progress file:</p>
<pre class="highlight"><code class="language-bash">touch progress.txt</code></pre>
<p>The PRD can be any format (markdown checklist, JSON, prose). What matters: clear scope, and tasks
the agent can pull out one at a time.</p>
<h2>Step 2 — Install &amp; authenticate (pick your combo)</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Combo</th>
<th>Install</th>
<th>Auth</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>Linux + opencode</td>
<td><code>curl -fsSL https://opencode.ai/install \| bash</code> or <code>npm install -g opencode-ai</code></td>
<td><code>opencode</code> → <code>/connect</code> → pick provider, <strong>or</strong> <code>export ANTHROPIC_API_KEY=...</code></td>
</tr>
<tr>
<td>B</td>
<td>Linux + pi</td>
<td><code>npm install -g --ignore-scripts @earendil-works/pi-coding-agent</code> (or <code>curl -fsSL https://pi.dev/install.sh \| sh</code>)</td>
<td><code>pi</code> → <code>/login</code> → pick provider, <strong>or</strong> <code>export ANTHROPIC_API_KEY=...</code></td>
</tr>
<tr>
<td>C</td>
<td>Windows + opencode</td>
<td><code>scoop install opencode</code> or <code>choco install opencode</code> (Node optional: <code>npm i -g opencode-ai</code>)</td>
<td><code>opencode</code> → <code>/connect</code>, <strong>or</strong> set <code>ANTHROPIC_API_KEY</code> env var</td>
</tr>
<tr>
<td>D</td>
<td>Windows + pi</td>
<td><code>npm install -g --ignore-scripts @earendil-works/pi-coding-agent</code> (needs Node.js) <strong>+ <a href="https://git-scm.com/download/win" rel="noopener noreferrer">Git for Windows</a></strong> — pi requires a bash shell</td>
<td><code>pi</code> → <code>/login</code>, <strong>or</strong> <code>export ANTHROPIC_API_KEY=...</code> in Git Bash</td>
</tr>
</tbody>
</table>
<p>Auth done in the TUI persists for later headless runs; an exported API key works everywhere
including scripts.</p>
<hr>
<h2>A. Linux + opencode (no Docker)</h2>
<p><strong>Human-in-the-loop run</strong> — <code>ralph-once.sh</code> (watch it, run it again):</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
opencode run -p --auto "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."</code></pre>
<pre class="highlight"><code class="language-bash">chmod +x ralph-once.sh
./ralph-once.sh</code></pre>
<ul>
<li><code>--auto</code> auto-approves permission requests so the loop never stalls (omit it for a stricter run).</li>
<li><code>-p</code>/<code>--print</code> formats output cleanly; <code>@file</code> attaches files to the prompt.</li>
</ul>
<p><strong>AFK loop</strong> — <code>afk-ralph.sh</code> (run with a cap: <code>./afk-ralph.sh 20</code>):</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 &lt;iterations&gt;"
  exit 1
fi
for ((i=1; i&lt;=$1; i++)); do
  result=$(opencode run -p --auto "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output &lt;promise&gt;COMPLETE&lt;/promise&gt;.")
  echo "$result"
  if [[ "$result" == *"&lt;promise&gt;COMPLETE&lt;/promise&gt;"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done</code></pre>
<p><code>set -e</code> exits on errors, <code>$1</code> caps iterations (runaway-cost protection), and the sigil check
stops the loop early when the PRD is done.</p>
<hr>
<h2>B. Linux + pi coding agent (no Docker)</h2>
<p><strong>Human-in-the-loop run</strong> — <code>ralph-once.sh</code>:</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
pi -p "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."</code></pre>
<pre class="highlight"><code class="language-bash">chmod +x ralph-once.sh
./ralph-once.sh</code></pre>
<ul>
<li>pi has <strong>no permission popups</strong> by design — tool calls just execute. <code>-p</code> is print (headless)
  mode; <code>@file</code> attaches files. Use <code>--tools read,write,edit,bash</code> (the default set) or a narrower
  allowlist if you want extra safety without a sandbox.</li>
</ul>
<p><strong>AFK loop</strong> — <code>afk-ralph.sh</code>:</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 &lt;iterations&gt;"
  exit 1
fi
for ((i=1; i&lt;=$1; i++)); do
  result=$(pi -p "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output &lt;promise&gt;COMPLETE&lt;/promise&gt;.")
  echo "$result"
  if [[ "$result" == *"&lt;promise&gt;COMPLETE&lt;/promise&gt;"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done</code></pre>
<hr>
<h2>C. Windows + opencode (no Docker)</h2>
<p>Runs fine from PowerShell (scripts below) or cmd. Install with <code>scoop install opencode</code>
or <code>choco install opencode</code>, run <code>opencode</code> once, <code>/connect</code>, and pick a provider.</p>
<p><strong>Human-in-the-loop run</strong> — <code>ralph-once.ps1</code>:</p>
<pre class="highlight"><code class="language-powershell"># Run once, watch it, run again.
opencode run -p --auto "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."</code></pre>
<pre class="highlight"><code class="language-powershell">Set-ExecutionPolicy -Scope Process Bypass   # if scripts are blocked
.\ralph-once.ps1</code></pre>
<p><strong>AFK loop</strong> — <code>afk-ralph.ps1</code> (run with <code>.\afk-ralph.ps1 20</code>):</p>
<pre class="highlight"><code class="language-powershell">param([int]$Iterations)
if (-not $Iterations) { Write-Host "Usage: .\afk-ralph.ps1 &lt;iterations&gt;"; exit 1 }

for ($i = 1; $i -le $Iterations; $i++) {
  $result = opencode run -p --auto "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output &lt;promise&gt;COMPLETE&lt;/promise&gt;."
  Write-Output $result
  if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
  if ($result -match "&lt;promise&gt;COMPLETE&lt;/promise&gt;") {
    Write-Host "PRD complete after $i iterations."
    exit 0
  }
}</code></pre>
<p><code>$result</code> collects opencode's stdout, <code>$LASTEXITCODE</code> propagates failures, and <code>-match</code> detects
the completion sigil.</p>
<hr>
<h2>D. Windows + pi coding agent (no Docker)</h2>
<p>pi requires a <strong>bash shell on Windows</strong> — install <a href="https://git-scm.com/download/win" rel="noopener noreferrer">Git for Windows</a>
(pi auto-detects <code>C:\Program Files\Git\bin\bash.exe</code>). Everything below is bash run from a
<strong>Git Bash</strong> terminal. Install pi, then authenticate (<code>pi</code> → <code>/login</code>, or export <code>ANTHROPIC_API_KEY</code>
in the Git Bash session).</p>
<p><strong>Human-in-the-loop run</strong> — <code>ralph-once.sh</code> (in Git Bash):</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
pi -p "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."</code></pre>
<pre class="highlight"><code class="language-bash">chmod +x ralph-once.sh
./ralph-once.sh</code></pre>
<p><strong>AFK loop</strong> — <code>afk-ralph.sh</code>:</p>
<pre class="highlight"><code class="language-bash">#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 &lt;iterations&gt;"
  exit 1
fi
for ((i=1; i&lt;=$1; i++)); do
  result=$(pi -p "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output &lt;promise&gt;COMPLETE&lt;/promise&gt;.")
  echo "$result"
  if [[ "$result" == *"&lt;promise&gt;COMPLETE&lt;/promise&gt;"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done</code></pre>
<p>Same as the Linux+pi variant — the only difference is <em>where</em> the shell comes from (Git Bash),
so these files work verbatim on both. If pi ever says it can't find a shell, point it at Git Bash
via <code>shellPath</code> in <code>~/.pi/agent/settings.json</code>:</p>
<pre class="highlight"><code class="language-json">{ "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe" }</code></pre>
<hr>
<h2>Customizing the loop</h2>
<p>Ralph is just a loop, so it's endlessly swappable:</p>
<ul>
<li><strong>Swap the task source.</strong> Instead of a local PRD, pull from GitHub Issues, Linear, or
  <a href="https://github.com/steveyegge/beads" rel="noopener noreferrer">beads</a> — the agent still picks what to work on.</li>
<li><strong>Change the output.</strong> Instead of committing to main, create a branch + PR per iteration to
  triage a backlog.</li>
<li><strong>Different loop types:</strong> test coverage (write tests until coverage hits target), linting
  (fix errors one by one), duplication (refactor <code>jscpd</code> clones), or entropy (clean up code smells).</li>
<li><strong>Per-agent extras:</strong> pi can load skills/extensions that gate tools or checkpoint git commits;
  opencode supports custom agent modes and permissions config. Both work fine inside the same loop.</li>
</ul>
<p><em>Original article: <a href="https://www.aihero.dev/getting-started-with-ralph" rel="noopener noreferrer">Getting Started with Ralph</a> ·
Tips: <a href="https://www.aihero.dev/tips-for-ai-coding-with-ralph-wiggum" rel="noopener noreferrer">11 tips for AI coding with Ralph</a></em></p>]]></content:encoded>
</item>
<item>
  <title>AIOps on Observability and Recent Trends: A Literature Review</title>
  <link>http://ustunkok.com.tr/posts/aiops-on-observability-and-recent-trends-a-literature-review</link>
  <description>AIOps (&quot;Artificial Intelligence for IT Operations&quot;) is the application of machine learning and, increasingly, large language models (LLMs) to observability telemetry — metrics, logs, traces, and events — in order to detect anomalies, reduce alert noise, correlate signals, and localize root causes faster than manual operation sallow. This note surveys the principal method families for anomaly detection, clustering and correlation, and root-cause analysis (RCA), then traces developments from 2021–2025:transformer and foundation models for time series, LLM-based log/telemetry analysis,eBPF-native instrumentation, and the consolidation of OpenTelemetry as the vendor-neutral standard. Each substantive technical claim is tied to a primary source (arXiv ID/DOI orofficial docs). Where a claim could not be verified against a primary source, it is flagged explicitly in the text.</description>
  <pubDate>Mon, 13 Jul 2026 11:37:14 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/aiops-on-observability-and-recent-trends-a-literature-review</guid>
  <content:encoded><![CDATA[<h2>1. Context and Definition</h2>
<p><strong>Observability</strong> is the property of a system whose internal state can be inferred from its external outputs. In modern distributed/microservice systems these outputs are commonly grouped into the "three pillars" — <strong>metrics</strong> (numeric time series such as CPU, latency,request rate), <strong>logs</strong> (semi-structured text events), and <strong>traces</strong> (causal request paths across services) — with <strong>events</strong> (deployments, config changes, alerts) as afourth, cross-cutting signal. The OpenTelemetry specification defines these signal typesand their data models directly (<a href="https://opentelemetry.io/docs/" rel="noopener noreferrer">OpenTelemetry docs</a>).</p>
<p><strong>AIOps</strong>, a term popularized by Gartner (industry analyst, not a primary technical source — flagged), refers to platforms that apply analytics and ML to operations data to automate detection, correlation, and remediation. The practical driver for applying ML at scale is volume and velocity: cloud-native systems emit telemetry at cardinalities and rates that exceed human triage capacity, and static thresholds generalize poorly across seasonal, multi-tenant, and rapidly-deploying workloads. The AIOps problem is therefore dominated by <strong>unsupervised / weakly-supervised</strong> learning, because ground-truth incident labels are scarce, delayed, and noisy.</p>
<hr>
<h2>2. Anomaly Detection Methods</h2>
<h3>2.1 Statistical / classical</h3>
<p>The oldest and still widely deployed family models the "normal" signal explicitly and
flags deviations.</p>
<ul>
<li><strong>Moving averages / EWMA</strong>: an exponentially weighted mean <span class="arithmatex">\(\hat{x}_t = \alpha x_t + (1-\alpha)\hat{x}_{t-1}\)</span> with residual thresholding.</li>
<li><strong>Holt-Winters</strong> triple exponential smoothing captures level, trend, and seasonality; it underpins many production forecasters (e.g., historically in RRDtool/Graphite).</li>
<li><strong>ARIMA</strong> (<span class="arithmatex">\(ARIMA(p,d,q)\)</span>) models autocorrelation of a differenced series; anomalies are points with large forecast residuals.</li>
<li><strong>Seasonal decomposition</strong> (classical and <strong>STL</strong>, Cleveland et al., 1990, <em>J. Official Statistics</em>) separates <span class="arithmatex">\(x_t = T_t + S_t + R_t\)</span>; anomalies are outliers in the remainder <span class="arithmatex">\(R_t\)</span>. Twitter's <code>AnomalyDetection</code> package built on STL + generalized ESD is a well-known open-source instance (repo, not peer-reviewed — flagged).</li>
<li><strong>3-sigma / MAD</strong>: flag points beyond <span class="arithmatex">\(\mu \pm 3\sigma\)</span>, or robustly beyond a Median Absolute Deviation multiple.</li>
</ul>
<p>These methods are cheap, interpretable, and strong baselines; they struggle with multivariate dependence and non-stationary regime changes.</p>
<h3>2.2 Traditional ML</h3>
<ul>
<li><strong>Isolation Forest</strong> (Liu, Ting, Zhou, ICDM 2008, <a href="https://doi.org/10.1109/ICDM.2008.17" rel="noopener noreferrer">DOI:10.1109/ICDM.2008.17</a>) isolates anomalies via random partitioning; anomalies require fewer splits (shorter path length).</li>
<li><strong>One-Class SVM</strong> (Schölkopf et al., 2001, <em>Neural Computation</em>, <a href="https://doi.org/10.1162/089976601750264965" rel="noopener noreferrer">DOI:10.1162/089976601750264965</a>) learns a boundary enclosing normal data in a kernel feature space.</li>
<li><strong>Clustering-based outlier detection</strong> with <strong>k-means</strong> or <strong>DBSCAN</strong> (Ester et al., KDD 1996) flags points far from any dense cluster; <strong>LOF</strong> (Breunig et al., SIGMOD 2000, <a href="https://doi.org/10.1145/342009.335388" rel="noopener noreferrer">DOI:10.1145/342009.335388</a>) scores local density deviation.</li>
</ul>
<h3>2.3 Deep learning</h3>
<ul>
<li><strong>LSTM/GRU</strong> forecasting + residual thresholding for sequences; the LSTM approach to system-log anomaly detection is exemplified by <strong>DeepLog</strong> (see §2.5).</li>
<li><strong>Autoencoders / VAE</strong>: reconstruction error as anomaly score. <strong>OmniAnomaly</strong> (Su et al., KDD 2019, <a href="https://doi.org/10.1145/3292500.3330672" rel="noopener noreferrer">DOI:10.1145/3292500.3330672</a>) uses a stochastic recurrent VAE for multivariate metrics and popularized the SMD/SMAP/MSL benchmarks.</li>
<li><strong>CNN for time series</strong> (dilated/temporal convolutions) and <strong>Seq2Seq</strong> encoder–decoder models for forecasting-based detection.</li>
<li><strong>LSTM-VAE</strong> and GAN-based detectors (e.g., <strong>MAD-GAN</strong>, Li et al., 2019) extend this reconstruction paradigm.</li>
</ul>
<h3>2.4 Modern / SOTA (2021–2025)</h3>
<p>Transformers dominate long-horizon multivariate forecasting and, adapted, anomaly detection:</p>
<ul>
<li><strong>Informer</strong> (Zhou et al., AAAI 2021, <a href="https://arxiv.org/abs/2012.07436" rel="noopener noreferrer">arXiv:2012.07436</a>) — ProbSparse attention for long-sequence forecasting. <em>(verified)</em></li>
<li><strong>Autoformer</strong> (Wu et al., NeurIPS 2021, <a href="https://arxiv.org/abs/2106.13008" rel="noopener noreferrer">arXiv:2106.13008</a>) — decomposition + Auto-Correlation. <em>(verified)</em></li>
<li><strong>PatchTST</strong> (Nie et al., ICLR 2023, <a href="https://arxiv.org/abs/2211.14730" rel="noopener noreferrer">arXiv:2211.14730</a>) — patching + channel independence ("a time series is worth 64 words"). <em>(verified)</em></li>
<li><strong>TimesNet</strong> (Wu et al., ICLR 2023, <a href="https://arxiv.org/abs/2210.02186" rel="noopener noreferrer">arXiv:2210.02186</a>) — reshapes 1D series into 2D by periodicity for general analysis incl. anomaly detection. <em>(verified)</em></li>
<li><strong>Anomaly Transformer</strong> (Xu et al., ICLR 2022, <a href="https://arxiv.org/abs/2110.02642" rel="noopener noreferrer">arXiv:2110.02642</a>) — association-discrepancy criterion. <em>(verified)</em></li>
<li><strong>TranAD</strong> (Tuli et al., VLDB 2022, <a href="https://arxiv.org/abs/2201.07284" rel="noopener noreferrer">arXiv:2201.07284</a>) — deep transformer with adversarial training for multivariate anomaly detection. <em>(verified)</em></li>
<li><strong>Diffusion / LLM-based</strong>: diffusion models and reprogrammed LLMs are emerging for forecasting/imputation (see §5 foundation models).</li>
<li><strong>Graph neural networks</strong> for multivariate metrics model inter-series dependency; <strong>GDN</strong> (Deng &amp; Hooi, AAAI 2021, <a href="https://arxiv.org/abs/2106.06947" rel="noopener noreferrer">arXiv:2106.06947</a>) learns a graph over sensors and flags edge-deviation. <strong>MTAD-GAT</strong> (Zhao et al., ICDM 2020) uses dual graph-attention.</li>
</ul>
<blockquote>
<p><strong>Caveat on transformer AD benchmarks.</strong> Several works (e.g., "revisiting time-series anomaly detection" critiques, 2022–2023) argue that popular point-adjustment evaluation inflates scores; comparative rankings should be read with this in mind. I have not re-verified individual leaderboard numbers here.</p>
</blockquote>
<h3>2.5 Unsupervised log anomaly detection</h3>
<ul>
<li><strong>Drain</strong> (He et al., ICWS 2017, <a href="https://doi.org/10.1109/ICWS.2017.13" rel="noopener noreferrer">DOI:10.1109/ICWS.2017.13</a>) — fixed-depth parse tree for online log-template extraction. <em>(Venue ICWS 2017 verified via Crossref.)</em></li>
<li><strong>DeepLog</strong> (Du et al., CCS 2017, <a href="https://doi.org/10.1145/3133956.3134015" rel="noopener noreferrer">DOI:10.1145/3133956.3134015</a>) — LSTM over log-key sequences; predicts next key and flags surprises.</li>
<li><strong>LogAnomaly</strong> (Meng et al., IJCAI 2019, <a href="https://doi.org/10.24963/ijcai.2019/658" rel="noopener noreferrer">DOI:10.24963/ijcai.2019/658</a>) — template2vec semantic embeddings + sequential + quantitative modeling.</li>
<li><strong>LogRobust</strong> (Zhang et al., ESEC/FSE 2019, <a href="https://doi.org/10.1145/3338906.3338931" rel="noopener noreferrer">DOI:10.1145/3338906.3338931</a>) — attention-BiLSTM robust to log instability/evolution.</li>
<li><strong>Log-template clustering</strong> (LogCluster, LKE) groups templates to reduce dimensionality before detection.</li>
</ul>
<p><strong>Comparison table.</strong></p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Family</th>
<th>Signal</th>
<th>Supervision</th>
<th>Primary citation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Holt-Winters / ARIMA</td>
<td>Statistical</td>
<td>Metrics</td>
<td>Unsup.</td>
<td>Cleveland et al. 1990 (STL); Box–Jenkins</td>
</tr>
<tr>
<td>Isolation Forest</td>
<td>Traditional ML</td>
<td>Metrics</td>
<td>Unsup.</td>
<td>Liu et al. ICDM 2008</td>
</tr>
<tr>
<td>One-Class SVM</td>
<td>Traditional ML</td>
<td>Metrics</td>
<td>Semi</td>
<td>Schölkopf et al. 2001</td>
</tr>
<tr>
<td>OmniAnomaly (VAE)</td>
<td>Deep</td>
<td>Multivariate</td>
<td>Unsup.</td>
<td>Su et al. KDD 2019</td>
</tr>
<tr>
<td>Informer/Autoformer/PatchTST</td>
<td>Deep (Transformer)</td>
<td>Metrics</td>
<td>Self/Unsup.</td>
<td>2012.07436 / 2106.13008 / 2211.14730</td>
</tr>
<tr>
<td>Anomaly Transformer</td>
<td>Deep (Transformer)</td>
<td>Multivariate</td>
<td>Unsup.</td>
<td>Xu et al. ICLR 2022</td>
</tr>
<tr>
<td>TranAD</td>
<td>Deep (Transformer)</td>
<td>Multivariate</td>
<td>Unsup.</td>
<td>Tuli et al. VLDB 2022</td>
</tr>
<tr>
<td>GDN / MTAD-GAT</td>
<td>GNN</td>
<td>Multivariate</td>
<td>Unsup.</td>
<td>Deng &amp; Hooi 2021</td>
</tr>
<tr>
<td>DeepLog</td>
<td>Deep (LSTM)</td>
<td>Logs</td>
<td>Unsup.</td>
<td>Du et al. CCS 2017</td>
</tr>
<tr>
<td>LogAnomaly / LogRobust</td>
<td>Deep</td>
<td>Logs</td>
<td>Semi/Sup.</td>
<td>IJCAI 2019 / FSE 2019</td>
</tr>
</tbody>
</table>
<hr>
<h2>3. Clustering and Signal Correlation</h2>
<p>Clustering serves two operational goals: <strong>compression</strong> (turn millions of log lines into a few hundred templates) and <strong>noise reduction</strong> (collapse redundant alerts).</p>
<ul>
<li><strong>Log clustering</strong>: Drain (parse-tree), <strong>LogCluster</strong> (Lin et al., ICSE 2016, <a href="https://doi.org/10.1145/2889160.2889232" rel="noopener noreferrer">DOI:10.1145/2889160.2889232</a>) clusters logs to identify problems; <strong>Spell</strong> (Du &amp; Li, ICDM 2016) uses longest-common-subsequence parsing.</li>
<li><strong>Metric clustering</strong>: grouping correlated time series (via correlation/DTW distance) identifies redundant signals and shared failure modes.</li>
<li><strong>Event correlation &amp; alert aggregation</strong>: temporal + topological correlation groups alerts into incidents, reducing "alert storms." Much of this is vendor-implemented; primary technical treatments appear in AIOps-challenge literature rather than product docs.</li>
<li><strong>Trace/span clustering</strong>: clustering trace structures/latency profiles surfaces anomalous request paths in microservice systems.</li>
<li><strong>Incident clustering</strong> — grouping alerts believed to share a root cause — is a bridge to
RCA: a well-formed cluster localizes <em>where</em> to look before <em>why</em> is determined.</li>
</ul>
<hr>
<h2>4. Root Cause Analysis and Fault Localization</h2>
<ul>
<li><strong>Spectrum-based fault localization (SBFL)</strong> ranks components by suspiciousness from pass/fail execution spectra (e.g., Ochiai, Tarantula) — mature in software testing, adapted to services.</li>
<li><strong>Causal inference / causal graphs</strong>: learn a causal DAG over metrics/services (e.g., PC/Granger-based) and trace anomaly propagation. <strong>CloudRanger</strong> (Wang et al., CCGrid 2018, <a href="https://doi.org/10.1109/CCGRID.2018.00076" rel="noopener noreferrer">DOI:10.1109/CCGRID.2018.00076</a>) builds an impact graph for cloud-native RCA.</li>
<li><strong>Microservice dependency graphs</strong>: <strong>MicroRCA</strong> (Wu et al., NOMS 2020, <a href="https://doi.org/10.1109/NOMS47738.2020.9110353" rel="noopener noreferrer">DOI:10.1109/NOMS47738.2020.9110353</a>) localizes anomalous services on an attributed service graph.</li>
<li><strong>GNN-based RCA</strong>: graph neural nets over service/topology graphs propagate anomaly evidence to rank likely culprits.</li>
<li><strong>LLM-assisted RCA</strong>: recent work uses LLMs to summarize evidence, hypothesize causes, and draft mitigations. <strong>RCACopilot</strong> (Chen et al., 2023, <a href="https://arxiv.org/abs/2305.15778" rel="noopener noreferrer">arXiv:2305.15778</a> — <em>ID verified: "Automatic Root Cause Analysis via Large Language Models for Cloud Incidents"</em>) and Microsoft studies on LLMs for incident RCA are representative. Treat efficacy claims cautiously: reported gains depend heavily on retrieval quality and evaluation setup.</li>
</ul>
<hr>
<h2>5. Recent Trends (2023–2025)</h2>
<ul>
<li><strong>LLM / LLM-agent observability.</strong> Domain LLMs and agents parse logs, answer natural-language queries over telemetry, and drive investigation loops. <strong>OWL: A Large Language Model for IT Operations</strong> (Guo et al., 2023, <a href="https://arxiv.org/abs/2309.09298" rel="noopener noreferrer">arXiv:2309.09298</a>) <em>(verified)</em> is an explicit ops-domain LLM with an Ops benchmark. "Observability copilots" are largely commercial (Datadog Bits AI, Grafana/Elastic AI assistants) — product docs, not peer-reviewed.</li>
<li><strong>Foundation / self-supervised models for time series.</strong> Zero-shot forecasters: <strong>TimesFM</strong> (decoder-only foundation model, Das et al., 2023, <a href="https://arxiv.org/abs/2310.10688" rel="noopener noreferrer">arXiv:2310.10688</a>) <em>(verified)</em>, <strong>TimeGPT-1</strong> (Garza et al., 2023, <a href="https://arxiv.org/abs/2310.03589" rel="noopener noreferrer">arXiv:2310.03589</a>) <em>(verified)</em>, and LLM-reprogramming via <strong>Time-LLM</strong> (Jin et al., ICLR 2024, <a href="https://arxiv.org/abs/2310.01728" rel="noopener noreferrer">arXiv:2310.01728</a>) <em>(verified)</em>. These promise few/zero-shot deployment across heterogeneous metrics.</li>
<li><strong>Generative AI for synthetic telemetry</strong>: using generative models to synthesize logs/ traces for augmentation and rare-fault simulation — active but still emerging; strong peer-reviewed baselines are sparse (flagged as low-verification).</li>
<li><strong>eBPF-based observability</strong>: kernel-level, low-overhead instrumentation (Cilium/Hubble, Pixie, Parca) enables auto-generated metrics/traces without code changes. Primary sources are the projects' docs/kernel docs rather than papers.</li>
<li><strong>OpenTelemetry standardization</strong>: OTel (CNCF) is now the de facto vendor-neutral instrumentation and semantic-conventions standard, unifying the pillars (<a href="https://opentelemetry.io/docs/" rel="noopener noreferrer">opentelemetry.io</a>) — a primary spec source.</li>
<li><strong>Causality-driven AIOps</strong>: shift from correlation to intervention/causal models for RCA.</li>
<li><strong>Benchmarks &amp; datasets</strong>:</li>
<li><strong>LogHub</strong> (He et al., collection of system-log datasets; <a href="https://arxiv.org/abs/2008.06448" rel="noopener noreferrer">arXiv:2008.06448</a>).</li>
<li><strong>NAB</strong> — Numenta Anomaly Benchmark (Lavin &amp; Ahmad, 2015, <a href="https://arxiv.org/abs/1510.03336" rel="noopener noreferrer">arXiv:1510.03336</a>).</li>
<li><strong>TSB-AD</strong> — recent reproducible TS-anomaly benchmark (VLDB 2024/2025; associated   reproducibility paper indexed on arXiv — <em>exact ID not cleanly verified in this pass,   flagged</em>).</li>
<li><strong>GAIA</strong> dataset and <strong>AIOps Challenge</strong> datasets (KPI/multi-source) from the AIOps   community — dataset repos, not peer-reviewed papers.</li>
</ul>
<hr>
<h2>6. Production Tooling and Ecosystem</h2>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Role</th>
<th>Primary-source docs</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Prometheus</strong></td>
<td>Metrics TSDB + alerting</td>
<td><a href="https://prometheus.io/docs/" rel="noopener noreferrer">prometheus.io/docs</a> ✅ primary</td>
</tr>
<tr>
<td><strong>Grafana</strong></td>
<td>Visualization, alerting, ML plugins</td>
<td><a href="https://grafana.com/docs/" rel="noopener noreferrer">grafana.com/docs</a> ✅ primary</td>
</tr>
<tr>
<td><strong>OpenTelemetry</strong></td>
<td>Instrumentation standard (all pillars)</td>
<td><a href="https://opentelemetry.io/docs/" rel="noopener noreferrer">opentelemetry.io/docs</a> ✅ primary spec</td>
</tr>
<tr>
<td><strong>Elastic</strong></td>
<td>Logs/search + ML anomaly jobs</td>
<td><a href="https://www.elastic.co/docs" rel="noopener noreferrer">elastic.co/docs</a> ✅ primary</td>
</tr>
<tr>
<td><strong>Datadog</strong></td>
<td>SaaS observability + Watchdog/Bits AI</td>
<td><a href="https://docs.datadoghq.com/" rel="noopener noreferrer">docs.datadoghq.com</a> ✅ primary</td>
</tr>
<tr>
<td><strong>Splunk</strong></td>
<td>Log analytics + ITSI/MLTK</td>
<td><a href="https://docs.splunk.com/" rel="noopener noreferrer">docs.splunk.com</a> ✅ primary</td>
</tr>
</tbody>
</table>
<p>Open-source AIOps frameworks include <strong>Merlion</strong> (Salesforce, <a href="https://arxiv.org/abs/2109.09265" rel="noopener noreferrer">arXiv:2109.09265</a>) and <strong>PyOD</strong>/<strong>TODS</strong> for anomaly-detection pipelines. Vendor "AI" features (Datadog Watchdog, Elastic ML jobs, Splunk MLTK) are documented in product docs but their internal algorithms are only partially disclosed — treat capability claims as vendor-sourced.</p>
<hr>
<h2>7. Open Challenges and Future Directions</h2>
<ul>
<li><strong>Evaluation validity</strong>: point-adjustment and leaky benchmarks inflate AD scores; the field is moving toward stricter protocols (TSB-AD, revisiting-AD critiques).</li>
<li><strong>Label scarcity &amp; concept drift</strong>: production telemetry is unlabeled and non-stationary; online/continual learning remains hard.</li>
<li><strong>Multimodal fusion</strong>: jointly reasoning over metrics + logs + traces + topology is still immature; most methods handle one pillar.</li>
<li><strong>Causality vs. correlation</strong>: reliable causal RCA at scale is unsolved; causal graphs are sensitive to hidden confounders and sampling.</li>
<li><strong>LLM reliability</strong>: hallucination, cost, latency, and reproducibility limit LLM-agent RCA in production; grounding via retrieval and tool use is the current mitigation.</li>
<li><strong>Foundation-model transfer</strong>: zero-shot TS models are promising but under-validated on operational anomaly tasks specifically.</li>
</ul>
<hr>
<h2>References</h2>
<p><em>Verified against arXiv metadata in this pass are marked ✔.</em></p>
<ol>
<li>✔ Zhou et al. <strong>Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting</strong>, AAAI 2021. <a href="https://arxiv.org/abs/2012.07436" rel="noopener noreferrer">arXiv:2012.07436</a></li>
<li>✔ Wu et al. <strong>Autoformer: Decomposition Transformers with Auto-Correlation</strong>, NeurIPS 2021. <a href="https://arxiv.org/abs/2106.13008" rel="noopener noreferrer">arXiv:2106.13008</a></li>
<li>✔ Nie et al. <strong>A Time Series is Worth 64 Words (PatchTST)</strong>, ICLR 2023. <a href="https://arxiv.org/abs/2211.14730" rel="noopener noreferrer">arXiv:2211.14730</a></li>
<li>✔ Wu et al. <strong>TimesNet: Temporal 2D-Variation Modeling</strong>, ICLR 2023. <a href="https://arxiv.org/abs/2210.02186" rel="noopener noreferrer">arXiv:2210.02186</a></li>
<li>✔ Xu et al. <strong>Anomaly Transformer: Time Series Anomaly Detection with Association Discrepancy</strong>, ICLR 2022. <a href="https://arxiv.org/abs/2110.02642" rel="noopener noreferrer">arXiv:2110.02642</a></li>
<li>✔ Tuli et al. <strong>TranAD: Deep Transformer Networks for Anomaly Detection in Multivariate Time Series</strong>, VLDB 2022. <a href="https://arxiv.org/abs/2201.07284" rel="noopener noreferrer">arXiv:2201.07284</a></li>
<li>✔ Guo et al. <strong>OWL: A Large Language Model for IT Operations</strong>, 2023. <a href="https://arxiv.org/abs/2309.09298" rel="noopener noreferrer">arXiv:2309.09298</a></li>
<li>✔ Das et al. <strong>A decoder-only foundation model for time-series forecasting (TimesFM)</strong>, 2023. <a href="https://arxiv.org/abs/2310.10688" rel="noopener noreferrer">arXiv:2310.10688</a></li>
<li>✔ Garza et al. <strong>TimeGPT-1</strong>, 2023. <a href="https://arxiv.org/abs/2310.03589" rel="noopener noreferrer">arXiv:2310.03589</a></li>
<li>✔ Jin et al. <strong>Time-LLM: Time Series Forecasting by Reprogramming Large Language Models</strong>, ICLR 2024. <a href="https://arxiv.org/abs/2310.01728" rel="noopener noreferrer">arXiv:2310.01728</a></li>
<li>Liu, Ting, Zhou. <strong>Isolation Forest</strong>, ICDM 2008. <a href="https://doi.org/10.1109/ICDM.2008.17" rel="noopener noreferrer">DOI:10.1109/ICDM.2008.17</a></li>
<li>Schölkopf et al. <strong>Estimating the Support of a High-Dimensional Distribution (One-Class SVM)</strong>, Neural Computation 2001. <a href="https://doi.org/10.1162/089976601750264965" rel="noopener noreferrer">DOI:10.1162/089976601750264965</a></li>
<li>Breunig et al. <strong>LOF: Identifying Density-Based Local Outliers</strong>, SIGMOD 2000. <a href="https://doi.org/10.1145/342009.335388" rel="noopener noreferrer">DOI:10.1145/342009.335388</a></li>
<li>Ester et al. <strong>A Density-Based Algorithm for Discovering Clusters (DBSCAN)</strong>, KDD 1996.</li>
<li>Cleveland et al. <strong>STL: A Seasonal-Trend Decomposition Procedure Based on Loess</strong>, J. Official Statistics 1990.</li>
<li>Su et al. <strong>OmniAnomaly: Robust Anomaly Detection for Multivariate Time Series through Stochastic Recurrent Networks</strong>, KDD 2019. <a href="https://doi.org/10.1145/3292500.3330672" rel="noopener noreferrer">DOI:10.1145/3292500.3330672</a></li>
<li>Deng &amp; Hooi. <strong>Graph Neural Network-Based Anomaly Detection in Multivariate Time Series (GDN)</strong>, AAAI 2021. <a href="https://arxiv.org/abs/2106.06947" rel="noopener noreferrer">arXiv:2106.06947</a></li>
<li>He et al. <strong>Drain: An Online Log Parsing Approach with Fixed Depth Tree</strong>, ICWS 2017. <a href="https://doi.org/10.1109/ICWS.2017.13" rel="noopener noreferrer">DOI:10.1109/ICWS.2017.13</a></li>
<li>Du et al. <strong>DeepLog: Anomaly Detection and Diagnosis from System Logs through Deep Learning</strong>, CCS 2017. <a href="https://doi.org/10.1145/3133956.3134015" rel="noopener noreferrer">DOI:10.1145/3133956.3134015</a></li>
<li>Meng et al. <strong>LogAnomaly: Unsupervised Detection of Sequential and Quantitative Anomalies in Unstructured Logs</strong>, IJCAI 2019. <a href="https://doi.org/10.24963/ijcai.2019/658" rel="noopener noreferrer">DOI:10.24963/ijcai.2019/658</a></li>
<li>Zhang et al. <strong>Robust Log-Based Anomaly Detection on Unstable Log Data (LogRobust)</strong>, ESEC/FSE 2019. <a href="https://doi.org/10.1145/3338906.3338931" rel="noopener noreferrer">DOI:10.1145/3338906.3338931</a></li>
<li>Lin et al. <strong>Log Clustering Based Problem Identification for Online Service Systems (LogCluster)</strong>, ICSE 2016. <a href="https://doi.org/10.1145/2889160.2889232" rel="noopener noreferrer">DOI:10.1145/2889160.2889232</a></li>
<li>Wang et al. <strong>CloudRanger: Root Cause Identification for Cloud Native Systems</strong>, CCGrid 2018. <a href="https://doi.org/10.1109/CCGRID.2018.00076" rel="noopener noreferrer">DOI:10.1109/CCGRID.2018.00076</a></li>
<li>Wu et al. <strong>MicroRCA: Root Cause Localization of Performance Issues in Microservices</strong>, NOMS 2020. <a href="https://doi.org/10.1109/NOMS47738.2020.9110353" rel="noopener noreferrer">DOI:10.1109/NOMS47738.2020.9110353</a></li>
<li>He et al. <strong>LogHub: A Large Collection of System Log Datasets</strong>, 2020. <a href="https://arxiv.org/abs/2008.06448" rel="noopener noreferrer">arXiv:2008.06448</a></li>
<li>Lavin &amp; Ahmad. <strong>Evaluating Real-Time Anomaly Detection Algorithms — the Numenta Anomaly Benchmark (NAB)</strong>, 2015. <a href="https://arxiv.org/abs/1510.03336" rel="noopener noreferrer">arXiv:1510.03336</a></li>
<li>Bhatnagar et al. <strong>Merlion: A Machine Learning Library for Time Series</strong>, 2021. <a href="https://arxiv.org/abs/2109.09265" rel="noopener noreferrer">arXiv:2109.09265</a></li>
<li>OpenTelemetry Documentation. <a href="https://opentelemetry.io/docs/" rel="noopener noreferrer">opentelemetry.io/docs</a> (primary spec)</li>
<li>Prometheus Documentation. <a href="https://prometheus.io/docs/" rel="noopener noreferrer">prometheus.io/docs</a> (primary)</li>
<li>Grafana Documentation. <a href="https://grafana.com/docs/" rel="noopener noreferrer">grafana.com/docs</a> (primary)</li>
</ol>
<p><strong>Unverified / flagged in text:</strong> TSB-AD exact arXiv ID (VLDB reproducibility paper —not cleanly resolved in this pass); GAIA and AIOps-Challenge dataset provenance (communitydataset repos, not peer-reviewed papers); generative-synthetic-telemetry peer-reviewedbaselines (sparse — emerging area); all vendor "AI" capability claims (Datadog Watchdog/BitsAI, Elastic ML, Splunk MLTK) are product-doc sourced, not peer-reviewed; "AIOps" definitionattributed to Gartner (analyst, not a primary technical source). <em>(Drain ICWS 2017 venue andRCACopilot arXiv:2305.15778 were both verified post-hoc via Crossref/arXiv metadata and areno longer flagged.)</em></p>]]></content:encoded>
</item>
<item>
  <title>Aegis: A Root Cause Engine for Distributed Telemetry</title>
  <link>http://ustunkok.com.tr/posts/aegis-a-root-cause-engine-for-distributed-telemetry</link>
  <description>The Anatomy of a Root Cause Engine: Correlating Hidden Patterns in Distributed Telemetry</description>
  <pubDate>Wed, 08 Jul 2026 16:18:20 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/aegis-a-root-cause-engine-for-distributed-telemetry</guid>
  <content:encoded><![CDATA[<h2>Preamble</h2>
<p>We operate a distributed system at scale. When it breaks, we know <strong>what</strong> broke and <strong>where</strong> — the affected service, the degraded operation, the time it started. This takes minutes.</p>
<p>We do not know <strong>why</strong>.</p>
<p>The answer exists somewhere in our telemetry — buried in a log line, encoded in a metric curve, hinted at in a trace fragment, or recorded in a change ticket. But these artifacts live in separate systems, speak different languages, and carry no common thread. Bridging them is a human act: an engineer opens half a dozen consoles, triangulates timestamps, forms a mental model of dependencies, and manually reasons backward from symptom to cause. This takes hours. Sometimes days. Every single time.</p>
<p>This is not a tooling gap. It is a reasoning gap. And we intend to close it.</p>
<hr>
<h2>I. The Aegis Thesis</h2>
<blockquote>
<p><strong>Correlation is not causation, but it is the raw material from which causation can be inferred. If we can fuse change records with telemetry signals across all three pillars — logs, metrics, traces — and if we can construct even a partial map of how our services depend on one another and on their infrastructure, then we can automate the hypothesis-generation step of root cause analysis. We can give the operator a ranked, evidence-backed causal timeline in under five minutes, instead of a blank search bar and a prayer.</strong></p>
</blockquote>
<p>Aegis does not aim to replace the engineer. It aims to compress the mechanical, multi-system search-and-correlate phase — the part that burns time without burning insight — so that the engineer starts their investigation already holding a set of plausible explanations, each backed by evidence drawn from the systems they would otherwise query by hand.</p>
<hr>
<h2>II. The Signals We Have</h2>
<p>We possess three families of telemetry, each with different character:</p>
<h3>Logs</h3>
<p>The richest and messiest signal. Some structured, some semi-structured, some nearly free-form text. They carry error messages, latency measurements, status codes, and — where maintained — ownership attribution and caller identity. They are the ground truth of what the application experienced.</p>
<h3>Metrics</h3>
<p>The cleanest signal. System metrics, application metrics, infrastructure metrics, trace-derived metrics. Well-typed, regularly sampled, pre-aggregated. They tell us <em>that</em> something changed and <em>when</em>, with precision. An existing anomaly pipeline already computes per-metric confidence intervals continuously.</p>
<h3>Traces</h3>
<p>The connective tissue — where they reach. Distributed tracing gives us span-level visibility into request flow, service-to-service call graphs, and latency propagation. But instrumentation is incomplete: critical infrastructure components, particularly database systems, are excluded from tracing due to agent stability concerns. The dependency graph has holes where it matters most.</p>
<h3>Beyond Telemetry</h3>
<p>We also possess a rich change record: every database modification, software deployment, and configuration alteration is recorded with precise timestamps through a formal approval pipeline. We know who changed what and when. What we lack is the connection from change to consequence — the blast radius, the dependent services, the expected behavioral signature.</p>
<hr>
<h2>III. The Gaps We Must Bridge</h2>
<p>Aegis is defined as much by what is missing as by what is present:</p>
<ol>
<li>
<p><strong>No universal correlation identifier.</strong> Some signals carry trace IDs, request IDs, or transaction IDs. Most do not. Cross-signal correlation today relies on temporal proximity and manual search.</p>
</li>
<li>
<p><strong>Traces amputated at the infrastructure boundary.</strong> The most critical dependency — the persistence layer — is invisible to our distributed tracing. When a database degrades, we see the symptoms in the services that call it but cannot see inside.</p>
</li>
<li>
<p><strong>A fragmented dependency graph.</strong> No single source maps which services depend on which other services, databases, or infrastructure. Tracing provides partial edges. Logs encode caller-callee relationships in fields that are being deprecated. The configuration management database aspires to centrality but is not yet complete.</p>
</li>
<li>
<p><strong>Change events carry no blast radius.</strong> A database administrator alters a parameter. The change is recorded. But nothing in that record says "this database serves these twelve services." That knowledge lives in human minds, scattered across teams.</p>
</li>
<li>
<p><strong>Ownership decays.</strong> Service ownership fields, where they exist, are populated at creation time and rarely maintained. A field written five years ago may point to a team that no longer exists.</p>
</li>
</ol>
<p>Aegis must work despite these gaps. It cannot wait for all data to be clean, all instrumentation to be complete, or all dependencies to be declared. It must make defensible inferences from partial information and express its uncertainty honestly.</p>
<hr>
<h2>IV. What Aegis Does</h2>
<p>Given a degraded service and a time window, Aegis returns:</p>
<p><strong>A ranked causal timeline.</strong> A chronologically ordered sequence connecting change events to anomaly onset to symptom emergence, with each candidate root cause scored by confidence and accompanied by supporting evidence drawn from logs, metrics, and traces.</p>
<p>The operator receives this as a report — pushed to a communication channel and persisted in our log aggregation system for visualization — within five minutes of trigger.</p>
<p>Aegis is triggered in two ways:</p>
<ul>
<li><strong>Automatically</strong>, when the anomaly pipeline detects a metric exceeding a severity threshold.</li>
<li><strong>Manually</strong>, when a platform operator initiates an investigation during an incident or post-incident review.</li>
</ul>
<p>In its first version, Aegis is non-interactive. It generates a complete report. Drill-down, hypothesis challenging, and iterative refinement are deferred to later iterations.</p>
<hr>
<h2>V. How Aegis Reasons</h2>
<h3>The Engine: Heuristics First</h3>
<p>Aegis v1 uses explicit, auditable rules. Each rule encodes a causal pattern: a type of change event, a temporal window, an expected signature in telemetry, and a scoring function. Rules compete against each other for explanatory power. Aegis ranks candidates; it does not pronounce a single verdict.</p>
<p>We begin with rule-based reasoning because it is transparent, debuggable, and requires no training data. It can be deployed immediately. Statistical and machine learning approaches are natural extensions when we have accumulated a labeled corpus of resolved incidents.</p>
<h3>Candidate Rule Families</h3>
<p><strong>Change-Induced Degradation.</strong> A change occurs on an entity. Within a bounded temporal window, dependent services exhibit anomaly onset, error rate increases, and novel error patterns in logs that were absent before the change.</p>
<p><strong>No-Change Degradation.</strong> An anomaly with no proximate change event. Suggests gradual resource exhaustion, external dependency failure, or traffic anomaly. Evidence is drawn from metric saturation curves and upstream correlation.</p>
<p><strong>Cascading Failure.</strong> Service A degrades. Service B, which depends on A, degrades with a temporal lag consistent with propagation. Service C follows. Evidence is drawn from trace spans and temporal ordering across the dependency graph.</p>
<p><strong>Infrastructure Event.</strong> Multiple unrelated services degrade simultaneously. Correlated with a host-level or network-level anomaly. Evidence is drawn from infrastructure metrics and network flow data.</p>
<h3>The Dependency Graph: Synthesized, Not Discovered</h3>
<p>Since no single source provides a complete dependency graph, Aegis constructs one from fragments:</p>
<ul>
<li>Trace spans from distributed tracing systems, where instrumented.</li>
<li>Caller-callee relationships inferred from log fields.</li>
<li>Application-to-host mappings from the configuration management database.</li>
<li>Network flow data, mapped to services.</li>
<li>Operator-declared known dependencies, weighted as high-confidence edges.</li>
</ul>
<p>The graph is constructed lazily, scoped to the investigation at hand. It is never expected to be complete — only useful. Every edge carries a confidence weight, and Aegis propagates uncertainty through its inferences.</p>
<h3>Correlation vs. Causation</h3>
<p>Aegis employs multiple strategies to avoid conflating coincidence with cause:</p>
<ul>
<li><strong>Rank, do not decide.</strong> All plausible candidates are presented. The operator retains judgment.</li>
<li><strong>Intervention analysis.</strong> If a changed entity serves N dependent services and all N degrade, the causal link is strong. If only one degrades, the link is weak.</li>
<li><strong>Temporal precedence.</strong> Changes that occurred after symptom onset are excluded as causes.</li>
<li><strong>Counterfactual weakening.</strong> If the same or similar change occurred previously without degradation, the hypothesis is discounted.</li>
<li><strong>Signal convergence.</strong> Hypotheses supported by multiple independent telemetry pillars gain confidence; those supported by only one are penalized.</li>
</ul>
<hr>
<h2>VI. What Aegis Does Not Do</h2>
<p>Clarity about scope is as important as clarity about function.</p>
<p>Aegis does not:</p>
<ul>
<li><strong>Replace the on-call engineer.</strong> It gives them a head start, not a final answer.</li>
<li><strong>Automate remediation.</strong> It identifies probable causes; it does not trigger rollbacks or configuration reversions.</li>
<li><strong>Require perfect data.</strong> It is designed to degrade gracefully with partial information, expressing lower confidence when signals are sparse.</li>
<li><strong>Operate continuously in v1.</strong> Investigations are triggered on-demand; continuous pre-computation of causal indices is a future optimization.</li>
<li><strong>Provide interactive drill-down in v1.</strong> The initial report is a complete artifact; iterative questioning comes later.</li>
</ul>
<hr>
<h2>VII. The Measure of Success</h2>
<p>Aegis v1 is successful if:</p>
<ol>
<li>Platform operators receive a ranked causal hypothesis list in <strong>under five minutes</strong> from trigger.</li>
<li>The true root cause appears in the <strong>top three candidates</strong> in the majority of investigations, as measured against post-incident review outcomes.</li>
<li>Incidents <strong>resolved during the event</strong> increase, because root cause is identified while the incident is still active — reducing the volume of formal post-incident reviews.</li>
<li>Operators adopt Aegis as their <strong>first investigation step</strong>, displacing manual multi-system querying as the default workflow.</li>
</ol>
<hr>
<h2>VIII. The Path Forward</h2>
<p>This manifesto describes intent, not implementation. The next steps are concrete:</p>
<ol>
<li><strong>Ratify the scope.</strong> Confirm the heuristic-first approach, trigger modes, output format, and latency target.</li>
<li><strong>Design the initial rule catalog.</strong> Convene domain experts — service owners, database administrators, incident commanders — to articulate the causal patterns they recognize today.</li>
<li><strong>Prototype the dependency graph construction.</strong> Build a throwaway integration against real data sources and measure coverage against a sample of known service dependencies.</li>
<li><strong>Define data contracts.</strong> Formalize the query interfaces and response schemas for each source system.</li>
<li><strong>Establish an evaluation baseline.</strong> Instrument current manual investigation workflows to capture time-to-root-cause for a representative set of historical incidents, so we can measure Aegis against reality.</li>
</ol>
<hr>
<blockquote>
<p><em>Aegis is not a dashboard. It is not an alerting system. It is a reasoning prosthesis — a machine that does the mechanical correlation work so that the human can do the thinking work. Our operators deserve to start their investigations with a hypothesis, not a blank page.</em></p>
</blockquote>]]></content:encoded>
</item>
<item>
  <title>What Is Information Gain in Information Theory?</title>
  <link>http://ustunkok.com.tr/posts/what-is-information-gain-in-information-theory</link>
  <description>Information gain is a very important concept in information theory. In the most simplest case, it is the reduction in entropy. If you are not familiar with entropy, check out my [entropy post](https://tolga.ustunkok.com.tr/posts/what-is-entropy-in-information-theory). Information gain is used in decision trees. A decision tree is a classification algorithm. Decision tree splits the given feature from specific points with specific questions by branching. By doing that, it tries to maximize information gain. In other words, it tries to minimize the entropy in each branch. To sum up, information gain tells us the reduction in entropy in each split.</description>
  <pubDate>Mon, 06 Jul 2026 16:44:11 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/what-is-information-gain-in-information-theory</guid>
  <content:encoded><![CDATA[<p>Here is the table from the image, converted into Markdown and translated into English:</p>
<p><strong>Picnic Decision Dataset:</strong></p>
<table>
<thead>
<tr>
<th>ID</th>
<th>Wind</th>
<th>Picnic</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>none</td>
<td>no</td>
</tr>
<tr>
<td>2</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>3</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>4</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>5</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>6</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>7</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>8</td>
<td>none</td>
<td>no</td>
</tr>
<tr>
<td>9</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>10</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>11</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>12</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>13</td>
<td>none</td>
<td>yes</td>
</tr>
<tr>
<td>14</td>
<td>yes</td>
<td>no</td>
</tr>
</tbody>
</table>
<p>A simple dataset.</p>
<p>The above toy dataset contains 14 samples of wind measurements and their respected picnic/no-picnic records. The first thing to do is to find the how much information does <code>Picnic</code> column have. There is 9 Evet and 5 Hayır records, total of 14 measurements. Thus, the entropy of Picnic variable is following.</p>
<div class="arithmatex">\[-\frac{9}{14}\log_2\left(\frac{9}{14}\right)-\frac{5}{14}\log_2\left(\frac{5}{14}\right)=0.9403\]</div>
<p>Entropy of picnic.</p>
<p>Now, if we split the <code>Picnic</code> variable by the wind situation <code>yes</code>/<code>none</code>, the average reduction in the entropy would be the information gain. To do that, let's put the <code>yes</code> and <code>no</code> measurements next to each other in a row, and split it by the wind measurements.</p>
<pre class="mermaid">graph TD
    Root[YYYYYYYYNNNNN] --&gt;|Yes| Left[YYYNNNN]
    Root --&gt;|None| Right[YYYYYYYYNN]
</pre>
<p>Split by wind.</p>
<p>Here, we should find the entropy in each leaf node. Then, we are going to calculate the weighted average of entropy by taking account of the E/H count in each node.</p>
<p>In the left most leaf node, the entropy is 1 since picking a letter results with the probability of 0.5 of Y and 0.5 of N. For the right node, we can calculate the entropy as follows.</p>
<div class="arithmatex">\[-\frac{6}{8}\log_2\left(\frac{6}{8}\right)-\frac{2}{8}\log_2\left(\frac{2}{8}\right)=0.8113\]</div>
<p>Entropy of the right node.</p>
<p>Now, we can calculate the weighted average of entropy. There is 6 samples in the left, and 8 samples in the right. The following equation calculates the weighted average.</p>
<div class="arithmatex">\[\frac{6}{14}\times1+\frac{8}{14}\times0.8113=0.8922\]</div>
<p>Weighted average of the entropies.</p>
<p>The last part is the calculating the reduction in the entropy. We just need to extract the average entropy from the first one.</p>
<div class="arithmatex">\[0.9483-0.8922=0.0561\]</div>
<p>Reduction in entropy.</p>
<p>This result tells us if we split the Picnic variable by the wind situations, there will be a 0.0561 reduction in the entropy. In another words, there will be a 0.0561 of information gain in this split.</p>
<p>In a decision tree, we do that for all of the independent variables. We calculate the each individual information gain for all of the independent variables. Then, we choose the feature that causes the largest reduction in entropy and split the tree into branches. We continue to the process until there is no split to make (entropy is 0) or to meet a stop condition (maximum split count or maximum depth of the tree). There are multiple ways to calculate the information gain for different purposes. Information gain is only one of them. Maybe, in another post I will write about some of them. Until then, see you in another day. Bye...</p>]]></content:encoded>
</item>
<item>
  <title>What Is Entropy in Information Theory?</title>
  <link>http://ustunkok.com.tr/posts/what-is-entropy-in-information-theory</link>
  <description>Entropy is one of the key concepts of information theory, data science and machine learning. Understanding the math behind it is crucial for designing solid machine learning pipelines. Therefore, in this post, I try to explain the entropy as simple as possible.</description>
  <pubDate>Sun, 05 Jul 2026 11:50:53 +0000</pubDate>
  <guid isPermaLink="true">http://ustunkok.com.tr/posts/what-is-entropy-in-information-theory</guid>
  <content:encoded><![CDATA[<p>When I first saw the name entropy in decision trees, I really didn't think about it. I couldn't get the importance of this concept. So, I moved on to my machine learning (ML) adventure without it. However, almost every time I tried to learn a new ML concept, entropy was on my way. I couldn't escape from it. Then, I (with the encouragement of my graduate advisor who is an excellent mentor for me) decided to confront it. The first few days to understand the entropy was not easy in terms of understanding why it was created in the first place. We already have the probability, haven't we? But, no. It is very useful, fix some problems that the probability can't, and almost every concept in ML make use of it due to some computational reasons.</p>
<p>In this first story of mine, I will try my best to clear out the concepts of entropy and some other related concepts such as information gain and information gain ratio. I also want to suggest a video about entropy by Luis Serrano. You can find the video here. While this is an excellent video, it is not enough to fully understand the entropy. You need to make lots of reading sessions and maybe implement it with a programming language. Now, let's get back to the subject.</p>
<p>I am not a physicist but as far as I know, entropy in physics corresponds to the energy of particles in a media. If we give an example, the four phases of matter would be a good candidate.</p>
<p><img alt="" src="/images/1"></p>
<p>The leftmost image (ice) has the lowest entropy since the particles are not moving as fast as the other two. The middle (water) has more energy than ice. So the entropy is higher than ice. The rightmost (water vapor) has the highest entropy since the particles move fastest.</p>
<p>This idea applies to the information theory in the sense of probability. Claude Shannon is the man who brings the idea in information theory. Suppose you have a computer. This computer can only output a sequence of characters. But some characters are permitted to repeat. The list of all possible characters that can present in the output is the dictionary of the computer. The question is here how much information do you have about the output of the computer?</p>
<p><img alt="" src="/images/2">
A computer with a dictionary consists of the only letter "A" outputs a string of "AAAAAAAAAAAA".</p>
<p>The above computer has a dictionary <span class="arithmatex">\(D = \{ \text{"A"} \}\)</span>. So, we will have a guaranteed output of "A", right? This means that we know a lot about the output. We will get into how we will compute entropy, but at this point let's say that this output has an entropy value of 0. Because we are certain about the output. It will consist of nothing else but the letter "A" only.</p>
<p>What if our dictionary consists of more than one letter or even numbers? For example, dictionary <span class="arithmatex">\(D = \{ \text{"A"}, \text{"B"} \}\)</span>. Then the output of the computer might be as follows.</p>
<p><img alt="" src="/images/3"></p>
<p>A computer with a dictionary consists of letter "A" and "B", outputs a string of "AAAAAABBBBBB".</p>
<p>Let's say from this output we need to pick a letter. Remember that each pick is independent of each other. So, what is the probability of producing an output that has the same order as in the original output sequence? The answer to this question is comes from the probability, right?</p>
<div class="arithmatex">\[\frac{6}{12} \times \frac{6}{12} \times \underbrace{\dots}_{9} \times \frac{6}{12} = \frac{1}{4096} = 0.0002\]</div>
<p>The probability of picking "A" or "B" independently is 0.5. There are 12 letters in the output. So we have multiplied 12 independent probability of picking different letters.</p>
<p>As you can see, the result is very small. This means that producing the same output as the computer is very difficult. We have little information about the output. Our chance to pick a letter and knowing what it is is the same as tossing a coin. This result suggests us we have a higher entropy value here.</p>
<p>But why do we need the entropy? We have the probability and it tells us something about the information amount of the data. Here is the reason. Actually, you can see it yourself, too. If we have fewer letters in the sequence, let's say 4 instead of 12; two for "A" and two for "B", the result will be 0.0625. But the entropy will still be high. So, what's change? You see that the amount of letters in the data affects the output of the probability exponentially. This is a problem for our computers, right? Smaller the floating point number, smaller the precision. You may be heard of the vanishing gradient problem in Recurrent Neural Networks (RNN). This is the reason for it and this is the starting point of entropy.</p>
<p>We need a way to not reducing the output that much but at the same time take care of all the letters in the sequence. What if we try to get rid of the exponential function (the repeated multiplication) by converting it to a linear function. How do we do that? Maybe the answer is in the summation. Because repeated summation is just a linear function, unlike multiplication. So, the conversion can be easily made by logarithms. Then let's take the logarithm of the above equation. There is only a little problem here. Which number should be used as the base of the logarithm? You can pick whatever number you want. However, we are from the area of computation. We love to express numbers and information as bits. A bit is a 1 or 0. So, a bit can be expressed in base 2. This means that we want to express the data with two symbols. Therefore, it is natural that we choose 2 as the base for the logarithm. Now, let's take the logarithm at base 2.</p>
<div class="arithmatex">\[\log_{2} \left( \frac{6}{12} \times \frac{6}{12} \times \underbrace{\dots}_{9} \times \frac{6}{12} \right) = -12\]</div>
<p>Logarithm base 2 of the above equation.</p>
<p>What a beautiful number here. But, hmm…, you see there are two little problems here. First, we have 12 letters in the sequence and the result is 12. Will this number increase as the letter count increases? Yes, it will increase. So we can normalize it with the letter count by dividing it to 12 in this case.</p>
<div class="arithmatex">\[\frac{1}{12} \times \log_{2} \left( \frac{6}{12} \times \frac{6}{12} \times \underbrace{\dots}_{9} \times \frac{6}{12} \right) = -1\]</div>
<p>The result is normalized with the letter count.</p>
<p>This is much better. But, why the number is negative? There is no point to proceed with a negative number while trying to measure the information in a sequence. So, let's multiply the expression with -1.</p>
<div class="arithmatex">\[-\frac{1}{12} \times \log_{2} \left( \frac{6}{12} \times \frac{6}{12} \times \underbrace{\dots}_{9} \times \frac{6}{12} \right) = 1\]</div>
<p>The previous expression is multiplied by -1 to get rid of the redundant negative sign.</p>
<p>This is it. We made to the end. Almost. We still haven't converted the multiplication into the summation.</p>
<div class="arithmatex">\[\frac{1}{12} \left( -\log_2\left(\frac{6}{12}\right) - \log_2\left(\frac{6}{12}\right) - \underbrace{\dots}_{9} - \log_2\left(\frac{6}{12}\right) \right) = 1\]</div>
<p>The multiplication is eliminated by taking advantage of the property of logarithms.</p>
<p>The first six expressions of the sequence are for the letter "A" and the remaining six is for the letter "B". Now, let's make this more obvious and distribute the multiplication over the whole expression.</p>
<div class="arithmatex">\[-\frac{6}{12} \log_2\left(\frac{6}{12}\right) - \frac{6}{12} \log_2\left(\frac{6}{12}\right) = 1\]</div>
<p>The coefficient at the beginning of the whole expression is distributed. In the meantime, the summations are grouped together each for a letter (6 for A and 6 for B).</p>
<p>This is the entropy. For this sequence, as we change the number of letters, the probability of producing the exact same output will change. However, the entropy will never change as the proportion of letter counts are constant regardless of the total number of letters in the sequence. If we generalize the entropy, the following expression can be obtained.</p>
<div class="arithmatex">\[\text{Entropy} = -\sum_{i=1}^{n} P_i \log_2(P_i)\]</div>
<p>The general formula for entropy.</p>
<p><span class="arithmatex">\(P\)</span> is the probability of picking <em>ith</em> distinct element from the sequence. The knowledge and entropy are opposites. If we have high knowledge about a sequence, the entropy is lower, and vice versa. Let's make another example with a different sequence.</p>
<p><img alt="" src="/images/4"></p>
<p>An example sequence with a dictionary of D = {"A", "B", "C"}.</p>
<p>Here we have 3 distinct letters in a 12 letter sequence. Let's calculate the entropy with the above formula.</p>
<div class="arithmatex">\[-\frac{2}{12} \log_2\left(\frac{2}{12}\right) - \frac{4}{12} \log_2\left(\frac{4}{12}\right) - \frac{6}{12} \log_2\left(\frac{6}{12}\right) = 1.4591\]</div>
<p>The entropy of the previous sequence.</p>
<p>Ok, we have calculated the entropy. But, what's the result even means? Actually, the result is the average number of yes/no questions to guess the next letter in the sequence. Be careful about that. You need to ask the questions in the smartest way possible.</p>
<p>Entropy is used in many ML methods. One of the popular ML methods is Decision Tree. In the decision tree, we try to find the independent variable that splits another dependent variable in the best way possible. How to find that variable? The answer is we split the target (dependent) variable with each of the other independent variables and check the reduction in entropy after each of the splits. The variable that causes the most reduction is the winner. This reduction is called information gain.</p>
<p>There are other types of entropy reduction metrics. For example, information gain ratio. It is a very close concept to information gain. I am planning to write about each of them later in separate stories. I hope this post is helpful. If I made a mistake in the post, please let me know. See you soon. Bye…</p>]]></content:encoded>
</item>
</channel>
</rss>
