pycsamt.ai.processing.anomaly#

AnomalyDetector — unsupervised profile-level anomaly detection.

A fully-connected autoencoder is trained on per-site feature vectors derived from a survey profile. Sites whose reconstruction error significantly exceeds the training distribution are flagged as anomalous — they may represent bad data, equipment problems, or genuinely anomalous geology that warrants closer inspection.

Architecture#

\[\hat{\mathbf{x}} = g(f(\mathbf{x}))\]

where \(f: \mathbb{R}^d \to \mathbb{R}^k\) is the encoder (\(k \ll d\)) and \(g: \mathbb{R}^k \to \mathbb{R}^d\) is the decoder. The anomaly score for site \(i\) is

\[s_i = \|\mathbf{x}_i - \hat{\mathbf{x}}_i\|_2^2 / d.\]

A site is flagged when \(s_i\) exceeds the threshold_percentile-th percentile of training scores.

When neither PyTorch nor TensorFlow is available the detector falls back to PCA-based reconstruction using sklearn.decomposition.PCA.

Classes

AnomalyDetector([n_features, latent_dim, ...])

Profile-level unsupervised anomaly detector.

class pycsamt.ai.processing.anomaly.AnomalyDetector(n_features=None, latent_dim=32, *, channels=(128, 64), threshold_percentile=95.0, device=None)[source]#

Bases: BaseEMProcessor

Profile-level unsupervised anomaly detector.

Parameters:
  • n_features (int or None, default None) – Feature vector length per site (typically n_freqs × n_components). When None, inferred from X.shape[1] on the first call to fit().

  • latent_dim (int, default 32) – Bottleneck dimension of the autoencoder.

  • channels (tuple of int, default (128, 64)) – Hidden layer widths in the encoder (decoder is mirrored).

  • threshold_percentile (float, default 95.0) – Sites with reconstruction error above this percentile of the training distribution are flagged as anomalous.

  • device (str or None) – Compute device. Ignored when using the PCA fallback.

Notes

When neither PyTorch nor TensorFlow is installed the detector silently uses a PCA reconstruction model via scikit-learn. The interface is identical; only the accuracy differs.

Examples

>>> import numpy as np
>>> X = np.random.randn(100, 120).astype("float32")
>>> det = AnomalyDetector(latent_dim=16)
>>> det.fit(X, epochs=10, verbose=False)
AnomalyDetector(n_features=120, latent_dim=16)
>>> scores = det.transform(X)
>>> flags = det.flag_anomalies(X)
fit(X, *, epochs=80, batch_size=32, lr=0.001, val_frac=0.1, seed=None, verbose=True)[source]#

Train the anomaly detector on profile data.

Parameters:
  • X (ndarray, shape (n_sites, n_features)) – Per-site feature vectors (normal / clean data).

  • epochs (int) – Training epochs (ignored when using PCA fallback).

  • batch_size (int)

  • lr (float)

  • val_frac (float)

  • seed (int or None)

  • verbose (bool)

Return type:

self

transform(X)[source]#

Compute per-site reconstruction error (anomaly score).

Parameters:

X (ndarray, shape (n_samples, n_features))

Returns:

scores – Per-site mean squared reconstruction error.

Return type:

ndarray, shape (n_samples,)

flag_anomalies(X)[source]#

Return a boolean mask of anomalous sites.

Parameters:

X (ndarray, shape (n_samples, n_features))

Returns:

flags

Return type:

bool ndarray, shape (n_samples,)