API Reference / algorithms / anomaly /

local_outlier_factor.py

Local Outlier Factor (LOF) anomaly detection algorithm.

Classes

LocalOutlierFactorDetector

class algorithms.anomaly.local_outlier_factor.LocalOutlierFactorDetector(Classifier)

Local Outlier Factor for density-based anomaly detection.

LOF detects anomalies by comparing the local density of a point with the densities of its neighbors. Points in significantly sparser regions than their neighbors are identified as outliers. Unlike global density methods, LOF adapts to local density variations in the data.
Constructor
__init__(
    self,
    n_neighbors: int = 20,
    contamination: float = 0.1,
    metric: str = 'euclidean',
    novelty: bool = False,
)

Overview

The algorithm works through four main steps:

  1. Find the k-nearest neighbors for each point
  2. Compute the reachability distance (smoothed distance to neighbors)
  3. Calculate Local Reachability Density (LRD) for each point
  4. Compute the LOF score as the ratio of neighbor densities to point density
The key insight: Outliers have much lower density than their neighbors, resulting in LOF scores significantly greater than 1.

Theory

For a point A with k-nearest neighbors N_k(A):

1. k-distance: Distance to the k-th nearest neighbor

2. Reachability distance:

\text{reach-dist}_k(A, B) = \max(k\text{-distance}(B), d(A, B))

This "smooths" distances to prevent instability when points are very close.

3. Local Reachability Density (LRD):

\text{LRD}_k(A) = \frac{1}{\frac{1}{|N_k(A)|} \sum_{B \in N_k(A)} \text{reach-dist}_k(A, B)}

Higher LRD → point is in a denser region.

4. Local Outlier Factor:

\text{LOF}_k(A) = \frac{1}{|N_k(A)|} \sum_{B \in N_k(A)} \frac{\text{LRD}_k(B)}{\text{LRD}_k(A)}

Score interpretation:

  • \text{LOF} \approx 1 → Normal point (similar density to neighbors)
  • \text{LOF} < 1 → Denser than neighbors (inlier)
  • \text{LOF} > 1 → Sparser than neighbors (outlier)
  • \text{LOF} \gg 1 → Strong outlier

Parameters

n_neighbors
int = 20
Number of neighbors to use for local density estimation. Larger values consider more global structure; smaller values are more sensitive to local variations.
contamination
float = 0.1
Expected proportion of outliers in the dataset. Must be in the range (0, 0.5]. Used to set the decision threshold.
metric
str = "euclidean"

Distance metric for computing neighbor distances:

  • "euclidean": Euclidean (L2) distance
  • "manhattan": Manhattan (L1) distance
  • "chebyshev": Chebyshev (L∞) distance
novelty
bool = False

Detection mode:

  • False: Outlier detection (fit and predict on same data)
  • True: Novelty detection (predict on new, unseen data)

Attributes

X_train_
np.ndarray
Training data (stored for computing densities of new points).
neighbors_indices_
np.ndarray of shape (n_samples, n_neighbors)
Indices of k-nearest neighbors for each training sample.
neighbors_distances_
np.ndarray of shape (n_samples, n_neighbors)
Distances to k-nearest neighbors for each training sample.
lrd_
np.ndarray of shape (n_samples,)
Local Reachability Density for each training sample.
lof_scores_
np.ndarray of shape (n_samples,)
LOF scores for each training sample.
threshold_
float
Decision threshold separating normal from anomalous instances. Computed based on the contamination parameter.
n_features_in_
int
Number of features observed during fit().

Notes

Complexity:

  • Training: O(n^2 \log n) where n = number of samples
  • Prediction: O(n \cdot k) where k = n_neighbors
When to use LOF:
  • Data with varying local densities (clusters of different densities)
  • When global outlier detection is insufficient
  • Medium-sized datasets (becomes slow for very large datasets)
  • When you want interpretable density-based scores
Limitations:
  • Quadratic complexity limits scalability to large datasets
  • Sensitive to choice of n_neighbors parameter
  • Requires storing training data for novelty detection
  • Performance degrades in very high dimensions (curse of dimensionality)

References

Breunig2000
Breunig, M.M., Kriegel, H.P., Ng, R.T. and Sander, J. (2000). LOF: identifying density-based local outliers. ACM Sigmod Record, 29(2), pp. 93-104. DOI: 10.1145/335191.335388

Basic usage for outlier detection:

python
>>> from tuiml.algorithms.anomaly import LocalOutlierFactorDetector
>>> import numpy as np
>>>
>>> # Create data with one clear outlier
>>> X = np.array([[1, 2], [2, 3], [3, 3], [2, 2], [10, 10]])
>>>
>>> # Fit and predict on training data
>>> clf = LocalOutlierFactorDetector(n_neighbors=3, contamination=0.2)
>>> predictions = clf.fit_predict(X)
>>> print(predictions)
[ 1  1  1  1 -1]

Novelty detection on new data:

python
>>> # Train on normal data
>>> X_train = np.array([[1, 2], [2, 3], [3, 3], [2, 2]])
>>> X_test = np.array([[2.5, 2.5], [10, 10]])
>>>
>>> # Use novelty mode to predict on new data
>>> clf = LocalOutlierFactorDetector(n_neighbors=3, novelty=True)
>>> clf.fit(X_train)
>>> predictions = clf.predict(X_test)
>>> print(predictions)
[ 1 -1]
>>>
>>> # Get LOF scores
>>> scores = clf.decision_function(X_test)

Methods

get_parameter_schema (cls) -> Dict[str, Dict[str, Any]]

Return JSON Schema for algorithm parameters.

get_capabilities (cls) -> List[str]

Return supported capabilities.

get_complexity (cls) -> str

Return complexity analysis.

get_references (cls) -> List[str]

Return academic citations.

fit (self, X: np.ndarray, y: Optional[np.ndarray]=None) -> 'LocalOutlierFactorDetector'

Fit the LOF model.

Parameters
X
np.ndarray of shape (n_samples, n_features)
Training data.
y
np.ndarray or None = None
Ignored. Present for API consistency.
Returns
self
LocalOutlierFactorDetector
Fitted estimator.
decision_function (self, X: np.ndarray) -> np.ndarray

Compute anomaly scores for samples.

Parameters
X
np.ndarray of shape (n_samples, n_features)
Input samples.
Returns
scores
np.ndarray of shape (n_samples,)
Anomaly scores. Higher values indicate anomalies.
predict (self, X: np.ndarray) -> np.ndarray

Predict if samples are anomalies or not.

Parameters
X
np.ndarray of shape (n_samples, n_features)
Input samples.
Returns
predictions
np.ndarray of shape (n_samples,)
-1 for anomalies, 1 for normal instances.
fit_predict (self, X: np.ndarray, y: Optional[np.ndarray]=None) -> np.ndarray

Fit and predict anomalies in training data.

Parameters
X
np.ndarray of shape (n_samples, n_features)
Training data.
y
np.ndarray or None = None
Ignored.
Returns
predictions
np.ndarray of shape (n_samples,)
-1 for anomalies, 1 for normal instances.
score_samples (self, X: np.ndarray) -> np.ndarray

Alias for decision_function for compatibility.

Parameters
X
np.ndarray of shape (n_samples, n_features)
Input samples.
Returns
scores
np.ndarray of shape (n_samples,)
Anomaly scores.