dtwDist¶
- dtw.dtwDist(mx, my=None, **kwargs)¶
Compute a dissimilarity matrix
Compute the dissimilarity matrix between a set of single-variate timeseries.
Details
dtwDistcomputes a dissimilarity matrix, akin toscipy.spatial.distance.cdist, based on the Dynamic Time Warping definition of a distance between single-variate timeseries.The timeseries are stored as rows in the matrix argument
mx. In other words, ifmxis an N * T matrix,dtwDistwill build N * N ordered pairs of timeseries, perform the corresponding N * N [dtw()] alignments, and return all of the results in a matrix. Each of the timeseries is T elements long. Timeseries of different lengths can be passed as a list of 1-D arrays instead.dtwDistreturns a square matrix, rather than the condensed form returned byscipy.spatial.distance.pdist. This makes sense because in general the DTW “distance” is not symmetric (see e.g. asymmetric step patterns).- Parameters:
mx – numeric matrix, containing timeseries as rows, or a list of 1-D arrays
my – numeric matrix, containing timeseries as rows, or a list of 1-D arrays (for cross-distance). Defaults to
mx.**kwargs – arguments passed to the [dtw()] call
- Returns:
A matrix whose element
[i,j]holds the Dynamic Time Warp distancebetween row
i(query) ofmxand rowj(reference) ofmy, i.e.dtw(mx[i], my[j]).distance. Its shape is(len(mx), len(my)).
Notes
To convert a square dissimilarity matrix to the condensed form used by
scipy.cluster.hierarchy, use a suitable symmetrization strategy (see examples) and thenscipy.spatial.distance.squareform.Examples
>>> from dtw import * >>> import numpy as np
Symmetric step pattern => symmetric dissimilarity matrix
>>> m = np.tile(np.arange(1, 5), (3, 1)).T >>> dtwDist(m) array([[ 0., 5., 10., 15.], [ 5., 0., 5., 10.], [10., 5., 0., 5.], [15., 10., 5., 0.]])
Find the optimal warping _and_ scale factor at the same time. (There may be a better, analytic way)
Prepare a query and a reference
>>> query = np.sin(np.linspace(0, 4 * np.pi, 100)) >>> reference = np.cos(np.linspace(0, 4 * np.pi, 100))
Make a set of several references, scaled from 0 to 3 in .1 increments. Put them in a matrix, in rows
>>> scaleSet = np.arange(1, 31) / 10 >>> referenceSet = np.outer(1 / scaleSet, reference)
The query has to be made into a 1-row matrix. Perform all of the alignments at once, and normalize the result.
>>> distanceSet = dtwDist(query[np.newaxis, :], referenceSet)[0]
The optimal scale for the reference is close to 1.0
>>> scaleSet[np.argmin(scaleSet * distanceSet)] np.float64(1.1)
>>> import matplotlib.pyplot as plt >>> plt.plot(scaleSet, scaleSet * distanceSet, "o-")
Asymmetric step pattern: we can either disregard part of the pairs, or average with the transpose
>>> mm = np.random.default_rng(1).uniform(size=(4, 3)) >>> dm = dtwDist(mm, step_pattern=asymmetric)
Symmetrize by averaging:
>>> dms = (dm + dm.T) / 2
Check definition
>>> bool(dm[1, 0] == dtw(mm[1, :], mm[0, :], step_pattern=asymmetric).distance) True