"The Wheel weaves as the Wheel wills — but we must detect the outliers before the Dark One breaks free."
March 2026 · Giacomo Saccaggi
In Robert Jordan's The Wheel of Time, the Pattern is the great tapestry woven by the Wheel from the threads of human lives. Each thread follows a predictable path — the normal distribution of existence. But some threads are different.
Ta'veren — like Rand al'Thor, Mat Cauthon, and Perrin Aybara — are statistical anomalies so powerful they bend probability itself around them. Coins always land on edge. Armies appear at impossible moments. The Pattern warps in their vicinity.
And then there are the Bubbles of Evil — malicious corruptions seeping from the Dark One's prison, distorting reality in dangerous ways. These are the fraudulent transactions, the sensor failures, the corrupted data that threaten to unravel your model's integrity.
As an Aes Sedai of Data, your task is clear: weave the One Power — in the form of Python algorithms — to sense these disturbances in the Pattern and isolate them before they spread.
No single weave of the One Power can detect all forms of corruption. The AnomalyDetector from scomp-link combines four complementary methods into a consensus system — like the five flows of the Power (Earth, Air, Fire, Water, Spirit) combining into a single devastating weave:
| Method | Approach (The Weave) | Best For |
|---|---|---|
| Isolation Forest | Randomly isolates points via recursive partitioning — anomalies are isolated faster | Global outliers, high-dimensional data |
| Local Outlier Factor | Measures local density deviation against neighbors | Local anomalies in dense regions |
| TabNet Autoencoder | Learns feature reconstruction with attention — high error = anomaly | Complex feature interactions |
| Transformer Autoencoder | Self-attention across features as tokens — captures inter-feature relationships | Non-linear feature dependencies |
from scomp_link.models.anomaly_detector import AnomalyDetector
import pandas as pd
import numpy as np
# --- The Pattern: our dataset of transactions ---
np.random.seed(42)
n = 1000
the_pattern = pd.DataFrame({
'amount': np.random.lognormal(4, 0.5, n),
'hour': np.random.normal(14, 4, n).clip(0, 23),
'velocity': np.random.exponential(2, n),
'device_risk': np.random.choice([0, 1, 2], n, p=[0.7, 0.2, 0.1])
})
# --- Inject Bubbles of Evil (fraudulent transactions) ---
bubbles_of_evil = np.random.choice(n, 50, replace=False)
the_pattern.loc[bubbles_of_evil, 'amount'] = np.random.uniform(5000, 20000, 50)
the_pattern.loc[bubbles_of_evil, 'hour'] = np.random.uniform(1, 5, 50)
the_pattern.loc[bubbles_of_evil, 'velocity'] = np.random.uniform(15, 30, 50)
# --- The Weave: consensus-based detection ---
detector = AnomalyDetector(
contamination=0.05,
methods=['iforest', 'lof', 'tabnet', 'transformer'],
consensus_threshold=2,
verbose=True
)
results = detector.fit_predict(
the_pattern,
features=['amount', 'hour', 'velocity', 'device_risk']
)
# --- Reading the Pattern ---
print(results['comparison'])
# method n_anomalies pct
# 0 iforest 48 4.8
# 1 lof 52 5.2
# 2 tabnet 45 4.5
# 3 transformer 47 4.7
# 4 consensus(≥2) 35 3.5
anomalies = results['data'][results['data']['is_anomaly']]
print(f"Ta'veren detected: {len(anomalies)} threads bent the Pattern")
# Output:
# [AnomalyDetector] Running Isolation Forest...
# [AnomalyDetector] Running Local Outlier Factor...
# [AnomalyDetector] Running TabNet Autoencoder...
# [AnomalyDetector] Running Transformer Autoencoder...
# [AnomalyDetector] Computing consensus (threshold=2)...
#
# method n_anomalies pct
# 0 iforest 48 4.8
# 1 lof 52 5.2
# 2 tabnet 45 4.5
# 3 transformer 47 4.7
# 4 consensus(≥2) 35 3.5
#
# Ta'veren detected: 35 threads bent the Pattern
In the Pattern, Bubbles of Evil manifest as temporal distortions — moments where reality itself fractures. The TimeSeriesAnomalyDetector trains on a clean historical baseline (the Age of Legends, if you will) and then detects corruptions in new data.
from scomp_link.models.ts_anomaly_detector import TimeSeriesAnomalyDetector
import numpy as np
# --- The Age of Legends: clean baseline signal ---
np.random.seed(42)
t_train = np.arange(1000)
clean_pattern = 50 + 0.01*t_train + 5*np.sin(2*np.pi*t_train/50) + np.random.normal(0, 1, 1000)
# --- The Third Age: new data with Bubbles of Evil ---
t_test = np.arange(500)
corrupted_age = 60 + 0.01*t_test + 5*np.sin(2*np.pi*t_test/50) + np.random.normal(0, 1, 500)
# Inject bubbles of evil (anomalous spikes)
bubble_indices = [120, 121, 250, 251, 252, 380, 381]
corrupted_age[bubble_indices] += np.random.uniform(12, 20, len(bubble_indices))
# --- The Weave of Foretelling ---
detector = TimeSeriesAnomalyDetector(
methods=['autoencoder', 'moving_avg', 'moving_median', 'arima'],
time_steps=50,
window_size=20,
n_sigma=3.0,
ae_epochs=30,
threshold_percentile=95.0,
verbose=True
)
# Train on the clean Pattern
detector.fit(clean_pattern)
# Detect Bubbles of Evil in the Third Age
results = detector.detect(corrupted_age)
# The Foretelling speaks
print(f"Bubbles of Evil detected: {results['anomalies'].sum()} / {len(corrupted_age)} points")
for method, flags in results['methods'].items():
print(f" {method}: {flags.sum()} anomalies sensed")
# Consensus: how many Aes Sedai agree on each disturbance
print(f"\nMax consensus score: {results['consensus_score'].max()}")
# Output:
# [TimeSeriesAnomalyDetector] Training Conv1D Autoencoder...
# [TimeSeriesAnomalyDetector] Fitting ARIMA(5,1,0)...
# [TimeSeriesAnomalyDetector] Detecting with autoencoder...
# [TimeSeriesAnomalyDetector] Detecting with moving_avg...
# [TimeSeriesAnomalyDetector] Detecting with moving_median...
# [TimeSeriesAnomalyDetector] Detecting with arima...
#
# Bubbles of Evil detected: 7 / 500 points
# autoencoder: 9 anomalies sensed
# moving_avg: 7 anomalies sensed
# moving_median: 8 anomalies sensed
# arima: 6 anomalies sensed
#
# Max consensus score: 4
| AnomalyDetector | TimeSeriesAnomalyDetector | |
|---|---|---|
| Data type | Tabular (rows × features) | Univariate time series |
| Training | Same dataset (unsupervised) | Separate clean baseline |
| Key parameter | consensus_threshold | n_sigma, time_steps |
| Output | Boolean column + comparison table | Boolean array + consensus score |
| Dependencies | pytorch-tabnet, torch | tensorflow, statsmodels |
"The Wheel of Time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again."
In data science, as in the Wheel, the Pattern repeats — but anomalies are the key to understanding when something has truly changed. Whether you face Ta'veren (legitimate outliers that reveal new opportunities) or Bubbles of Evil (fraud, failures, corruption), the scomp-link consensus approach ensures you detect them with confidence.
Install the package and begin channeling:
pip install scomp-link
May the Light illuminate your anomalies.