sktime.dists_kernels.dtw._dtw_dtaidist 源代码

"""Dynamic time warping distance, from dtaidistance."""

__author__ = ["fkiraly"]

import numpy as np

from sktime.dists_kernels.base import BasePairwiseTransformerPanel


[文档]class DtwDtaidistUniv(BasePairwiseTransformerPanel): """Univariate dynamic time warping distance, from dtaidistance. Direct interface to ``dtaidistance.dtw.distance_matrix`` and ``dtaidistance.dtw.distance_matrix_fast``. This distance is specifically for univariate time series. While mathematically equivalent for using the multivariate ``DtwDtaidistMultiv`` for univariate data, this class uses a more efficient implementation and a different internal API. To specify an inner scalar distance, use ``DtwDtaidistMultiv`` with the ``inner_dist`` parameter set to the desired scalar distance. Parameters ---------- use_c: bool, optional, default=False Whether to use the faster C variant: ``True`` for C, ``False`` for Python. ``True`` requires a C compiled installation of ``dtaidistance``. * If False, uses ``dtaidistance.dtw.distance_matrix``. * If True, uses ``dtaidistance.dtw.distance_matrix_fast``. window : integer, optional, default=infinite Sakoe Chiba window width, from diagonal to boundary. Only allow for maximal shifts from the two diagonals smaller than this number. The maximally allowed warping, thus difference between indices i in series 1 and j in series 2, is thus |i-j| < 2*window + |len(s1) - len(s2)|. It includes the diagonal, meaning that Euclidean distance is obtained by setting ``window=1.`` If the two series are of equal length, this means that the band appearing on the cumulative cost matrix is of width 2*window-1. In other definitions of DTW this number may be referred to as the window instead. max_dist: float, optional, default=infinite Stop if the returned values will be larger than this value. max_step: float, optional, default=infinite Do not allow steps larger than this value. If the difference between two values in the two series is larger than this, thus if |s1[i]-s2[j]| > max_step, replace that value with infinity. max_length_diff: int, optional, default=infinite Return infinity if difference of length of two series is larger than this value. penalty: float, optional, default=0 Penalty to add if compression or expansion is applied psi: integer or 4-tuple of integers or none, optional, default=none Psi relaxation parameter (ignore start and end of matching). If psi is a single integer, it is used for both start and end relaxations for both series in a pair of series. If psi is a 4-tuple, it is used as the psi-relaxation for (begin series1, end series1, begin series2, end series2). Useful for cyclical series. use_pruning: bool, optional, default=False Prune values based on Euclidean distance. References ---------- .. [1] H. Sakoe, S. Chiba, "Dynamic programming algorithm optimization for spoken word recognition," IEEE Transactions on Acoustics, Speech and Signal Processing, vol. 26(1), pp. 43--49, 1978. """ _tags = { # packaging info # -------------- "authors": ["wannesm", "probberechts", "fkiraly"], # wannesm, probberechts credit for interfaced code "python_dependencies": ["dtaidistance"], # estimator type # -------------- "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" "symmetric": True, # all the distances are symmetric "capability:multivariate": False, # can estimator handle multivariate data? "capability:unequal_length": True, # can dist handle unequal length panels? "X_inner_mtype": "df-list", } def __init__( self, use_c=False, window=None, max_dist=None, max_step=None, max_length_diff=None, penalty=None, psi=None, use_pruning=False, ): self.window = window self.use_pruning = use_pruning self.max_dist = max_dist self.max_step = max_step self.max_length_diff = max_length_diff self.penalty = penalty self.psi = psi self.use_c = use_c super().__init__() self._dtai_params = self.get_params() def _transform(self, X, X2=None): """Compute distance/kernel matrix. Core logic Behaviour: returns pairwise distance/kernel matrix between samples in X and X2 if X2 is not passed, is equal to X if X/X2 is a pd.DataFrame and contains non-numeric columns, these are removed before computation Parameters ---------- X: list of pd.DataFrame of length n X2: list of pd.DataFrame of length m, optional default X2 = X Returns ------- distmat: np.array of shape [n, m] (i,j)-th entry contains distance/kernel between X.iloc[i] and X2.iloc[j] """ from dtaidistance.dtw import distance_matrix dtai_params = self._dtai_params if X2 is None: X_np = [x.values.flatten() for x in X] distmat = distance_matrix(X_np, **dtai_params) return distmat # else X2 is not none # and know X, X2 are lists of df # dtaidistance handles X2 via the "block" parameter, so we need to translate X_np = [x.values.flatten() for x in X] X2_np = [x.values.flatten() for x in X2] len_X = len(X) len_X2 = len(X2) block = ((0, len_X), (len_X, len_X + len_X2)) X_all = X_np + X2_np distmat = distance_matrix(X_all, block=block, **dtai_params) distmat_ss = distmat[:len_X, -len_X2:] return distmat_ss
[文档] @classmethod def get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. Parameters ---------- parameter_set : str, default="default" Name of the set of test parameters to return, for use in tests. If no special parameters are defined for a value, will return ``"default"`` set. There are currently no reserved values for distance/kernel transformers. Returns ------- params : dict or list of dict, default = {} Parameters to create testing instances of the class Each dict are parameters to construct an "interesting" test instance, i.e., ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test instance. ``create_test_instance`` uses the first (or only) dictionary in ``params`` """ params0 = {} # params1 = {"window": 1, "use_pruning": True, "max_length_diff": 1} params2 = {"penalty": 0.1, "psi": 2} # params1 seems to lead to a bug in the dtaidistance package # return [params0, params1, params2] return [params0, params2]
[文档]class DtwDtaidistMultiv(BasePairwiseTransformerPanel): """Multivariate dynamic time warping distance, from dtaidistance. Direct interface to ``dtaidistance.dtw_ndim.distance_matrix`` and ``dtaidistance.dtw_ndim.distance_matrix_fast``. This distance is covers multivariate data. For univariate data and the default euclidean distance, ``DtwDtaidistUniv`` is mathematically equivalent but may be more efficient. To specify the internal distance to be separate from squared euclidean, use ``AlignerDtwDtai`` inside a ``DistFromAligner``. Parameters ---------- use_c: bool, optional, default=False Whether to use the faster C variant: ``True`` for C, ``False`` for Python. ``True`` requires a C compiled installation of ``dtaidistance``. * If False, uses ``dtaidistance.dtw_ndim.distance_matrix``. * If True, uses ``dtaidistance.dtw_ndim.distance_matrix_fast``. window : integer, optional, default=infinite Sakoe Chiba window width, from diagonal to boundary. Only allow for maximal shifts from the two diagonals smaller than this number. The maximally allowed warping, thus difference between indices i in series 1 and j in series 2, is thus |i-j| < 2*window + |len(s1) - len(s2)|. It includes the diagonal, meaning that Euclidean distance is obtained by setting ``window=1.`` If the two series are of equal length, this means that the band appearing on the cumulative cost matrix is of width 2*window-1. In other definitions of DTW this number may be referred to as the window instead. max_dist: float, optional, default=infinite Stop if the returned values will be larger than this value. max_step: float, optional, default=infinite Do not allow steps larger than this value. If the difference between two values in the two series is larger than this, thus if |s1[i]-s2[j]| > max_step, replace that value with infinity. max_length_diff: int, optional, default=infinite Return infinity if difference of length of two series is larger than this value. penalty: float, optional, default=0 Penalty to add if compression or expansion is applied psi: integer or 4-tuple of integers or none, optional, default=none Psi relaxation parameter (ignore start and end of matching). If psi is a single integer, it is used for both start and end relaxations for both series in a pair of series. If psi is a 4-tuple, it is used as the psi-relaxation for (begin series1, end series1, begin series2, end series2). Useful for cyclical series. use_pruning: bool, optional, default=False Prune values based on Euclidean distance. References ---------- .. [1] H. Sakoe, S. Chiba, "Dynamic programming algorithm optimization for spoken word recognition," IEEE Transactions on Acoustics, Speech and Signal Processing, vol. 26(1), pp. 43--49, 1978. """ _tags = { # packaging info # -------------- "authors": ["wannesm", "probberechts", "fkiraly"], # wannesm, probberechts credit for interfaced code "python_dependencies": ["dtaidistance"], # estimator type # -------------- "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" "symmetric": True, # all the distances are symmetric "capability:multivariate": True, # can estimator handle multivariate data? "capability:unequal_length": True, # can dist handle unequal length panels? "X_inner_mtype": ["df-list", "numpy3D"], } def __init__( self, use_c=False, window=None, max_dist=None, max_step=None, max_length_diff=None, penalty=None, psi=None, use_pruning=False, ): self.window = window self.use_pruning = use_pruning self.max_dist = max_dist self.max_step = max_step self.max_length_diff = max_length_diff self.penalty = penalty self.psi = psi self.use_c = use_c super().__init__() self._dtai_params = self.get_params() def _transform(self, X, X2=None): """Compute distance/kernel matrix. Core logic Behaviour: returns pairwise distance/kernel matrix between samples in X and X2 if X2 is not passed, is equal to X if X/X2 is a pd.DataFrame and contains non-numeric columns, these are removed before computation Parameters ---------- X: list of pd.DataFrame of length n X2: list of pd.DataFrame of length m, optional default X2 = X Returns ------- distmat: np.array of shape [n, m] (i,j)-th entry contains distance/kernel between X.iloc[i] and X2.iloc[j] """ from dtaidistance.dtw_ndim import distance_matrix dtai_params = self._dtai_params if X2 is not None: len_X = len(X) len_X2 = len(X2) block = ((0, len_X), (len_X, len_X + len_X2)) dtai_params["block"] = block # if 3D numpy: # dtaidistance expects (instance, time, variable) # sktime expects (instance, variable, time) if isinstance(X, np.ndarray): X = np.swapaxes(X, 1, 2) # handle X2 - dtaidistance does this via the "block" parameter if X2 is not None: X2 = np.swapaxes(X2, 1, 2) X_all = np.concatenate((X, X2), axis=0) else: X_all = X else: # X is a list of df, because if X_inner_mtype options # for unequal length, dtaidistance expects # list of 2D arrays, (time, variable) # sktime list-of-df is (time, variable), but pandas # so al we need to do is coerce to numpy X = [x.values for x in X] # handle X2 - dtaidistance does this via the "block" parameter if X2 is not None: X2 = [x.values for x in X2] X_all = X + X2 else: X_all = X distmat = distance_matrix(X_all, **dtai_params) if X2 is None: return distmat # else, the matrix is for X_all, and we need to extract the submatrix # the matrix outside the block will contain nans distmat_ss = distmat[:len_X, -len_X2:] return distmat_ss
[文档] @classmethod def get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. Parameters ---------- parameter_set : str, default="default" Name of the set of test parameters to return, for use in tests. If no special parameters are defined for a value, will return ``"default"`` set. There are currently no reserved values for distance/kernel transformers. Returns ------- params : dict or list of dict, default = {} Parameters to create testing instances of the class Each dict are parameters to construct an "interesting" test instance, i.e., ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test instance. ``create_test_instance`` uses the first (or only) dictionary in ``params`` """ params0 = {} # params1 = {"window": 1, "use_pruning": True, "max_length_diff": 1} params2 = {"penalty": 0.1, "psi": 2} # params1 seems to lead to a bug in the dtaidistance package # return [params0, params1, params2] return [params0, params2]