distances.md
264 lines · skills/aeon/references/distances.md at 5f2bc03
Distance Metrics
Aeon provides specialized distance functions for measuring similarity between time series, compatible with both aeon and scikit-learn estimators.
Raw lines 1 to 4Distance Categories
Raw lines 5 to 6Elastic Distances
Allow flexible temporal alignment between series:
Dynamic Time Warping Family:
dtw- Classic Dynamic Time Warpingddtw- Derivative DTW (compares derivatives)wdtw- Weighted DTW (penalizes warping by location)wddtw- Weighted Derivative DTWshape_dtw- Shape-based DTW
Edit-Based:
erp- Edit distance with Real Penaltyedr- Edit Distance on Real sequenceslcss- Longest Common SubSequencetwe- Time Warp Edit distance
Specialized:
msm- Move-Split-Merge distanceadtw- Amerced DTWsbd- Shape-Based Distance
Use when: Time series may have temporal shifts, speed variations, or phase differences.
Raw lines 7 to 30Lock-Step Distances
Compare time series point-by-point without alignment:
euclidean- Euclidean distance (L2 norm)manhattan- Manhattan distance (L1 norm)minkowski- Generalized Minkowski distance (Lp norm)squared- Squared Euclidean distance
Use when: Series already aligned, need computational speed, or no temporal warping expected.
Raw lines 31 to 41Usage Patterns
Raw lines 42 to 43Computing Single Distance
from aeon.distances import dtw_distance
# Distance between two time series
distance = dtw_distance(x, y)
# With window constraint (Sakoe-Chiba band)
distance = dtw_distance(x, y, window=0.1)Raw lines 44 to 55Pairwise Distance Matrix
from aeon.distances import dtw_pairwise_distance
# All pairwise distances in collection
X = [series1, series2, series3, series4]
distance_matrix = dtw_pairwise_distance(X)
# Cross-collection distances
distance_matrix = dtw_pairwise_distance(X_train, X_test)Raw lines 56 to 68Cost Matrix and Alignment Path
from aeon.distances import dtw_cost_matrix, dtw_alignment_path
# Get full cost matrix
cost_matrix = dtw_cost_matrix(x, y)
# Get optimal alignment path
path, cost = dtw_alignment_path(x, y)
# path is a list of index pairs; cost equals dtw_distance(x, y)Raw lines 69 to 81Using with Estimators
from aeon.classification.distance_based import KNeighborsTimeSeriesClassifier
# Use DTW distance in classifier
clf = KNeighborsTimeSeriesClassifier(
n_neighbors=5,
distance="dtw",
distance_params={"window": 0.2}
)
clf.fit(X_train, y_train)Raw lines 82 to 95Distance Parameters
Raw lines 96 to 97Window Constraints
Limit warping path deviation (improves speed and prevents pathological warping):
# Sakoe-Chiba band: window as fraction of series length
dtw_distance(x, y, window=0.1) # Allow 10% deviation
# Itakura parameter is a fraction in [0, 1], not a raw slope
dtw_distance(x, y, itakura_max_slope=0.5)Raw lines 98 to 109Normalization
Normalize explicitly when shape rather than amplitude is the scientific target. dtw_distance has no normalize argument; it returns the accumulated squared local cost, without a final square root:
import numpy as np
from aeon.transformations.collection import Normalizer
# x and y are equal-length univariate arrays here
xy = Normalizer().fit_transform(np.stack([x, y])[:, None, :])
distance = dtw_distance(xy[0], xy[1])Raw lines 110 to 122Distance-Specific Parameters
from aeon.distances import erp_distance, twe_distance, lcss_distance
# ERP: penalty for gaps
distance = erp_distance(x, y, g=0.5)
# TWE: stiffness and penalty parameters
distance = twe_distance(x, y, nu=0.001, lmbda=1.0)
# LCSS: epsilon threshold for matching
distance = lcss_distance(x, y, epsilon=0.5)Raw lines 123 to 137Algorithm Selection
Raw lines 138 to 139By Use Case:
Temporal misalignment: DTW, DDTW, WDTW Speed variations: DTW with window constraint Shape similarity: Shape DTW, SBD Edit operations: ERP, EDR, LCSS Derivative matching: DDTW Computational speed: Euclidean, Manhattan Outlier robustness: Manhattan, LCSS
Raw lines 140 to 149By Computational Cost:
Fastest: Euclidean (O(n)) Fast: Constrained DTW (O(nw) where w is window) Medium: Full DTW (O(n²)) Slower: Complex elastic distances (ERP, TWE, MSM)
Raw lines 150 to 156Quick Reference Table
| Distance | Alignment | Speed | Robustness | Interpretability |
|---|---|---|---|---|
| Euclidean | Lock-step | Very Fast | Low | High |
| DTW | Elastic | Medium | Medium | Medium |
| DDTW | Elastic | Medium | High | Medium |
| WDTW | Elastic | Medium | Medium | Medium |
| ERP | Edit-based | Slow | High | Low |
| LCSS | Edit-based | Slow | Very High | Low |
| Shape DTW | Elastic | Medium | Medium | High |
Best Practices
Raw lines 169 to 1701. Normalization
Most distances sensitive to scale; normalize when appropriate:
from aeon.transformations.collection import Normalizer
normalizer = Normalizer()
X_normalized = normalizer.fit_transform(X)Raw lines 171 to 1812. Window Constraints
For DTW variants, use window constraints for speed and better generalization:
# Start with 10-20% window
distance = dtw_distance(x, y, window=0.1)Raw lines 182 to 1903. Series Length
- Equal-length required: Most lock-step distances
- Unequal-length supported: Elastic distances (DTW, ERP, etc.)
4. Multivariate Series
Most distances support multivariate time series:
# x.shape = (n_channels, n_timepoints)
distance = dtw_distance(x_multivariate, y_multivariate)Raw lines 196 to 2045. Performance Optimization
- Use numba-compiled implementations (default in aeon)
- Consider lock-step distances if alignment not needed
- Use windowed DTW instead of full DTW
- Precompute distance matrices for repeated use
6. Choosing the Right Distance
# Quick decision tree:
if series_aligned:
use_distance = "euclidean"
elif need_speed:
use_distance = "dtw" # with window constraint
elif temporal_shifts_expected:
use_distance = "dtw" # compare with "shape_dtw" by validation
elif outliers_present:
use_distance = "lcss" # compare with "manhattan" by validation
elif derivatives_matter:
use_distance = "ddtw" # compare with "wddtw" by validationRaw lines 212 to 227Integration with scikit-learn
Aeon distances work with sklearn estimators:
from sklearn.neighbors import KNeighborsClassifier
from aeon.distances import dtw_pairwise_distance
# Precompute distance matrix
X_train_distances = dtw_pairwise_distance(X_train)
# Use with sklearn
clf = KNeighborsClassifier(metric='precomputed')
clf.fit(X_train_distances, y_train)
X_test_distances = dtw_pairwise_distance(X_test, X_train)
predictions = clf.predict(X_test_distances) # shape: test cases by train casesRaw lines 228 to 245Available Distance Functions
Get list of all available distances:
from aeon.distances import get_distance_function_names
print(get_distance_function_names())
# ['dtw', 'ddtw', 'wdtw', 'euclidean', 'erp', 'edr', ...]Retrieve specific distance function:
from aeon.distances import get_distance_function
distance_func = get_distance_function("dtw")
result = distance_func(x, y, window=0.1)Raw lines 246 to 264