Coverage for /usr/lib/python3/dist-packages/scipy/spatial/distance.py: 15%
656 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Distance computations (:mod:`scipy.spatial.distance`)
3=====================================================
5.. sectionauthor:: Damian Eads
7Function reference
8------------------
10Distance matrix computation from a collection of raw observation vectors
11stored in a rectangular array.
13.. autosummary::
14 :toctree: generated/
16 pdist -- pairwise distances between observation vectors.
17 cdist -- distances between two collections of observation vectors
18 squareform -- convert distance matrix to a condensed one and vice versa
19 directed_hausdorff -- directed Hausdorff distance between arrays
21Predicates for checking the validity of distance matrices, both
22condensed and redundant. Also contained in this module are functions
23for computing the number of observations in a distance matrix.
25.. autosummary::
26 :toctree: generated/
28 is_valid_dm -- checks for a valid distance matrix
29 is_valid_y -- checks for a valid condensed distance matrix
30 num_obs_dm -- # of observations in a distance matrix
31 num_obs_y -- # of observations in a condensed distance matrix
33Distance functions between two numeric vectors ``u`` and ``v``. Computing
34distances over a large collection of vectors is inefficient for these
35functions. Use ``pdist`` for this purpose.
37.. autosummary::
38 :toctree: generated/
40 braycurtis -- the Bray-Curtis distance.
41 canberra -- the Canberra distance.
42 chebyshev -- the Chebyshev distance.
43 cityblock -- the Manhattan distance.
44 correlation -- the Correlation distance.
45 cosine -- the Cosine distance.
46 euclidean -- the Euclidean distance.
47 jensenshannon -- the Jensen-Shannon distance.
48 mahalanobis -- the Mahalanobis distance.
49 minkowski -- the Minkowski distance.
50 seuclidean -- the normalized Euclidean distance.
51 sqeuclidean -- the squared Euclidean distance.
53Distance functions between two boolean vectors (representing sets) ``u`` and
54``v``. As in the case of numerical vectors, ``pdist`` is more efficient for
55computing the distances between all pairs.
57.. autosummary::
58 :toctree: generated/
60 dice -- the Dice dissimilarity.
61 hamming -- the Hamming distance.
62 jaccard -- the Jaccard distance.
63 kulczynski1 -- the Kulczynski 1 distance.
64 rogerstanimoto -- the Rogers-Tanimoto dissimilarity.
65 russellrao -- the Russell-Rao dissimilarity.
66 sokalmichener -- the Sokal-Michener dissimilarity.
67 sokalsneath -- the Sokal-Sneath dissimilarity.
68 yule -- the Yule dissimilarity.
70:func:`hamming` also operates over discrete numerical vectors.
71"""
73# Copyright (C) Damian Eads, 2007-2008. New BSD License.
75__all__ = [
76 'braycurtis',
77 'canberra',
78 'cdist',
79 'chebyshev',
80 'cityblock',
81 'correlation',
82 'cosine',
83 'dice',
84 'directed_hausdorff',
85 'euclidean',
86 'hamming',
87 'is_valid_dm',
88 'is_valid_y',
89 'jaccard',
90 'jensenshannon',
91 'kulczynski1',
92 'mahalanobis',
93 'minkowski',
94 'num_obs_dm',
95 'num_obs_y',
96 'pdist',
97 'rogerstanimoto',
98 'russellrao',
99 'seuclidean',
100 'sokalmichener',
101 'sokalsneath',
102 'sqeuclidean',
103 'squareform',
104 'yule'
105]
108import os
109import warnings
110import numpy as np
111import dataclasses
113from typing import Optional, Callable
115from functools import partial
116from scipy._lib._util import _asarray_validated
118from . import _distance_wrap
119from . import _hausdorff
120from ..linalg import norm
121from ..special import rel_entr
123from . import _distance_pybind
126def _extra_windows_error_checks(x, out, required_shape, **kwargs):
127 # TODO: remove this function when distutils
128 # build system is removed because pybind11 error
129 # handling should suffice per gh-18108
130 if os.name == "nt" and out is not None:
131 if out.shape != required_shape:
132 raise ValueError("Output array has incorrect shape.")
133 if not out.flags["C_CONTIGUOUS"]:
134 raise ValueError("Output array must be C-contiguous.")
135 if not np.can_cast(x.dtype, out.dtype):
136 raise ValueError("Wrong out dtype.")
137 if os.name == "nt" and "w" in kwargs:
138 w = kwargs["w"]
139 if w is not None:
140 if (w < 0).sum() > 0:
141 raise ValueError("Input weights should be all non-negative")
144def _copy_array_if_base_present(a):
145 """Copy the array if its base points to a parent array."""
146 if a.base is not None:
147 return a.copy()
148 return a
151def _correlation_cdist_wrap(XA, XB, dm, **kwargs):
152 XA = XA - XA.mean(axis=1, keepdims=True)
153 XB = XB - XB.mean(axis=1, keepdims=True)
154 _distance_wrap.cdist_cosine_double_wrap(XA, XB, dm, **kwargs)
157def _correlation_pdist_wrap(X, dm, **kwargs):
158 X2 = X - X.mean(axis=1, keepdims=True)
159 _distance_wrap.pdist_cosine_double_wrap(X2, dm, **kwargs)
162def _convert_to_type(X, out_type):
163 return np.ascontiguousarray(X, dtype=out_type)
166def _nbool_correspond_all(u, v, w=None):
167 if u.dtype == v.dtype == bool and w is None:
168 not_u = ~u
169 not_v = ~v
170 nff = (not_u & not_v).sum()
171 nft = (not_u & v).sum()
172 ntf = (u & not_v).sum()
173 ntt = (u & v).sum()
174 else:
175 dtype = np.result_type(int, u.dtype, v.dtype)
176 u = u.astype(dtype)
177 v = v.astype(dtype)
178 not_u = 1.0 - u
179 not_v = 1.0 - v
180 if w is not None:
181 not_u = w * not_u
182 u = w * u
183 nff = (not_u * not_v).sum()
184 nft = (not_u * v).sum()
185 ntf = (u * not_v).sum()
186 ntt = (u * v).sum()
187 return (nff, nft, ntf, ntt)
190def _nbool_correspond_ft_tf(u, v, w=None):
191 if u.dtype == v.dtype == bool and w is None:
192 not_u = ~u
193 not_v = ~v
194 nft = (not_u & v).sum()
195 ntf = (u & not_v).sum()
196 else:
197 dtype = np.result_type(int, u.dtype, v.dtype)
198 u = u.astype(dtype)
199 v = v.astype(dtype)
200 not_u = 1.0 - u
201 not_v = 1.0 - v
202 if w is not None:
203 not_u = w * not_u
204 u = w * u
205 nft = (not_u * v).sum()
206 ntf = (u * not_v).sum()
207 return (nft, ntf)
210def _validate_cdist_input(XA, XB, mA, mB, n, metric_info, **kwargs):
211 # get supported types
212 types = metric_info.types
213 # choose best type
214 typ = types[types.index(XA.dtype)] if XA.dtype in types else types[0]
215 # validate data
216 XA = _convert_to_type(XA, out_type=typ)
217 XB = _convert_to_type(XB, out_type=typ)
219 # validate kwargs
220 _validate_kwargs = metric_info.validator
221 if _validate_kwargs:
222 kwargs = _validate_kwargs((XA, XB), mA + mB, n, **kwargs)
223 return XA, XB, typ, kwargs
226def _validate_weight_with_size(X, m, n, **kwargs):
227 w = kwargs.pop('w', None)
228 if w is None:
229 return kwargs
231 if w.ndim != 1 or w.shape[0] != n:
232 raise ValueError("Weights must have same size as input vector. "
233 f"{w.shape[0]} vs. {n}")
235 kwargs['w'] = _validate_weights(w)
236 return kwargs
239def _validate_hamming_kwargs(X, m, n, **kwargs):
240 w = kwargs.get('w', np.ones((n,), dtype='double'))
242 if w.ndim != 1 or w.shape[0] != n:
243 raise ValueError("Weights must have same size as input vector. %d vs. %d" % (w.shape[0], n))
245 kwargs['w'] = _validate_weights(w)
246 return kwargs
249def _validate_mahalanobis_kwargs(X, m, n, **kwargs):
250 VI = kwargs.pop('VI', None)
251 if VI is None:
252 if m <= n:
253 # There are fewer observations than the dimension of
254 # the observations.
255 raise ValueError("The number of observations (%d) is too "
256 "small; the covariance matrix is "
257 "singular. For observations with %d "
258 "dimensions, at least %d observations "
259 "are required." % (m, n, n + 1))
260 if isinstance(X, tuple):
261 X = np.vstack(X)
262 CV = np.atleast_2d(np.cov(X.astype(np.double, copy=False).T))
263 VI = np.linalg.inv(CV).T.copy()
264 kwargs["VI"] = _convert_to_double(VI)
265 return kwargs
268def _validate_minkowski_kwargs(X, m, n, **kwargs):
269 kwargs = _validate_weight_with_size(X, m, n, **kwargs)
270 if 'p' not in kwargs:
271 kwargs['p'] = 2.
272 else:
273 if kwargs['p'] <= 0:
274 raise ValueError("p must be greater than 0")
276 return kwargs
279def _validate_pdist_input(X, m, n, metric_info, **kwargs):
280 # get supported types
281 types = metric_info.types
282 # choose best type
283 typ = types[types.index(X.dtype)] if X.dtype in types else types[0]
284 # validate data
285 X = _convert_to_type(X, out_type=typ)
287 # validate kwargs
288 _validate_kwargs = metric_info.validator
289 if _validate_kwargs:
290 kwargs = _validate_kwargs(X, m, n, **kwargs)
291 return X, typ, kwargs
294def _validate_seuclidean_kwargs(X, m, n, **kwargs):
295 V = kwargs.pop('V', None)
296 if V is None:
297 if isinstance(X, tuple):
298 X = np.vstack(X)
299 V = np.var(X.astype(np.double, copy=False), axis=0, ddof=1)
300 else:
301 V = np.asarray(V, order='c')
302 if len(V.shape) != 1:
303 raise ValueError('Variance vector V must '
304 'be one-dimensional.')
305 if V.shape[0] != n:
306 raise ValueError('Variance vector V must be of the same '
307 'dimension as the vectors on which the distances '
308 'are computed.')
309 kwargs['V'] = _convert_to_double(V)
310 return kwargs
313def _validate_vector(u, dtype=None):
314 # XXX Is order='c' really necessary?
315 u = np.asarray(u, dtype=dtype, order='c')
316 if u.ndim == 1:
317 return u
318 raise ValueError("Input vector should be 1-D.")
321def _validate_weights(w, dtype=np.double):
322 w = _validate_vector(w, dtype=dtype)
323 if np.any(w < 0):
324 raise ValueError("Input weights should be all non-negative")
325 return w
328def directed_hausdorff(u, v, seed=0):
329 """
330 Compute the directed Hausdorff distance between two 2-D arrays.
332 Distances between pairs are calculated using a Euclidean metric.
334 Parameters
335 ----------
336 u : (M,N) array_like
337 Input array.
338 v : (O,N) array_like
339 Input array.
340 seed : int or None
341 Local `numpy.random.RandomState` seed. Default is 0, a random
342 shuffling of u and v that guarantees reproducibility.
344 Returns
345 -------
346 d : double
347 The directed Hausdorff distance between arrays `u` and `v`,
349 index_1 : int
350 index of point contributing to Hausdorff pair in `u`
352 index_2 : int
353 index of point contributing to Hausdorff pair in `v`
355 Raises
356 ------
357 ValueError
358 An exception is thrown if `u` and `v` do not have
359 the same number of columns.
361 See Also
362 --------
363 scipy.spatial.procrustes : Another similarity test for two data sets
365 Notes
366 -----
367 Uses the early break technique and the random sampling approach
368 described by [1]_. Although worst-case performance is ``O(m * o)``
369 (as with the brute force algorithm), this is unlikely in practice
370 as the input data would have to require the algorithm to explore
371 every single point interaction, and after the algorithm shuffles
372 the input points at that. The best case performance is O(m), which
373 is satisfied by selecting an inner loop distance that is less than
374 cmax and leads to an early break as often as possible. The authors
375 have formally shown that the average runtime is closer to O(m).
377 .. versionadded:: 0.19.0
379 References
380 ----------
381 .. [1] A. A. Taha and A. Hanbury, "An efficient algorithm for
382 calculating the exact Hausdorff distance." IEEE Transactions On
383 Pattern Analysis And Machine Intelligence, vol. 37 pp. 2153-63,
384 2015.
386 Examples
387 --------
388 Find the directed Hausdorff distance between two 2-D arrays of
389 coordinates:
391 >>> from scipy.spatial.distance import directed_hausdorff
392 >>> import numpy as np
393 >>> u = np.array([(1.0, 0.0),
394 ... (0.0, 1.0),
395 ... (-1.0, 0.0),
396 ... (0.0, -1.0)])
397 >>> v = np.array([(2.0, 0.0),
398 ... (0.0, 2.0),
399 ... (-2.0, 0.0),
400 ... (0.0, -4.0)])
402 >>> directed_hausdorff(u, v)[0]
403 2.23606797749979
404 >>> directed_hausdorff(v, u)[0]
405 3.0
407 Find the general (symmetric) Hausdorff distance between two 2-D
408 arrays of coordinates:
410 >>> max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])
411 3.0
413 Find the indices of the points that generate the Hausdorff distance
414 (the Hausdorff pair):
416 >>> directed_hausdorff(v, u)[1:]
417 (3, 3)
419 """
420 u = np.asarray(u, dtype=np.float64, order='c')
421 v = np.asarray(v, dtype=np.float64, order='c')
422 if u.shape[1] != v.shape[1]:
423 raise ValueError('u and v need to have the same '
424 'number of columns')
425 result = _hausdorff.directed_hausdorff(u, v, seed)
426 return result
429def minkowski(u, v, p=2, w=None):
430 """
431 Compute the Minkowski distance between two 1-D arrays.
433 The Minkowski distance between 1-D arrays `u` and `v`,
434 is defined as
436 .. math::
438 {\\|u-v\\|}_p = (\\sum{|u_i - v_i|^p})^{1/p}.
441 \\left(\\sum{w_i(|(u_i - v_i)|^p)}\\right)^{1/p}.
443 Parameters
444 ----------
445 u : (N,) array_like
446 Input array.
447 v : (N,) array_like
448 Input array.
449 p : scalar
450 The order of the norm of the difference :math:`{\\|u-v\\|}_p`. Note
451 that for :math:`0 < p < 1`, the triangle inequality only holds with
452 an additional multiplicative factor, i.e. it is only a quasi-metric.
453 w : (N,) array_like, optional
454 The weights for each value in `u` and `v`. Default is None,
455 which gives each value a weight of 1.0
457 Returns
458 -------
459 minkowski : double
460 The Minkowski distance between vectors `u` and `v`.
462 Examples
463 --------
464 >>> from scipy.spatial import distance
465 >>> distance.minkowski([1, 0, 0], [0, 1, 0], 1)
466 2.0
467 >>> distance.minkowski([1, 0, 0], [0, 1, 0], 2)
468 1.4142135623730951
469 >>> distance.minkowski([1, 0, 0], [0, 1, 0], 3)
470 1.2599210498948732
471 >>> distance.minkowski([1, 1, 0], [0, 1, 0], 1)
472 1.0
473 >>> distance.minkowski([1, 1, 0], [0, 1, 0], 2)
474 1.0
475 >>> distance.minkowski([1, 1, 0], [0, 1, 0], 3)
476 1.0
478 """
479 u = _validate_vector(u)
480 v = _validate_vector(v)
481 if p <= 0:
482 raise ValueError("p must be greater than 0")
483 u_v = u - v
484 if w is not None:
485 w = _validate_weights(w)
486 if p == 1:
487 root_w = w
488 elif p == 2:
489 # better precision and speed
490 root_w = np.sqrt(w)
491 elif p == np.inf:
492 root_w = (w != 0)
493 else:
494 root_w = np.power(w, 1/p)
495 u_v = root_w * u_v
496 dist = norm(u_v, ord=p)
497 return dist
500def euclidean(u, v, w=None):
501 """
502 Computes the Euclidean distance between two 1-D arrays.
504 The Euclidean distance between 1-D arrays `u` and `v`, is defined as
506 .. math::
508 {\\|u-v\\|}_2
510 \\left(\\sum{(w_i |(u_i - v_i)|^2)}\\right)^{1/2}
512 Parameters
513 ----------
514 u : (N,) array_like
515 Input array.
516 v : (N,) array_like
517 Input array.
518 w : (N,) array_like, optional
519 The weights for each value in `u` and `v`. Default is None,
520 which gives each value a weight of 1.0
522 Returns
523 -------
524 euclidean : double
525 The Euclidean distance between vectors `u` and `v`.
527 Examples
528 --------
529 >>> from scipy.spatial import distance
530 >>> distance.euclidean([1, 0, 0], [0, 1, 0])
531 1.4142135623730951
532 >>> distance.euclidean([1, 1, 0], [0, 1, 0])
533 1.0
535 """
536 return minkowski(u, v, p=2, w=w)
539def sqeuclidean(u, v, w=None):
540 """
541 Compute the squared Euclidean distance between two 1-D arrays.
543 The squared Euclidean distance between `u` and `v` is defined as
545 .. math::
547 \\sum_i{w_i |u_i - v_i|^2}
549 Parameters
550 ----------
551 u : (N,) array_like
552 Input array.
553 v : (N,) array_like
554 Input array.
555 w : (N,) array_like, optional
556 The weights for each value in `u` and `v`. Default is None,
557 which gives each value a weight of 1.0
559 Returns
560 -------
561 sqeuclidean : double
562 The squared Euclidean distance between vectors `u` and `v`.
564 Examples
565 --------
566 >>> from scipy.spatial import distance
567 >>> distance.sqeuclidean([1, 0, 0], [0, 1, 0])
568 2.0
569 >>> distance.sqeuclidean([1, 1, 0], [0, 1, 0])
570 1.0
572 """
573 # Preserve float dtypes, but convert everything else to np.float64
574 # for stability.
575 utype, vtype = None, None
576 if not (hasattr(u, "dtype") and np.issubdtype(u.dtype, np.inexact)):
577 utype = np.float64
578 if not (hasattr(v, "dtype") and np.issubdtype(v.dtype, np.inexact)):
579 vtype = np.float64
581 u = _validate_vector(u, dtype=utype)
582 v = _validate_vector(v, dtype=vtype)
583 u_v = u - v
584 u_v_w = u_v # only want weights applied once
585 if w is not None:
586 w = _validate_weights(w)
587 u_v_w = w * u_v
588 return np.dot(u_v, u_v_w)
591def correlation(u, v, w=None, centered=True):
592 """
593 Compute the correlation distance between two 1-D arrays.
595 The correlation distance between `u` and `v`, is
596 defined as
598 .. math::
600 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
601 {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
603 where :math:`\\bar{u}` is the mean of the elements of `u`
604 and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
606 Parameters
607 ----------
608 u : (N,) array_like
609 Input array.
610 v : (N,) array_like
611 Input array.
612 w : (N,) array_like, optional
613 The weights for each value in `u` and `v`. Default is None,
614 which gives each value a weight of 1.0
615 centered : bool, optional
616 If True, `u` and `v` will be centered. Default is True.
618 Returns
619 -------
620 correlation : double
621 The correlation distance between 1-D array `u` and `v`.
623 """
624 u = _validate_vector(u)
625 v = _validate_vector(v)
626 if w is not None:
627 w = _validate_weights(w)
628 if centered:
629 umu = np.average(u, weights=w)
630 vmu = np.average(v, weights=w)
631 u = u - umu
632 v = v - vmu
633 uv = np.average(u * v, weights=w)
634 uu = np.average(np.square(u), weights=w)
635 vv = np.average(np.square(v), weights=w)
636 dist = 1.0 - uv / np.sqrt(uu * vv)
637 # Return absolute value to avoid small negative value due to rounding
638 return np.abs(dist)
641def cosine(u, v, w=None):
642 """
643 Compute the Cosine distance between 1-D arrays.
645 The Cosine distance between `u` and `v`, is defined as
647 .. math::
649 1 - \\frac{u \\cdot v}
650 {\\|u\\|_2 \\|v\\|_2}.
652 where :math:`u \\cdot v` is the dot product of :math:`u` and
653 :math:`v`.
655 Parameters
656 ----------
657 u : (N,) array_like
658 Input array.
659 v : (N,) array_like
660 Input array.
661 w : (N,) array_like, optional
662 The weights for each value in `u` and `v`. Default is None,
663 which gives each value a weight of 1.0
665 Returns
666 -------
667 cosine : double
668 The Cosine distance between vectors `u` and `v`.
670 Examples
671 --------
672 >>> from scipy.spatial import distance
673 >>> distance.cosine([1, 0, 0], [0, 1, 0])
674 1.0
675 >>> distance.cosine([100, 0, 0], [0, 1, 0])
676 1.0
677 >>> distance.cosine([1, 1, 0], [0, 1, 0])
678 0.29289321881345254
680 """
681 # cosine distance is also referred to as 'uncentered correlation',
682 # or 'reflective correlation'
683 # clamp the result to 0-2
684 return max(0, min(correlation(u, v, w=w, centered=False), 2.0))
687def hamming(u, v, w=None):
688 """
689 Compute the Hamming distance between two 1-D arrays.
691 The Hamming distance between 1-D arrays `u` and `v`, is simply the
692 proportion of disagreeing components in `u` and `v`. If `u` and `v` are
693 boolean vectors, the Hamming distance is
695 .. math::
697 \\frac{c_{01} + c_{10}}{n}
699 where :math:`c_{ij}` is the number of occurrences of
700 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
701 :math:`k < n`.
703 Parameters
704 ----------
705 u : (N,) array_like
706 Input array.
707 v : (N,) array_like
708 Input array.
709 w : (N,) array_like, optional
710 The weights for each value in `u` and `v`. Default is None,
711 which gives each value a weight of 1.0
713 Returns
714 -------
715 hamming : double
716 The Hamming distance between vectors `u` and `v`.
718 Examples
719 --------
720 >>> from scipy.spatial import distance
721 >>> distance.hamming([1, 0, 0], [0, 1, 0])
722 0.66666666666666663
723 >>> distance.hamming([1, 0, 0], [1, 1, 0])
724 0.33333333333333331
725 >>> distance.hamming([1, 0, 0], [2, 0, 0])
726 0.33333333333333331
727 >>> distance.hamming([1, 0, 0], [3, 0, 0])
728 0.33333333333333331
730 """
731 u = _validate_vector(u)
732 v = _validate_vector(v)
733 if u.shape != v.shape:
734 raise ValueError('The 1d arrays must have equal lengths.')
735 u_ne_v = u != v
736 if w is not None:
737 w = _validate_weights(w)
738 if w.shape != u.shape:
739 raise ValueError("'w' should have the same length as 'u' and 'v'.")
740 return np.average(u_ne_v, weights=w)
743def jaccard(u, v, w=None):
744 """
745 Compute the Jaccard-Needham dissimilarity between two boolean 1-D arrays.
747 The Jaccard-Needham dissimilarity between 1-D boolean arrays `u` and `v`,
748 is defined as
750 .. math::
752 \\frac{c_{TF} + c_{FT}}
753 {c_{TT} + c_{FT} + c_{TF}}
755 where :math:`c_{ij}` is the number of occurrences of
756 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
757 :math:`k < n`.
759 Parameters
760 ----------
761 u : (N,) array_like, bool
762 Input array.
763 v : (N,) array_like, bool
764 Input array.
765 w : (N,) array_like, optional
766 The weights for each value in `u` and `v`. Default is None,
767 which gives each value a weight of 1.0
769 Returns
770 -------
771 jaccard : double
772 The Jaccard distance between vectors `u` and `v`.
774 Notes
775 -----
776 When both `u` and `v` lead to a `0/0` division i.e. there is no overlap
777 between the items in the vectors the returned distance is 0. See the
778 Wikipedia page on the Jaccard index [1]_, and this paper [2]_.
780 .. versionchanged:: 1.2.0
781 Previously, when `u` and `v` lead to a `0/0` division, the function
782 would return NaN. This was changed to return 0 instead.
784 References
785 ----------
786 .. [1] https://en.wikipedia.org/wiki/Jaccard_index
787 .. [2] S. Kosub, "A note on the triangle inequality for the Jaccard
788 distance", 2016, :arxiv:`1612.02696`
790 Examples
791 --------
792 >>> from scipy.spatial import distance
793 >>> distance.jaccard([1, 0, 0], [0, 1, 0])
794 1.0
795 >>> distance.jaccard([1, 0, 0], [1, 1, 0])
796 0.5
797 >>> distance.jaccard([1, 0, 0], [1, 2, 0])
798 0.5
799 >>> distance.jaccard([1, 0, 0], [1, 1, 1])
800 0.66666666666666663
802 """
803 u = _validate_vector(u)
804 v = _validate_vector(v)
806 nonzero = np.bitwise_or(u != 0, v != 0)
807 unequal_nonzero = np.bitwise_and((u != v), nonzero)
808 if w is not None:
809 w = _validate_weights(w)
810 nonzero = w * nonzero
811 unequal_nonzero = w * unequal_nonzero
812 a = np.double(unequal_nonzero.sum())
813 b = np.double(nonzero.sum())
814 return (a / b) if b != 0 else 0
817def kulczynski1(u, v, *, w=None):
818 """
819 Compute the Kulczynski 1 dissimilarity between two boolean 1-D arrays.
821 The Kulczynski 1 dissimilarity between two boolean 1-D arrays `u` and `v`
822 of length ``n``, is defined as
824 .. math::
826 \\frac{c_{11}}
827 {c_{01} + c_{10}}
829 where :math:`c_{ij}` is the number of occurrences of
830 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
831 :math:`k \\in {0, 1, ..., n-1}`.
833 Parameters
834 ----------
835 u : (N,) array_like, bool
836 Input array.
837 v : (N,) array_like, bool
838 Input array.
839 w : (N,) array_like, optional
840 The weights for each value in `u` and `v`. Default is None,
841 which gives each value a weight of 1.0
843 Returns
844 -------
845 kulczynski1 : float
846 The Kulczynski 1 distance between vectors `u` and `v`.
848 Notes
849 -----
850 This measure has a minimum value of 0 and no upper limit.
851 It is un-defined when there are no non-matches.
853 .. versionadded:: 1.8.0
855 References
856 ----------
857 .. [1] Kulczynski S. et al. Bulletin
858 International de l'Academie Polonaise des Sciences
859 et des Lettres, Classe des Sciences Mathematiques
860 et Naturelles, Serie B (Sciences Naturelles). 1927;
861 Supplement II: 57-203.
863 Examples
864 --------
865 >>> from scipy.spatial import distance
866 >>> distance.kulczynski1([1, 0, 0], [0, 1, 0])
867 0.0
868 >>> distance.kulczynski1([True, False, False], [True, True, False])
869 1.0
870 >>> distance.kulczynski1([True, False, False], [True])
871 0.5
872 >>> distance.kulczynski1([1, 0, 0], [3, 1, 0])
873 -3.0
875 """
876 u = _validate_vector(u)
877 v = _validate_vector(v)
878 if w is not None:
879 w = _validate_weights(w)
880 (_, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
882 return ntt / (ntf + nft)
885def seuclidean(u, v, V):
886 """
887 Return the standardized Euclidean distance between two 1-D arrays.
889 The standardized Euclidean distance between two n-vectors `u` and `v` is
891 .. math::
893 \\sqrt{\\sum\\limits_i \\frac{1}{V_i} \\left(u_i-v_i \\right)^2}
895 ``V`` is the variance vector; ``V[I]`` is the variance computed over all the i-th
896 components of the points. If not passed, it is automatically computed.
898 Parameters
899 ----------
900 u : (N,) array_like
901 Input array.
902 v : (N,) array_like
903 Input array.
904 V : (N,) array_like
905 `V` is an 1-D array of component variances. It is usually computed
906 among a larger collection vectors.
908 Returns
909 -------
910 seuclidean : double
911 The standardized Euclidean distance between vectors `u` and `v`.
913 Examples
914 --------
915 >>> from scipy.spatial import distance
916 >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [0.1, 0.1, 0.1])
917 4.4721359549995796
918 >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [1, 0.1, 0.1])
919 3.3166247903553998
920 >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [10, 0.1, 0.1])
921 3.1780497164141406
923 """
924 u = _validate_vector(u)
925 v = _validate_vector(v)
926 V = _validate_vector(V, dtype=np.float64)
927 if V.shape[0] != u.shape[0] or u.shape[0] != v.shape[0]:
928 raise TypeError('V must be a 1-D array of the same dimension '
929 'as u and v.')
930 return euclidean(u, v, w=1/V)
933def cityblock(u, v, w=None):
934 """
935 Compute the City Block (Manhattan) distance.
937 Computes the Manhattan distance between two 1-D arrays `u` and `v`,
938 which is defined as
940 .. math::
942 \\sum_i {\\left| u_i - v_i \\right|}.
944 Parameters
945 ----------
946 u : (N,) array_like
947 Input array.
948 v : (N,) array_like
949 Input array.
950 w : (N,) array_like, optional
951 The weights for each value in `u` and `v`. Default is None,
952 which gives each value a weight of 1.0
954 Returns
955 -------
956 cityblock : double
957 The City Block (Manhattan) distance between vectors `u` and `v`.
959 Examples
960 --------
961 >>> from scipy.spatial import distance
962 >>> distance.cityblock([1, 0, 0], [0, 1, 0])
963 2
964 >>> distance.cityblock([1, 0, 0], [0, 2, 0])
965 3
966 >>> distance.cityblock([1, 0, 0], [1, 1, 0])
967 1
969 """
970 u = _validate_vector(u)
971 v = _validate_vector(v)
972 l1_diff = abs(u - v)
973 if w is not None:
974 w = _validate_weights(w)
975 l1_diff = w * l1_diff
976 return l1_diff.sum()
979def mahalanobis(u, v, VI):
980 """
981 Compute the Mahalanobis distance between two 1-D arrays.
983 The Mahalanobis distance between 1-D arrays `u` and `v`, is defined as
985 .. math::
987 \\sqrt{ (u-v) V^{-1} (u-v)^T }
989 where ``V`` is the covariance matrix. Note that the argument `VI`
990 is the inverse of ``V``.
992 Parameters
993 ----------
994 u : (N,) array_like
995 Input array.
996 v : (N,) array_like
997 Input array.
998 VI : array_like
999 The inverse of the covariance matrix.
1001 Returns
1002 -------
1003 mahalanobis : double
1004 The Mahalanobis distance between vectors `u` and `v`.
1006 Examples
1007 --------
1008 >>> from scipy.spatial import distance
1009 >>> iv = [[1, 0.5, 0.5], [0.5, 1, 0.5], [0.5, 0.5, 1]]
1010 >>> distance.mahalanobis([1, 0, 0], [0, 1, 0], iv)
1011 1.0
1012 >>> distance.mahalanobis([0, 2, 0], [0, 1, 0], iv)
1013 1.0
1014 >>> distance.mahalanobis([2, 0, 0], [0, 1, 0], iv)
1015 1.7320508075688772
1017 """
1018 u = _validate_vector(u)
1019 v = _validate_vector(v)
1020 VI = np.atleast_2d(VI)
1021 delta = u - v
1022 m = np.dot(np.dot(delta, VI), delta)
1023 return np.sqrt(m)
1026def chebyshev(u, v, w=None):
1027 """
1028 Compute the Chebyshev distance.
1030 Computes the Chebyshev distance between two 1-D arrays `u` and `v`,
1031 which is defined as
1033 .. math::
1035 \\max_i {|u_i-v_i|}.
1037 Parameters
1038 ----------
1039 u : (N,) array_like
1040 Input vector.
1041 v : (N,) array_like
1042 Input vector.
1043 w : (N,) array_like, optional
1044 Unused, as 'max' is a weightless operation. Here for API consistency.
1046 Returns
1047 -------
1048 chebyshev : double
1049 The Chebyshev distance between vectors `u` and `v`.
1051 Examples
1052 --------
1053 >>> from scipy.spatial import distance
1054 >>> distance.chebyshev([1, 0, 0], [0, 1, 0])
1055 1
1056 >>> distance.chebyshev([1, 1, 0], [0, 1, 0])
1057 1
1059 """
1060 u = _validate_vector(u)
1061 v = _validate_vector(v)
1062 if w is not None:
1063 w = _validate_weights(w)
1064 has_weight = w > 0
1065 if has_weight.sum() < w.size:
1066 u = u[has_weight]
1067 v = v[has_weight]
1068 return max(abs(u - v))
1071def braycurtis(u, v, w=None):
1072 """
1073 Compute the Bray-Curtis distance between two 1-D arrays.
1075 Bray-Curtis distance is defined as
1077 .. math::
1079 \\sum{|u_i-v_i|} / \\sum{|u_i+v_i|}
1081 The Bray-Curtis distance is in the range [0, 1] if all coordinates are
1082 positive, and is undefined if the inputs are of length zero.
1084 Parameters
1085 ----------
1086 u : (N,) array_like
1087 Input array.
1088 v : (N,) array_like
1089 Input array.
1090 w : (N,) array_like, optional
1091 The weights for each value in `u` and `v`. Default is None,
1092 which gives each value a weight of 1.0
1094 Returns
1095 -------
1096 braycurtis : double
1097 The Bray-Curtis distance between 1-D arrays `u` and `v`.
1099 Examples
1100 --------
1101 >>> from scipy.spatial import distance
1102 >>> distance.braycurtis([1, 0, 0], [0, 1, 0])
1103 1.0
1104 >>> distance.braycurtis([1, 1, 0], [0, 1, 0])
1105 0.33333333333333331
1107 """
1108 u = _validate_vector(u)
1109 v = _validate_vector(v, dtype=np.float64)
1110 l1_diff = abs(u - v)
1111 l1_sum = abs(u + v)
1112 if w is not None:
1113 w = _validate_weights(w)
1114 l1_diff = w * l1_diff
1115 l1_sum = w * l1_sum
1116 return l1_diff.sum() / l1_sum.sum()
1119def canberra(u, v, w=None):
1120 """
1121 Compute the Canberra distance between two 1-D arrays.
1123 The Canberra distance is defined as
1125 .. math::
1127 d(u,v) = \\sum_i \\frac{|u_i-v_i|}
1128 {|u_i|+|v_i|}.
1130 Parameters
1131 ----------
1132 u : (N,) array_like
1133 Input array.
1134 v : (N,) array_like
1135 Input array.
1136 w : (N,) array_like, optional
1137 The weights for each value in `u` and `v`. Default is None,
1138 which gives each value a weight of 1.0
1140 Returns
1141 -------
1142 canberra : double
1143 The Canberra distance between vectors `u` and `v`.
1145 Notes
1146 -----
1147 When `u[i]` and `v[i]` are 0 for given i, then the fraction 0/0 = 0 is
1148 used in the calculation.
1150 Examples
1151 --------
1152 >>> from scipy.spatial import distance
1153 >>> distance.canberra([1, 0, 0], [0, 1, 0])
1154 2.0
1155 >>> distance.canberra([1, 1, 0], [0, 1, 0])
1156 1.0
1158 """
1159 u = _validate_vector(u)
1160 v = _validate_vector(v, dtype=np.float64)
1161 if w is not None:
1162 w = _validate_weights(w)
1163 with np.errstate(invalid='ignore'):
1164 abs_uv = abs(u - v)
1165 abs_u = abs(u)
1166 abs_v = abs(v)
1167 d = abs_uv / (abs_u + abs_v)
1168 if w is not None:
1169 d = w * d
1170 d = np.nansum(d)
1171 return d
1174def jensenshannon(p, q, base=None, *, axis=0, keepdims=False):
1175 """
1176 Compute the Jensen-Shannon distance (metric) between
1177 two probability arrays. This is the square root
1178 of the Jensen-Shannon divergence.
1180 The Jensen-Shannon distance between two probability
1181 vectors `p` and `q` is defined as,
1183 .. math::
1185 \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
1187 where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
1188 and :math:`D` is the Kullback-Leibler divergence.
1190 This routine will normalize `p` and `q` if they don't sum to 1.0.
1192 Parameters
1193 ----------
1194 p : (N,) array_like
1195 left probability vector
1196 q : (N,) array_like
1197 right probability vector
1198 base : double, optional
1199 the base of the logarithm used to compute the output
1200 if not given, then the routine uses the default base of
1201 scipy.stats.entropy.
1202 axis : int, optional
1203 Axis along which the Jensen-Shannon distances are computed. The default
1204 is 0.
1206 .. versionadded:: 1.7.0
1207 keepdims : bool, optional
1208 If this is set to `True`, the reduced axes are left in the
1209 result as dimensions with size one. With this option,
1210 the result will broadcast correctly against the input array.
1211 Default is False.
1213 .. versionadded:: 1.7.0
1215 Returns
1216 -------
1217 js : double or ndarray
1218 The Jensen-Shannon distances between `p` and `q` along the `axis`.
1220 Notes
1221 -----
1223 .. versionadded:: 1.2.0
1225 Examples
1226 --------
1227 >>> from scipy.spatial import distance
1228 >>> import numpy as np
1229 >>> distance.jensenshannon([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], 2.0)
1230 1.0
1231 >>> distance.jensenshannon([1.0, 0.0], [0.5, 0.5])
1232 0.46450140402245893
1233 >>> distance.jensenshannon([1.0, 0.0, 0.0], [1.0, 0.0, 0.0])
1234 0.0
1235 >>> a = np.array([[1, 2, 3, 4],
1236 ... [5, 6, 7, 8],
1237 ... [9, 10, 11, 12]])
1238 >>> b = np.array([[13, 14, 15, 16],
1239 ... [17, 18, 19, 20],
1240 ... [21, 22, 23, 24]])
1241 >>> distance.jensenshannon(a, b, axis=0)
1242 array([0.1954288, 0.1447697, 0.1138377, 0.0927636])
1243 >>> distance.jensenshannon(a, b, axis=1)
1244 array([0.1402339, 0.0399106, 0.0201815])
1246 """
1247 p = np.asarray(p)
1248 q = np.asarray(q)
1249 p = p / np.sum(p, axis=axis, keepdims=True)
1250 q = q / np.sum(q, axis=axis, keepdims=True)
1251 m = (p + q) / 2.0
1252 left = rel_entr(p, m)
1253 right = rel_entr(q, m)
1254 left_sum = np.sum(left, axis=axis, keepdims=keepdims)
1255 right_sum = np.sum(right, axis=axis, keepdims=keepdims)
1256 js = left_sum + right_sum
1257 if base is not None:
1258 js /= np.log(base)
1259 return np.sqrt(js / 2.0)
1262def yule(u, v, w=None):
1263 """
1264 Compute the Yule dissimilarity between two boolean 1-D arrays.
1266 The Yule dissimilarity is defined as
1268 .. math::
1270 \\frac{R}{c_{TT} * c_{FF} + \\frac{R}{2}}
1272 where :math:`c_{ij}` is the number of occurrences of
1273 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1274 :math:`k < n` and :math:`R = 2.0 * c_{TF} * c_{FT}`.
1276 Parameters
1277 ----------
1278 u : (N,) array_like, bool
1279 Input array.
1280 v : (N,) array_like, bool
1281 Input array.
1282 w : (N,) array_like, optional
1283 The weights for each value in `u` and `v`. Default is None,
1284 which gives each value a weight of 1.0
1286 Returns
1287 -------
1288 yule : double
1289 The Yule dissimilarity between vectors `u` and `v`.
1291 Examples
1292 --------
1293 >>> from scipy.spatial import distance
1294 >>> distance.yule([1, 0, 0], [0, 1, 0])
1295 2.0
1296 >>> distance.yule([1, 1, 0], [0, 1, 0])
1297 0.0
1299 """
1300 u = _validate_vector(u)
1301 v = _validate_vector(v)
1302 if w is not None:
1303 w = _validate_weights(w)
1304 (nff, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
1305 half_R = ntf * nft
1306 if half_R == 0:
1307 return 0.0
1308 else:
1309 return float(2.0 * half_R / (ntt * nff + half_R))
1312def dice(u, v, w=None):
1313 """
1314 Compute the Dice dissimilarity between two boolean 1-D arrays.
1316 The Dice dissimilarity between `u` and `v`, is
1318 .. math::
1320 \\frac{c_{TF} + c_{FT}}
1321 {2c_{TT} + c_{FT} + c_{TF}}
1323 where :math:`c_{ij}` is the number of occurrences of
1324 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1325 :math:`k < n`.
1327 Parameters
1328 ----------
1329 u : (N,) array_like, bool
1330 Input 1-D array.
1331 v : (N,) array_like, bool
1332 Input 1-D array.
1333 w : (N,) array_like, optional
1334 The weights for each value in `u` and `v`. Default is None,
1335 which gives each value a weight of 1.0
1337 Returns
1338 -------
1339 dice : double
1340 The Dice dissimilarity between 1-D arrays `u` and `v`.
1342 Notes
1343 -----
1344 This function computes the Dice dissimilarity index. To compute the
1345 Dice similarity index, convert one to the other with similarity =
1346 1 - dissimilarity.
1348 Examples
1349 --------
1350 >>> from scipy.spatial import distance
1351 >>> distance.dice([1, 0, 0], [0, 1, 0])
1352 1.0
1353 >>> distance.dice([1, 0, 0], [1, 1, 0])
1354 0.3333333333333333
1355 >>> distance.dice([1, 0, 0], [2, 0, 0])
1356 -0.3333333333333333
1358 """
1359 u = _validate_vector(u)
1360 v = _validate_vector(v)
1361 if w is not None:
1362 w = _validate_weights(w)
1363 if u.dtype == v.dtype == bool and w is None:
1364 ntt = (u & v).sum()
1365 else:
1366 dtype = np.result_type(int, u.dtype, v.dtype)
1367 u = u.astype(dtype)
1368 v = v.astype(dtype)
1369 if w is None:
1370 ntt = (u * v).sum()
1371 else:
1372 ntt = (u * v * w).sum()
1373 (nft, ntf) = _nbool_correspond_ft_tf(u, v, w=w)
1374 return float((ntf + nft) / np.array(2.0 * ntt + ntf + nft))
1377def rogerstanimoto(u, v, w=None):
1378 """
1379 Compute the Rogers-Tanimoto dissimilarity between two boolean 1-D arrays.
1381 The Rogers-Tanimoto dissimilarity between two boolean 1-D arrays
1382 `u` and `v`, is defined as
1384 .. math::
1385 \\frac{R}
1386 {c_{TT} + c_{FF} + R}
1388 where :math:`c_{ij}` is the number of occurrences of
1389 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1390 :math:`k < n` and :math:`R = 2(c_{TF} + c_{FT})`.
1392 Parameters
1393 ----------
1394 u : (N,) array_like, bool
1395 Input array.
1396 v : (N,) array_like, bool
1397 Input array.
1398 w : (N,) array_like, optional
1399 The weights for each value in `u` and `v`. Default is None,
1400 which gives each value a weight of 1.0
1402 Returns
1403 -------
1404 rogerstanimoto : double
1405 The Rogers-Tanimoto dissimilarity between vectors
1406 `u` and `v`.
1408 Examples
1409 --------
1410 >>> from scipy.spatial import distance
1411 >>> distance.rogerstanimoto([1, 0, 0], [0, 1, 0])
1412 0.8
1413 >>> distance.rogerstanimoto([1, 0, 0], [1, 1, 0])
1414 0.5
1415 >>> distance.rogerstanimoto([1, 0, 0], [2, 0, 0])
1416 -1.0
1418 """
1419 u = _validate_vector(u)
1420 v = _validate_vector(v)
1421 if w is not None:
1422 w = _validate_weights(w)
1423 (nff, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
1424 return float(2.0 * (ntf + nft)) / float(ntt + nff + (2.0 * (ntf + nft)))
1427def russellrao(u, v, w=None):
1428 """
1429 Compute the Russell-Rao dissimilarity between two boolean 1-D arrays.
1431 The Russell-Rao dissimilarity between two boolean 1-D arrays, `u` and
1432 `v`, is defined as
1434 .. math::
1436 \\frac{n - c_{TT}}
1437 {n}
1439 where :math:`c_{ij}` is the number of occurrences of
1440 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1441 :math:`k < n`.
1443 Parameters
1444 ----------
1445 u : (N,) array_like, bool
1446 Input array.
1447 v : (N,) array_like, bool
1448 Input array.
1449 w : (N,) array_like, optional
1450 The weights for each value in `u` and `v`. Default is None,
1451 which gives each value a weight of 1.0
1453 Returns
1454 -------
1455 russellrao : double
1456 The Russell-Rao dissimilarity between vectors `u` and `v`.
1458 Examples
1459 --------
1460 >>> from scipy.spatial import distance
1461 >>> distance.russellrao([1, 0, 0], [0, 1, 0])
1462 1.0
1463 >>> distance.russellrao([1, 0, 0], [1, 1, 0])
1464 0.6666666666666666
1465 >>> distance.russellrao([1, 0, 0], [2, 0, 0])
1466 0.3333333333333333
1468 """
1469 u = _validate_vector(u)
1470 v = _validate_vector(v)
1471 if u.dtype == v.dtype == bool and w is None:
1472 ntt = (u & v).sum()
1473 n = float(len(u))
1474 elif w is None:
1475 ntt = (u * v).sum()
1476 n = float(len(u))
1477 else:
1478 w = _validate_weights(w)
1479 ntt = (u * v * w).sum()
1480 n = w.sum()
1481 return float(n - ntt) / n
1484def sokalmichener(u, v, w=None):
1485 """
1486 Compute the Sokal-Michener dissimilarity between two boolean 1-D arrays.
1488 The Sokal-Michener dissimilarity between boolean 1-D arrays `u` and `v`,
1489 is defined as
1491 .. math::
1493 \\frac{R}
1494 {S + R}
1496 where :math:`c_{ij}` is the number of occurrences of
1497 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1498 :math:`k < n`, :math:`R = 2 * (c_{TF} + c_{FT})` and
1499 :math:`S = c_{FF} + c_{TT}`.
1501 Parameters
1502 ----------
1503 u : (N,) array_like, bool
1504 Input array.
1505 v : (N,) array_like, bool
1506 Input array.
1507 w : (N,) array_like, optional
1508 The weights for each value in `u` and `v`. Default is None,
1509 which gives each value a weight of 1.0
1511 Returns
1512 -------
1513 sokalmichener : double
1514 The Sokal-Michener dissimilarity between vectors `u` and `v`.
1516 Examples
1517 --------
1518 >>> from scipy.spatial import distance
1519 >>> distance.sokalmichener([1, 0, 0], [0, 1, 0])
1520 0.8
1521 >>> distance.sokalmichener([1, 0, 0], [1, 1, 0])
1522 0.5
1523 >>> distance.sokalmichener([1, 0, 0], [2, 0, 0])
1524 -1.0
1526 """
1527 u = _validate_vector(u)
1528 v = _validate_vector(v)
1529 if w is not None:
1530 w = _validate_weights(w)
1531 nff, nft, ntf, ntt = _nbool_correspond_all(u, v, w=w)
1532 return float(2.0 * (ntf + nft)) / float(ntt + nff + 2.0 * (ntf + nft))
1535def sokalsneath(u, v, w=None):
1536 """
1537 Compute the Sokal-Sneath dissimilarity between two boolean 1-D arrays.
1539 The Sokal-Sneath dissimilarity between `u` and `v`,
1541 .. math::
1543 \\frac{R}
1544 {c_{TT} + R}
1546 where :math:`c_{ij}` is the number of occurrences of
1547 :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
1548 :math:`k < n` and :math:`R = 2(c_{TF} + c_{FT})`.
1550 Parameters
1551 ----------
1552 u : (N,) array_like, bool
1553 Input array.
1554 v : (N,) array_like, bool
1555 Input array.
1556 w : (N,) array_like, optional
1557 The weights for each value in `u` and `v`. Default is None,
1558 which gives each value a weight of 1.0
1560 Returns
1561 -------
1562 sokalsneath : double
1563 The Sokal-Sneath dissimilarity between vectors `u` and `v`.
1565 Examples
1566 --------
1567 >>> from scipy.spatial import distance
1568 >>> distance.sokalsneath([1, 0, 0], [0, 1, 0])
1569 1.0
1570 >>> distance.sokalsneath([1, 0, 0], [1, 1, 0])
1571 0.66666666666666663
1572 >>> distance.sokalsneath([1, 0, 0], [2, 1, 0])
1573 0.0
1574 >>> distance.sokalsneath([1, 0, 0], [3, 1, 0])
1575 -2.0
1577 """
1578 u = _validate_vector(u)
1579 v = _validate_vector(v)
1580 if u.dtype == v.dtype == bool and w is None:
1581 ntt = (u & v).sum()
1582 elif w is None:
1583 ntt = (u * v).sum()
1584 else:
1585 w = _validate_weights(w)
1586 ntt = (u * v * w).sum()
1587 (nft, ntf) = _nbool_correspond_ft_tf(u, v, w=w)
1588 denom = np.array(ntt + 2.0 * (ntf + nft))
1589 if not denom.any():
1590 raise ValueError('Sokal-Sneath dissimilarity is not defined for '
1591 'vectors that are entirely false.')
1592 return float(2.0 * (ntf + nft)) / denom
1595_convert_to_double = partial(_convert_to_type, out_type=np.double)
1596_convert_to_bool = partial(_convert_to_type, out_type=bool)
1598# adding python-only wrappers to _distance_wrap module
1599_distance_wrap.pdist_correlation_double_wrap = _correlation_pdist_wrap
1600_distance_wrap.cdist_correlation_double_wrap = _correlation_cdist_wrap
1603@dataclasses.dataclass(frozen=True)
1604class CDistMetricWrapper:
1605 metric_name: str
1607 def __call__(self, XA, XB, *, out=None, **kwargs):
1608 XA = np.ascontiguousarray(XA)
1609 XB = np.ascontiguousarray(XB)
1610 mA, n = XA.shape
1611 mB, _ = XB.shape
1612 metric_name = self.metric_name
1613 metric_info = _METRICS[metric_name]
1614 XA, XB, typ, kwargs = _validate_cdist_input(
1615 XA, XB, mA, mB, n, metric_info, **kwargs)
1617 w = kwargs.pop('w', None)
1618 if w is not None:
1619 metric = metric_info.dist_func
1620 return _cdist_callable(
1621 XA, XB, metric=metric, out=out, w=w, **kwargs)
1623 dm = _prepare_out_argument(out, np.double, (mA, mB))
1624 # get cdist wrapper
1625 cdist_fn = getattr(_distance_wrap, f'cdist_{metric_name}_{typ}_wrap')
1626 cdist_fn(XA, XB, dm, **kwargs)
1627 return dm
1630@dataclasses.dataclass(frozen=True)
1631class CDistWeightedMetricWrapper:
1632 metric_name: str
1633 weighted_metric: str
1635 def __call__(self, XA, XB, *, out=None, **kwargs):
1636 XA = np.ascontiguousarray(XA)
1637 XB = np.ascontiguousarray(XB)
1638 mA, n = XA.shape
1639 mB, _ = XB.shape
1640 metric_name = self.metric_name
1641 XA, XB, typ, kwargs = _validate_cdist_input(
1642 XA, XB, mA, mB, n, _METRICS[metric_name], **kwargs)
1643 dm = _prepare_out_argument(out, np.double, (mA, mB))
1645 w = kwargs.pop('w', None)
1646 if w is not None:
1647 metric_name = self.weighted_metric
1648 kwargs['w'] = w
1650 # get cdist wrapper
1651 cdist_fn = getattr(_distance_wrap, f'cdist_{metric_name}_{typ}_wrap')
1652 cdist_fn(XA, XB, dm, **kwargs)
1653 return dm
1656@dataclasses.dataclass(frozen=True)
1657class PDistMetricWrapper:
1658 metric_name: str
1660 def __call__(self, X, *, out=None, **kwargs):
1661 X = np.ascontiguousarray(X)
1662 m, n = X.shape
1663 metric_name = self.metric_name
1664 metric_info = _METRICS[metric_name]
1665 X, typ, kwargs = _validate_pdist_input(
1666 X, m, n, metric_info, **kwargs)
1667 out_size = (m * (m - 1)) // 2
1668 w = kwargs.pop('w', None)
1669 if w is not None:
1670 metric = metric_info.dist_func
1671 return _pdist_callable(
1672 X, metric=metric, out=out, w=w, **kwargs)
1674 dm = _prepare_out_argument(out, np.double, (out_size,))
1675 # get pdist wrapper
1676 pdist_fn = getattr(_distance_wrap, f'pdist_{metric_name}_{typ}_wrap')
1677 pdist_fn(X, dm, **kwargs)
1678 return dm
1681@dataclasses.dataclass(frozen=True)
1682class PDistWeightedMetricWrapper:
1683 metric_name: str
1684 weighted_metric: str
1686 def __call__(self, X, *, out=None, **kwargs):
1687 X = np.ascontiguousarray(X)
1688 m, n = X.shape
1689 metric_name = self.metric_name
1690 X, typ, kwargs = _validate_pdist_input(
1691 X, m, n, _METRICS[metric_name], **kwargs)
1692 out_size = (m * (m - 1)) // 2
1693 dm = _prepare_out_argument(out, np.double, (out_size,))
1695 w = kwargs.pop('w', None)
1696 if w is not None:
1697 metric_name = self.weighted_metric
1698 kwargs['w'] = w
1700 # get pdist wrapper
1701 pdist_fn = getattr(_distance_wrap, f'pdist_{metric_name}_{typ}_wrap')
1702 pdist_fn(X, dm, **kwargs)
1703 return dm
1706@dataclasses.dataclass(frozen=True)
1707class MetricInfo:
1708 # Name of python distance function
1709 canonical_name: str
1710 # All aliases, including canonical_name
1711 aka: set[str]
1712 # unvectorized distance function
1713 dist_func: Callable
1714 # Optimized cdist function
1715 cdist_func: Callable
1716 # Optimized pdist function
1717 pdist_func: Callable
1718 # function that checks kwargs and computes default values:
1719 # f(X, m, n, **kwargs)
1720 validator: Optional[Callable] = None
1721 # list of supported types:
1722 # X (pdist) and XA (cdist) are used to choose the type. if there is no
1723 # match the first type is used. Default double
1724 types: list[str] = dataclasses.field(default_factory=lambda: ['double'])
1725 # true if out array must be C-contiguous
1726 requires_contiguous_out: bool = True
1729# Registry of implemented metrics:
1730_METRIC_INFOS = [
1731 MetricInfo(
1732 canonical_name='braycurtis',
1733 aka={'braycurtis'},
1734 dist_func=braycurtis,
1735 cdist_func=_distance_pybind.cdist_braycurtis,
1736 pdist_func=_distance_pybind.pdist_braycurtis,
1737 ),
1738 MetricInfo(
1739 canonical_name='canberra',
1740 aka={'canberra'},
1741 dist_func=canberra,
1742 cdist_func=_distance_pybind.cdist_canberra,
1743 pdist_func=_distance_pybind.pdist_canberra,
1744 ),
1745 MetricInfo(
1746 canonical_name='chebyshev',
1747 aka={'chebychev', 'chebyshev', 'cheby', 'cheb', 'ch'},
1748 dist_func=chebyshev,
1749 cdist_func=_distance_pybind.cdist_chebyshev,
1750 pdist_func=_distance_pybind.pdist_chebyshev,
1751 ),
1752 MetricInfo(
1753 canonical_name='cityblock',
1754 aka={'cityblock', 'cblock', 'cb', 'c'},
1755 dist_func=cityblock,
1756 cdist_func=_distance_pybind.cdist_cityblock,
1757 pdist_func=_distance_pybind.pdist_cityblock,
1758 ),
1759 MetricInfo(
1760 canonical_name='correlation',
1761 aka={'correlation', 'co'},
1762 dist_func=correlation,
1763 cdist_func=CDistMetricWrapper('correlation'),
1764 pdist_func=PDistMetricWrapper('correlation'),
1765 ),
1766 MetricInfo(
1767 canonical_name='cosine',
1768 aka={'cosine', 'cos'},
1769 dist_func=cosine,
1770 cdist_func=CDistMetricWrapper('cosine'),
1771 pdist_func=PDistMetricWrapper('cosine'),
1772 ),
1773 MetricInfo(
1774 canonical_name='dice',
1775 aka={'dice'},
1776 types=['bool'],
1777 dist_func=dice,
1778 cdist_func=_distance_pybind.cdist_dice,
1779 pdist_func=_distance_pybind.pdist_dice,
1780 ),
1781 MetricInfo(
1782 canonical_name='euclidean',
1783 aka={'euclidean', 'euclid', 'eu', 'e'},
1784 dist_func=euclidean,
1785 cdist_func=_distance_pybind.cdist_euclidean,
1786 pdist_func=_distance_pybind.pdist_euclidean,
1787 ),
1788 MetricInfo(
1789 canonical_name='hamming',
1790 aka={'matching', 'hamming', 'hamm', 'ha', 'h'},
1791 types=['double', 'bool'],
1792 validator=_validate_hamming_kwargs,
1793 dist_func=hamming,
1794 cdist_func=_distance_pybind.cdist_hamming,
1795 pdist_func=_distance_pybind.pdist_hamming,
1796 ),
1797 MetricInfo(
1798 canonical_name='jaccard',
1799 aka={'jaccard', 'jacc', 'ja', 'j'},
1800 types=['double', 'bool'],
1801 dist_func=jaccard,
1802 cdist_func=_distance_pybind.cdist_jaccard,
1803 pdist_func=_distance_pybind.pdist_jaccard,
1804 ),
1805 MetricInfo(
1806 canonical_name='jensenshannon',
1807 aka={'jensenshannon', 'js'},
1808 dist_func=jensenshannon,
1809 cdist_func=CDistMetricWrapper('jensenshannon'),
1810 pdist_func=PDistMetricWrapper('jensenshannon'),
1811 ),
1812 MetricInfo(
1813 canonical_name='kulczynski1',
1814 aka={'kulczynski1'},
1815 types=['bool'],
1816 dist_func=kulczynski1,
1817 cdist_func=_distance_pybind.cdist_kulczynski1,
1818 pdist_func=_distance_pybind.pdist_kulczynski1,
1819 ),
1820 MetricInfo(
1821 canonical_name='mahalanobis',
1822 aka={'mahalanobis', 'mahal', 'mah'},
1823 validator=_validate_mahalanobis_kwargs,
1824 dist_func=mahalanobis,
1825 cdist_func=CDistMetricWrapper('mahalanobis'),
1826 pdist_func=PDistMetricWrapper('mahalanobis'),
1827 ),
1828 MetricInfo(
1829 canonical_name='minkowski',
1830 aka={'minkowski', 'mi', 'm', 'pnorm'},
1831 validator=_validate_minkowski_kwargs,
1832 dist_func=minkowski,
1833 cdist_func=_distance_pybind.cdist_minkowski,
1834 pdist_func=_distance_pybind.pdist_minkowski,
1835 ),
1836 MetricInfo(
1837 canonical_name='rogerstanimoto',
1838 aka={'rogerstanimoto'},
1839 types=['bool'],
1840 dist_func=rogerstanimoto,
1841 cdist_func=_distance_pybind.cdist_rogerstanimoto,
1842 pdist_func=_distance_pybind.pdist_rogerstanimoto,
1843 ),
1844 MetricInfo(
1845 canonical_name='russellrao',
1846 aka={'russellrao'},
1847 types=['bool'],
1848 dist_func=russellrao,
1849 cdist_func=_distance_pybind.cdist_russellrao,
1850 pdist_func=_distance_pybind.pdist_russellrao,
1851 ),
1852 MetricInfo(
1853 canonical_name='seuclidean',
1854 aka={'seuclidean', 'se', 's'},
1855 validator=_validate_seuclidean_kwargs,
1856 dist_func=seuclidean,
1857 cdist_func=CDistMetricWrapper('seuclidean'),
1858 pdist_func=PDistMetricWrapper('seuclidean'),
1859 ),
1860 MetricInfo(
1861 canonical_name='sokalmichener',
1862 aka={'sokalmichener'},
1863 types=['bool'],
1864 dist_func=sokalmichener,
1865 cdist_func=_distance_pybind.cdist_sokalmichener,
1866 pdist_func=_distance_pybind.pdist_sokalmichener,
1867 ),
1868 MetricInfo(
1869 canonical_name='sokalsneath',
1870 aka={'sokalsneath'},
1871 types=['bool'],
1872 dist_func=sokalsneath,
1873 cdist_func=_distance_pybind.cdist_sokalsneath,
1874 pdist_func=_distance_pybind.pdist_sokalsneath,
1875 ),
1876 MetricInfo(
1877 canonical_name='sqeuclidean',
1878 aka={'sqeuclidean', 'sqe', 'sqeuclid'},
1879 dist_func=sqeuclidean,
1880 cdist_func=_distance_pybind.cdist_sqeuclidean,
1881 pdist_func=_distance_pybind.pdist_sqeuclidean,
1882 ),
1883 MetricInfo(
1884 canonical_name='yule',
1885 aka={'yule'},
1886 types=['bool'],
1887 dist_func=yule,
1888 cdist_func=_distance_pybind.cdist_yule,
1889 pdist_func=_distance_pybind.pdist_yule,
1890 ),
1891]
1893_METRICS = {info.canonical_name: info for info in _METRIC_INFOS}
1894_METRIC_ALIAS = {alias: info
1895 for info in _METRIC_INFOS
1896 for alias in info.aka}
1898_METRICS_NAMES = list(_METRICS.keys())
1900_TEST_METRICS = {'test_' + info.canonical_name: info for info in _METRIC_INFOS}
1903def pdist(X, metric='euclidean', *, out=None, **kwargs):
1904 """
1905 Pairwise distances between observations in n-dimensional space.
1907 See Notes for common calling conventions.
1909 Parameters
1910 ----------
1911 X : array_like
1912 An m by n array of m original observations in an
1913 n-dimensional space.
1914 metric : str or function, optional
1915 The distance metric to use. The distance function can
1916 be 'braycurtis', 'canberra', 'chebyshev', 'cityblock',
1917 'correlation', 'cosine', 'dice', 'euclidean', 'hamming',
1918 'jaccard', 'jensenshannon', 'kulczynski1',
1919 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto',
1920 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath',
1921 'sqeuclidean', 'yule'.
1922 out : ndarray
1923 The output array.
1924 If not None, condensed distance matrix Y is stored in this array.
1925 **kwargs : dict, optional
1926 Extra arguments to `metric`: refer to each metric documentation for a
1927 list of all possible arguments.
1929 Some possible arguments:
1931 p : scalar
1932 The p-norm to apply for Minkowski, weighted and unweighted.
1933 Default: 2.
1935 w : ndarray
1936 The weight vector for metrics that support weights (e.g., Minkowski).
1938 V : ndarray
1939 The variance vector for standardized Euclidean.
1940 Default: var(X, axis=0, ddof=1)
1942 VI : ndarray
1943 The inverse of the covariance matrix for Mahalanobis.
1944 Default: inv(cov(X.T)).T
1946 Returns
1947 -------
1948 Y : ndarray
1949 Returns a condensed distance matrix Y. For each :math:`i` and :math:`j`
1950 (where :math:`i<j<m`),where m is the number of original observations.
1951 The metric ``dist(u=X[i], v=X[j])`` is computed and stored in entry ``m
1952 * i + j - ((i + 2) * (i + 1)) // 2``.
1954 See Also
1955 --------
1956 squareform : converts between condensed distance matrices and
1957 square distance matrices.
1959 Notes
1960 -----
1961 See ``squareform`` for information on how to calculate the index of
1962 this entry or to convert the condensed distance matrix to a
1963 redundant square matrix.
1965 The following are common calling conventions.
1967 1. ``Y = pdist(X, 'euclidean')``
1969 Computes the distance between m points using Euclidean distance
1970 (2-norm) as the distance metric between the points. The points
1971 are arranged as m n-dimensional row vectors in the matrix X.
1973 2. ``Y = pdist(X, 'minkowski', p=2.)``
1975 Computes the distances using the Minkowski distance
1976 :math:`\\|u-v\\|_p` (:math:`p`-norm) where :math:`p > 0` (note
1977 that this is only a quasi-metric if :math:`0 < p < 1`).
1979 3. ``Y = pdist(X, 'cityblock')``
1981 Computes the city block or Manhattan distance between the
1982 points.
1984 4. ``Y = pdist(X, 'seuclidean', V=None)``
1986 Computes the standardized Euclidean distance. The standardized
1987 Euclidean distance between two n-vectors ``u`` and ``v`` is
1989 .. math::
1991 \\sqrt{\\sum {(u_i-v_i)^2 / V[x_i]}}
1994 V is the variance vector; V[i] is the variance computed over all
1995 the i'th components of the points. If not passed, it is
1996 automatically computed.
1998 5. ``Y = pdist(X, 'sqeuclidean')``
2000 Computes the squared Euclidean distance :math:`\\|u-v\\|_2^2` between
2001 the vectors.
2003 6. ``Y = pdist(X, 'cosine')``
2005 Computes the cosine distance between vectors u and v,
2007 .. math::
2009 1 - \\frac{u \\cdot v}
2010 {{\\|u\\|}_2 {\\|v\\|}_2}
2012 where :math:`\\|*\\|_2` is the 2-norm of its argument ``*``, and
2013 :math:`u \\cdot v` is the dot product of ``u`` and ``v``.
2015 7. ``Y = pdist(X, 'correlation')``
2017 Computes the correlation distance between vectors u and v. This is
2019 .. math::
2021 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
2022 {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
2024 where :math:`\\bar{v}` is the mean of the elements of vector v,
2025 and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
2027 8. ``Y = pdist(X, 'hamming')``
2029 Computes the normalized Hamming distance, or the proportion of
2030 those vector elements between two n-vectors ``u`` and ``v``
2031 which disagree. To save memory, the matrix ``X`` can be of type
2032 boolean.
2034 9. ``Y = pdist(X, 'jaccard')``
2036 Computes the Jaccard distance between the points. Given two
2037 vectors, ``u`` and ``v``, the Jaccard distance is the
2038 proportion of those elements ``u[i]`` and ``v[i]`` that
2039 disagree.
2041 10. ``Y = pdist(X, 'jensenshannon')``
2043 Computes the Jensen-Shannon distance between two probability arrays.
2044 Given two probability vectors, :math:`p` and :math:`q`, the
2045 Jensen-Shannon distance is
2047 .. math::
2049 \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
2051 where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
2052 and :math:`D` is the Kullback-Leibler divergence.
2054 11. ``Y = pdist(X, 'chebyshev')``
2056 Computes the Chebyshev distance between the points. The
2057 Chebyshev distance between two n-vectors ``u`` and ``v`` is the
2058 maximum norm-1 distance between their respective elements. More
2059 precisely, the distance is given by
2061 .. math::
2063 d(u,v) = \\max_i {|u_i-v_i|}
2065 12. ``Y = pdist(X, 'canberra')``
2067 Computes the Canberra distance between the points. The
2068 Canberra distance between two points ``u`` and ``v`` is
2070 .. math::
2072 d(u,v) = \\sum_i \\frac{|u_i-v_i|}
2073 {|u_i|+|v_i|}
2076 13. ``Y = pdist(X, 'braycurtis')``
2078 Computes the Bray-Curtis distance between the points. The
2079 Bray-Curtis distance between two points ``u`` and ``v`` is
2082 .. math::
2084 d(u,v) = \\frac{\\sum_i {|u_i-v_i|}}
2085 {\\sum_i {|u_i+v_i|}}
2087 14. ``Y = pdist(X, 'mahalanobis', VI=None)``
2089 Computes the Mahalanobis distance between the points. The
2090 Mahalanobis distance between two points ``u`` and ``v`` is
2091 :math:`\\sqrt{(u-v)(1/V)(u-v)^T}` where :math:`(1/V)` (the ``VI``
2092 variable) is the inverse covariance. If ``VI`` is not None,
2093 ``VI`` will be used as the inverse covariance matrix.
2095 15. ``Y = pdist(X, 'yule')``
2097 Computes the Yule distance between each pair of boolean
2098 vectors. (see yule function documentation)
2100 16. ``Y = pdist(X, 'matching')``
2102 Synonym for 'hamming'.
2104 17. ``Y = pdist(X, 'dice')``
2106 Computes the Dice distance between each pair of boolean
2107 vectors. (see dice function documentation)
2109 18. ``Y = pdist(X, 'kulczynski1')``
2111 Computes the kulczynski1 distance between each pair of
2112 boolean vectors. (see kulczynski1 function documentation)
2114 19. ``Y = pdist(X, 'rogerstanimoto')``
2116 Computes the Rogers-Tanimoto distance between each pair of
2117 boolean vectors. (see rogerstanimoto function documentation)
2119 20. ``Y = pdist(X, 'russellrao')``
2121 Computes the Russell-Rao distance between each pair of
2122 boolean vectors. (see russellrao function documentation)
2124 21. ``Y = pdist(X, 'sokalmichener')``
2126 Computes the Sokal-Michener distance between each pair of
2127 boolean vectors. (see sokalmichener function documentation)
2129 22. ``Y = pdist(X, 'sokalsneath')``
2131 Computes the Sokal-Sneath distance between each pair of
2132 boolean vectors. (see sokalsneath function documentation)
2134 23. ``Y = pdist(X, 'kulczynski1')``
2136 Computes the Kulczynski 1 distance between each pair of
2137 boolean vectors. (see kulczynski1 function documentation)
2139 24. ``Y = pdist(X, f)``
2141 Computes the distance between all pairs of vectors in X
2142 using the user supplied 2-arity function f. For example,
2143 Euclidean distance between the vectors could be computed
2144 as follows::
2146 dm = pdist(X, lambda u, v: np.sqrt(((u-v)**2).sum()))
2148 Note that you should avoid passing a reference to one of
2149 the distance functions defined in this library. For example,::
2151 dm = pdist(X, sokalsneath)
2153 would calculate the pair-wise distances between the vectors in
2154 X using the Python function sokalsneath. This would result in
2155 sokalsneath being called :math:`{n \\choose 2}` times, which
2156 is inefficient. Instead, the optimized C version is more
2157 efficient, and we call it using the following syntax.::
2159 dm = pdist(X, 'sokalsneath')
2161 Examples
2162 --------
2163 >>> import numpy as np
2164 >>> from scipy.spatial.distance import pdist
2166 ``x`` is an array of five points in three-dimensional space.
2168 >>> x = np.array([[2, 0, 2], [2, 2, 3], [-2, 4, 5], [0, 1, 9], [2, 2, 4]])
2170 ``pdist(x)`` with no additional arguments computes the 10 pairwise
2171 Euclidean distances:
2173 >>> pdist(x)
2174 array([2.23606798, 6.40312424, 7.34846923, 2.82842712, 4.89897949,
2175 6.40312424, 1. , 5.38516481, 4.58257569, 5.47722558])
2177 The following computes the pairwise Minkowski distances with ``p = 3.5``:
2179 >>> pdist(x, metric='minkowski', p=3.5)
2180 array([2.04898923, 5.1154929 , 7.02700737, 2.43802731, 4.19042714,
2181 6.03956994, 1. , 4.45128103, 4.10636143, 5.0619695 ])
2183 The pairwise city block or Manhattan distances:
2185 >>> pdist(x, metric='cityblock')
2186 array([ 3., 11., 10., 4., 8., 9., 1., 9., 7., 8.])
2188 """
2189 # You can also call this as:
2190 # Y = pdist(X, 'test_abc')
2191 # where 'abc' is the metric being tested. This computes the distance
2192 # between all pairs of vectors in X using the distance metric 'abc' but
2193 # with a more succinct, verifiable, but less efficient implementation.
2195 X = _asarray_validated(X, sparse_ok=False, objects_ok=True, mask_ok=True,
2196 check_finite=False)
2198 s = X.shape
2199 if len(s) != 2:
2200 raise ValueError('A 2-dimensional array must be passed.')
2202 m, n = s
2204 if callable(metric):
2205 mstr = getattr(metric, '__name__', 'UnknownCustomMetric')
2206 metric_info = _METRIC_ALIAS.get(mstr, None)
2208 if metric_info is not None:
2209 X, typ, kwargs = _validate_pdist_input(
2210 X, m, n, metric_info, **kwargs)
2212 return _pdist_callable(X, metric=metric, out=out, **kwargs)
2213 elif isinstance(metric, str):
2214 mstr = metric.lower()
2215 metric_info = _METRIC_ALIAS.get(mstr, None)
2217 if metric_info is not None:
2218 pdist_fn = metric_info.pdist_func
2219 _extra_windows_error_checks(X, out, (m * (m - 1) / 2,), **kwargs)
2220 return pdist_fn(X, out=out, **kwargs)
2221 elif mstr.startswith("test_"):
2222 metric_info = _TEST_METRICS.get(mstr, None)
2223 if metric_info is None:
2224 raise ValueError(f'Unknown "Test" Distance Metric: {mstr[5:]}')
2225 X, typ, kwargs = _validate_pdist_input(
2226 X, m, n, metric_info, **kwargs)
2227 return _pdist_callable(
2228 X, metric=metric_info.dist_func, out=out, **kwargs)
2229 else:
2230 raise ValueError('Unknown Distance Metric: %s' % mstr)
2231 else:
2232 raise TypeError('2nd argument metric must be a string identifier '
2233 'or a function.')
2236def squareform(X, force="no", checks=True):
2237 """
2238 Convert a vector-form distance vector to a square-form distance
2239 matrix, and vice-versa.
2241 Parameters
2242 ----------
2243 X : array_like
2244 Either a condensed or redundant distance matrix.
2245 force : str, optional
2246 As with MATLAB(TM), if force is equal to ``'tovector'`` or
2247 ``'tomatrix'``, the input will be treated as a distance matrix or
2248 distance vector respectively.
2249 checks : bool, optional
2250 If set to False, no checks will be made for matrix
2251 symmetry nor zero diagonals. This is useful if it is known that
2252 ``X - X.T1`` is small and ``diag(X)`` is close to zero.
2253 These values are ignored any way so they do not disrupt the
2254 squareform transformation.
2256 Returns
2257 -------
2258 Y : ndarray
2259 If a condensed distance matrix is passed, a redundant one is
2260 returned, or if a redundant one is passed, a condensed distance
2261 matrix is returned.
2263 Notes
2264 -----
2265 1. ``v = squareform(X)``
2267 Given a square n-by-n symmetric distance matrix ``X``,
2268 ``v = squareform(X)`` returns a ``n * (n-1) / 2``
2269 (i.e. binomial coefficient n choose 2) sized vector `v`
2270 where :math:`v[{n \\choose 2} - {n-i \\choose 2} + (j-i-1)]`
2271 is the distance between distinct points ``i`` and ``j``.
2272 If ``X`` is non-square or asymmetric, an error is raised.
2274 2. ``X = squareform(v)``
2276 Given a ``n * (n-1) / 2`` sized vector ``v``
2277 for some integer ``n >= 1`` encoding distances as described,
2278 ``X = squareform(v)`` returns a n-by-n distance matrix ``X``.
2279 The ``X[i, j]`` and ``X[j, i]`` values are set to
2280 :math:`v[{n \\choose 2} - {n-i \\choose 2} + (j-i-1)]`
2281 and all diagonal elements are zero.
2283 In SciPy 0.19.0, ``squareform`` stopped casting all input types to
2284 float64, and started returning arrays of the same dtype as the input.
2286 Examples
2287 --------
2288 >>> import numpy as np
2289 >>> from scipy.spatial.distance import pdist, squareform
2291 ``x`` is an array of five points in three-dimensional space.
2293 >>> x = np.array([[2, 0, 2], [2, 2, 3], [-2, 4, 5], [0, 1, 9], [2, 2, 4]])
2295 ``pdist(x)`` computes the Euclidean distances between each pair of
2296 points in ``x``. The distances are returned in a one-dimensional
2297 array with length ``5*(5 - 1)/2 = 10``.
2299 >>> distvec = pdist(x)
2300 >>> distvec
2301 array([2.23606798, 6.40312424, 7.34846923, 2.82842712, 4.89897949,
2302 6.40312424, 1. , 5.38516481, 4.58257569, 5.47722558])
2304 ``squareform(distvec)`` returns the 5x5 distance matrix.
2306 >>> m = squareform(distvec)
2307 >>> m
2308 array([[0. , 2.23606798, 6.40312424, 7.34846923, 2.82842712],
2309 [2.23606798, 0. , 4.89897949, 6.40312424, 1. ],
2310 [6.40312424, 4.89897949, 0. , 5.38516481, 4.58257569],
2311 [7.34846923, 6.40312424, 5.38516481, 0. , 5.47722558],
2312 [2.82842712, 1. , 4.58257569, 5.47722558, 0. ]])
2314 When given a square distance matrix ``m``, ``squareform(m)`` returns
2315 the one-dimensional condensed distance vector associated with the
2316 matrix. In this case, we recover ``distvec``.
2318 >>> squareform(m)
2319 array([2.23606798, 6.40312424, 7.34846923, 2.82842712, 4.89897949,
2320 6.40312424, 1. , 5.38516481, 4.58257569, 5.47722558])
2321 """
2322 X = np.ascontiguousarray(X)
2324 s = X.shape
2326 if force.lower() == 'tomatrix':
2327 if len(s) != 1:
2328 raise ValueError("Forcing 'tomatrix' but input X is not a "
2329 "distance vector.")
2330 elif force.lower() == 'tovector':
2331 if len(s) != 2:
2332 raise ValueError("Forcing 'tovector' but input X is not a "
2333 "distance matrix.")
2335 # X = squareform(v)
2336 if len(s) == 1:
2337 if s[0] == 0:
2338 return np.zeros((1, 1), dtype=X.dtype)
2340 # Grab the closest value to the square root of the number
2341 # of elements times 2 to see if the number of elements
2342 # is indeed a binomial coefficient.
2343 d = int(np.ceil(np.sqrt(s[0] * 2)))
2345 # Check that v is of valid dimensions.
2346 if d * (d - 1) != s[0] * 2:
2347 raise ValueError('Incompatible vector size. It must be a binomial '
2348 'coefficient n choose 2 for some integer n >= 2.')
2350 # Allocate memory for the distance matrix.
2351 M = np.zeros((d, d), dtype=X.dtype)
2353 # Since the C code does not support striding using strides.
2354 # The dimensions are used instead.
2355 X = _copy_array_if_base_present(X)
2357 # Fill in the values of the distance matrix.
2358 _distance_wrap.to_squareform_from_vector_wrap(M, X)
2360 # Return the distance matrix.
2361 return M
2362 elif len(s) == 2:
2363 if s[0] != s[1]:
2364 raise ValueError('The matrix argument must be square.')
2365 if checks:
2366 is_valid_dm(X, throw=True, name='X')
2368 # One-side of the dimensions is set here.
2369 d = s[0]
2371 if d <= 1:
2372 return np.array([], dtype=X.dtype)
2374 # Create a vector.
2375 v = np.zeros((d * (d - 1)) // 2, dtype=X.dtype)
2377 # Since the C code does not support striding using strides.
2378 # The dimensions are used instead.
2379 X = _copy_array_if_base_present(X)
2381 # Convert the vector to squareform.
2382 _distance_wrap.to_vector_from_squareform_wrap(X, v)
2383 return v
2384 else:
2385 raise ValueError(('The first argument must be one or two dimensional '
2386 'array. A %d-dimensional array is not '
2387 'permitted') % len(s))
2390def is_valid_dm(D, tol=0.0, throw=False, name="D", warning=False):
2391 """
2392 Return True if input array is a valid distance matrix.
2394 Distance matrices must be 2-dimensional numpy arrays.
2395 They must have a zero-diagonal, and they must be symmetric.
2397 Parameters
2398 ----------
2399 D : array_like
2400 The candidate object to test for validity.
2401 tol : float, optional
2402 The distance matrix should be symmetric. `tol` is the maximum
2403 difference between entries ``ij`` and ``ji`` for the distance
2404 metric to be considered symmetric.
2405 throw : bool, optional
2406 An exception is thrown if the distance matrix passed is not valid.
2407 name : str, optional
2408 The name of the variable to checked. This is useful if
2409 throw is set to True so the offending variable can be identified
2410 in the exception message when an exception is thrown.
2411 warning : bool, optional
2412 Instead of throwing an exception, a warning message is
2413 raised.
2415 Returns
2416 -------
2417 valid : bool
2418 True if the variable `D` passed is a valid distance matrix.
2420 Notes
2421 -----
2422 Small numerical differences in `D` and `D.T` and non-zeroness of
2423 the diagonal are ignored if they are within the tolerance specified
2424 by `tol`.
2426 Examples
2427 --------
2428 >>> import numpy as np
2429 >>> from scipy.spatial.distance import is_valid_dm
2431 This matrix is a valid distance matrix.
2433 >>> d = np.array([[0.0, 1.1, 1.2, 1.3],
2434 ... [1.1, 0.0, 1.0, 1.4],
2435 ... [1.2, 1.0, 0.0, 1.5],
2436 ... [1.3, 1.4, 1.5, 0.0]])
2437 >>> is_valid_dm(d)
2438 True
2440 In the following examples, the input is not a valid distance matrix.
2442 Not square:
2444 >>> is_valid_dm([[0, 2, 2], [2, 0, 2]])
2445 False
2447 Nonzero diagonal element:
2449 >>> is_valid_dm([[0, 1, 1], [1, 2, 3], [1, 3, 0]])
2450 False
2452 Not symmetric:
2454 >>> is_valid_dm([[0, 1, 3], [2, 0, 1], [3, 1, 0]])
2455 False
2457 """
2458 D = np.asarray(D, order='c')
2459 valid = True
2460 try:
2461 s = D.shape
2462 if len(D.shape) != 2:
2463 if name:
2464 raise ValueError(('Distance matrix \'%s\' must have shape=2 '
2465 '(i.e. be two-dimensional).') % name)
2466 else:
2467 raise ValueError('Distance matrix must have shape=2 (i.e. '
2468 'be two-dimensional).')
2469 if tol == 0.0:
2470 if not (D == D.T).all():
2471 if name:
2472 raise ValueError(('Distance matrix \'%s\' must be '
2473 'symmetric.') % name)
2474 else:
2475 raise ValueError('Distance matrix must be symmetric.')
2476 if not (D[range(0, s[0]), range(0, s[0])] == 0).all():
2477 if name:
2478 raise ValueError(('Distance matrix \'%s\' diagonal must '
2479 'be zero.') % name)
2480 else:
2481 raise ValueError('Distance matrix diagonal must be zero.')
2482 else:
2483 if not (D - D.T <= tol).all():
2484 if name:
2485 raise ValueError(('Distance matrix \'%s\' must be '
2486 'symmetric within tolerance %5.5f.')
2487 % (name, tol))
2488 else:
2489 raise ValueError('Distance matrix must be symmetric within'
2490 ' tolerance %5.5f.' % tol)
2491 if not (D[range(0, s[0]), range(0, s[0])] <= tol).all():
2492 if name:
2493 raise ValueError(('Distance matrix \'%s\' diagonal must be'
2494 ' close to zero within tolerance %5.5f.')
2495 % (name, tol))
2496 else:
2497 raise ValueError(('Distance matrix \'%s\' diagonal must be'
2498 ' close to zero within tolerance %5.5f.')
2499 % tol)
2500 except Exception as e:
2501 if throw:
2502 raise
2503 if warning:
2504 warnings.warn(str(e))
2505 valid = False
2506 return valid
2509def is_valid_y(y, warning=False, throw=False, name=None):
2510 """
2511 Return True if the input array is a valid condensed distance matrix.
2513 Condensed distance matrices must be 1-dimensional numpy arrays.
2514 Their length must be a binomial coefficient :math:`{n \\choose 2}`
2515 for some positive integer n.
2517 Parameters
2518 ----------
2519 y : array_like
2520 The condensed distance matrix.
2521 warning : bool, optional
2522 Invokes a warning if the variable passed is not a valid
2523 condensed distance matrix. The warning message explains why
2524 the distance matrix is not valid. `name` is used when
2525 referencing the offending variable.
2526 throw : bool, optional
2527 Throws an exception if the variable passed is not a valid
2528 condensed distance matrix.
2529 name : bool, optional
2530 Used when referencing the offending variable in the
2531 warning or exception message.
2533 Returns
2534 -------
2535 bool
2536 True if the input array is a valid condensed distance matrix,
2537 False otherwise.
2539 Examples
2540 --------
2541 >>> from scipy.spatial.distance import is_valid_y
2543 This vector is a valid condensed distance matrix. The length is 6,
2544 which corresponds to ``n = 4``, since ``4*(4 - 1)/2`` is 6.
2546 >>> v = [1.0, 1.2, 1.0, 0.5, 1.3, 0.9]
2547 >>> is_valid_y(v)
2548 True
2550 An input vector with length, say, 7, is not a valid condensed distance
2551 matrix.
2553 >>> is_valid_y([1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7])
2554 False
2556 """
2557 y = np.asarray(y, order='c')
2558 valid = True
2559 try:
2560 if len(y.shape) != 1:
2561 if name:
2562 raise ValueError(('Condensed distance matrix \'%s\' must '
2563 'have shape=1 (i.e. be one-dimensional).')
2564 % name)
2565 else:
2566 raise ValueError('Condensed distance matrix must have shape=1 '
2567 '(i.e. be one-dimensional).')
2568 n = y.shape[0]
2569 d = int(np.ceil(np.sqrt(n * 2)))
2570 if (d * (d - 1) / 2) != n:
2571 if name:
2572 raise ValueError(('Length n of condensed distance matrix '
2573 '\'%s\' must be a binomial coefficient, i.e.'
2574 'there must be a k such that '
2575 '(k \\choose 2)=n)!') % name)
2576 else:
2577 raise ValueError('Length n of condensed distance matrix must '
2578 'be a binomial coefficient, i.e. there must '
2579 'be a k such that (k \\choose 2)=n)!')
2580 except Exception as e:
2581 if throw:
2582 raise
2583 if warning:
2584 warnings.warn(str(e))
2585 valid = False
2586 return valid
2589def num_obs_dm(d):
2590 """
2591 Return the number of original observations that correspond to a
2592 square, redundant distance matrix.
2594 Parameters
2595 ----------
2596 d : array_like
2597 The target distance matrix.
2599 Returns
2600 -------
2601 num_obs_dm : int
2602 The number of observations in the redundant distance matrix.
2604 """
2605 d = np.asarray(d, order='c')
2606 is_valid_dm(d, tol=np.inf, throw=True, name='d')
2607 return d.shape[0]
2610def num_obs_y(Y):
2611 """
2612 Return the number of original observations that correspond to a
2613 condensed distance matrix.
2615 Parameters
2616 ----------
2617 Y : array_like
2618 Condensed distance matrix.
2620 Returns
2621 -------
2622 n : int
2623 The number of observations in the condensed distance matrix `Y`.
2625 """
2626 Y = np.asarray(Y, order='c')
2627 is_valid_y(Y, throw=True, name='Y')
2628 k = Y.shape[0]
2629 if k == 0:
2630 raise ValueError("The number of observations cannot be determined on "
2631 "an empty distance matrix.")
2632 d = int(np.ceil(np.sqrt(k * 2)))
2633 if (d * (d - 1) / 2) != k:
2634 raise ValueError("Invalid condensed distance matrix passed. Must be "
2635 "some k where k=(n choose 2) for some n >= 2.")
2636 return d
2639def _prepare_out_argument(out, dtype, expected_shape):
2640 if out is None:
2641 return np.empty(expected_shape, dtype=dtype)
2643 if out.shape != expected_shape:
2644 raise ValueError("Output array has incorrect shape.")
2645 if not out.flags.c_contiguous:
2646 raise ValueError("Output array must be C-contiguous.")
2647 if out.dtype != np.double:
2648 raise ValueError("Output array must be double type.")
2649 return out
2652def _pdist_callable(X, *, out, metric, **kwargs):
2653 n = X.shape[0]
2654 out_size = (n * (n - 1)) // 2
2655 dm = _prepare_out_argument(out, np.double, (out_size,))
2656 k = 0
2657 for i in range(X.shape[0] - 1):
2658 for j in range(i + 1, X.shape[0]):
2659 dm[k] = metric(X[i], X[j], **kwargs)
2660 k += 1
2661 return dm
2664def _cdist_callable(XA, XB, *, out, metric, **kwargs):
2665 mA = XA.shape[0]
2666 mB = XB.shape[0]
2667 dm = _prepare_out_argument(out, np.double, (mA, mB))
2668 for i in range(mA):
2669 for j in range(mB):
2670 dm[i, j] = metric(XA[i], XB[j], **kwargs)
2671 return dm
2674def cdist(XA, XB, metric='euclidean', *, out=None, **kwargs):
2675 """
2676 Compute distance between each pair of the two collections of inputs.
2678 See Notes for common calling conventions.
2680 Parameters
2681 ----------
2682 XA : array_like
2683 An :math:`m_A` by :math:`n` array of :math:`m_A`
2684 original observations in an :math:`n`-dimensional space.
2685 Inputs are converted to float type.
2686 XB : array_like
2687 An :math:`m_B` by :math:`n` array of :math:`m_B`
2688 original observations in an :math:`n`-dimensional space.
2689 Inputs are converted to float type.
2690 metric : str or callable, optional
2691 The distance metric to use. If a string, the distance function can be
2692 'braycurtis', 'canberra', 'chebyshev', 'cityblock', 'correlation',
2693 'cosine', 'dice', 'euclidean', 'hamming', 'jaccard', 'jensenshannon',
2694 'kulczynski1', 'mahalanobis', 'matching', 'minkowski',
2695 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener',
2696 'sokalsneath', 'sqeuclidean', 'yule'.
2697 **kwargs : dict, optional
2698 Extra arguments to `metric`: refer to each metric documentation for a
2699 list of all possible arguments.
2701 Some possible arguments:
2703 p : scalar
2704 The p-norm to apply for Minkowski, weighted and unweighted.
2705 Default: 2.
2707 w : array_like
2708 The weight vector for metrics that support weights (e.g., Minkowski).
2710 V : array_like
2711 The variance vector for standardized Euclidean.
2712 Default: var(vstack([XA, XB]), axis=0, ddof=1)
2714 VI : array_like
2715 The inverse of the covariance matrix for Mahalanobis.
2716 Default: inv(cov(vstack([XA, XB].T))).T
2718 out : ndarray
2719 The output array
2720 If not None, the distance matrix Y is stored in this array.
2722 Returns
2723 -------
2724 Y : ndarray
2725 A :math:`m_A` by :math:`m_B` distance matrix is returned.
2726 For each :math:`i` and :math:`j`, the metric
2727 ``dist(u=XA[i], v=XB[j])`` is computed and stored in the
2728 :math:`ij` th entry.
2730 Raises
2731 ------
2732 ValueError
2733 An exception is thrown if `XA` and `XB` do not have
2734 the same number of columns.
2736 Notes
2737 -----
2738 The following are common calling conventions:
2740 1. ``Y = cdist(XA, XB, 'euclidean')``
2742 Computes the distance between :math:`m` points using
2743 Euclidean distance (2-norm) as the distance metric between the
2744 points. The points are arranged as :math:`m`
2745 :math:`n`-dimensional row vectors in the matrix X.
2747 2. ``Y = cdist(XA, XB, 'minkowski', p=2.)``
2749 Computes the distances using the Minkowski distance
2750 :math:`\\|u-v\\|_p` (:math:`p`-norm) where :math:`p > 0` (note
2751 that this is only a quasi-metric if :math:`0 < p < 1`).
2753 3. ``Y = cdist(XA, XB, 'cityblock')``
2755 Computes the city block or Manhattan distance between the
2756 points.
2758 4. ``Y = cdist(XA, XB, 'seuclidean', V=None)``
2760 Computes the standardized Euclidean distance. The standardized
2761 Euclidean distance between two n-vectors ``u`` and ``v`` is
2763 .. math::
2765 \\sqrt{\\sum {(u_i-v_i)^2 / V[x_i]}}.
2767 V is the variance vector; V[i] is the variance computed over all
2768 the i'th components of the points. If not passed, it is
2769 automatically computed.
2771 5. ``Y = cdist(XA, XB, 'sqeuclidean')``
2773 Computes the squared Euclidean distance :math:`\\|u-v\\|_2^2` between
2774 the vectors.
2776 6. ``Y = cdist(XA, XB, 'cosine')``
2778 Computes the cosine distance between vectors u and v,
2780 .. math::
2782 1 - \\frac{u \\cdot v}
2783 {{\\|u\\|}_2 {\\|v\\|}_2}
2785 where :math:`\\|*\\|_2` is the 2-norm of its argument ``*``, and
2786 :math:`u \\cdot v` is the dot product of :math:`u` and :math:`v`.
2788 7. ``Y = cdist(XA, XB, 'correlation')``
2790 Computes the correlation distance between vectors u and v. This is
2792 .. math::
2794 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
2795 {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
2797 where :math:`\\bar{v}` is the mean of the elements of vector v,
2798 and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
2801 8. ``Y = cdist(XA, XB, 'hamming')``
2803 Computes the normalized Hamming distance, or the proportion of
2804 those vector elements between two n-vectors ``u`` and ``v``
2805 which disagree. To save memory, the matrix ``X`` can be of type
2806 boolean.
2808 9. ``Y = cdist(XA, XB, 'jaccard')``
2810 Computes the Jaccard distance between the points. Given two
2811 vectors, ``u`` and ``v``, the Jaccard distance is the
2812 proportion of those elements ``u[i]`` and ``v[i]`` that
2813 disagree where at least one of them is non-zero.
2815 10. ``Y = cdist(XA, XB, 'jensenshannon')``
2817 Computes the Jensen-Shannon distance between two probability arrays.
2818 Given two probability vectors, :math:`p` and :math:`q`, the
2819 Jensen-Shannon distance is
2821 .. math::
2823 \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
2825 where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
2826 and :math:`D` is the Kullback-Leibler divergence.
2828 11. ``Y = cdist(XA, XB, 'chebyshev')``
2830 Computes the Chebyshev distance between the points. The
2831 Chebyshev distance between two n-vectors ``u`` and ``v`` is the
2832 maximum norm-1 distance between their respective elements. More
2833 precisely, the distance is given by
2835 .. math::
2837 d(u,v) = \\max_i {|u_i-v_i|}.
2839 12. ``Y = cdist(XA, XB, 'canberra')``
2841 Computes the Canberra distance between the points. The
2842 Canberra distance between two points ``u`` and ``v`` is
2844 .. math::
2846 d(u,v) = \\sum_i \\frac{|u_i-v_i|}
2847 {|u_i|+|v_i|}.
2849 13. ``Y = cdist(XA, XB, 'braycurtis')``
2851 Computes the Bray-Curtis distance between the points. The
2852 Bray-Curtis distance between two points ``u`` and ``v`` is
2855 .. math::
2857 d(u,v) = \\frac{\\sum_i (|u_i-v_i|)}
2858 {\\sum_i (|u_i+v_i|)}
2860 14. ``Y = cdist(XA, XB, 'mahalanobis', VI=None)``
2862 Computes the Mahalanobis distance between the points. The
2863 Mahalanobis distance between two points ``u`` and ``v`` is
2864 :math:`\\sqrt{(u-v)(1/V)(u-v)^T}` where :math:`(1/V)` (the ``VI``
2865 variable) is the inverse covariance. If ``VI`` is not None,
2866 ``VI`` will be used as the inverse covariance matrix.
2868 15. ``Y = cdist(XA, XB, 'yule')``
2870 Computes the Yule distance between the boolean
2871 vectors. (see `yule` function documentation)
2873 16. ``Y = cdist(XA, XB, 'matching')``
2875 Synonym for 'hamming'.
2877 17. ``Y = cdist(XA, XB, 'dice')``
2879 Computes the Dice distance between the boolean vectors. (see
2880 `dice` function documentation)
2882 18. ``Y = cdist(XA, XB, 'kulczynski1')``
2884 Computes the kulczynski distance between the boolean
2885 vectors. (see `kulczynski1` function documentation)
2887 19. ``Y = cdist(XA, XB, 'rogerstanimoto')``
2889 Computes the Rogers-Tanimoto distance between the boolean
2890 vectors. (see `rogerstanimoto` function documentation)
2892 20. ``Y = cdist(XA, XB, 'russellrao')``
2894 Computes the Russell-Rao distance between the boolean
2895 vectors. (see `russellrao` function documentation)
2897 21. ``Y = cdist(XA, XB, 'sokalmichener')``
2899 Computes the Sokal-Michener distance between the boolean
2900 vectors. (see `sokalmichener` function documentation)
2902 22. ``Y = cdist(XA, XB, 'sokalsneath')``
2904 Computes the Sokal-Sneath distance between the vectors. (see
2905 `sokalsneath` function documentation)
2907 23. ``Y = cdist(XA, XB, f)``
2909 Computes the distance between all pairs of vectors in X
2910 using the user supplied 2-arity function f. For example,
2911 Euclidean distance between the vectors could be computed
2912 as follows::
2914 dm = cdist(XA, XB, lambda u, v: np.sqrt(((u-v)**2).sum()))
2916 Note that you should avoid passing a reference to one of
2917 the distance functions defined in this library. For example,::
2919 dm = cdist(XA, XB, sokalsneath)
2921 would calculate the pair-wise distances between the vectors in
2922 X using the Python function `sokalsneath`. This would result in
2923 sokalsneath being called :math:`{n \\choose 2}` times, which
2924 is inefficient. Instead, the optimized C version is more
2925 efficient, and we call it using the following syntax::
2927 dm = cdist(XA, XB, 'sokalsneath')
2929 Examples
2930 --------
2931 Find the Euclidean distances between four 2-D coordinates:
2933 >>> from scipy.spatial import distance
2934 >>> import numpy as np
2935 >>> coords = [(35.0456, -85.2672),
2936 ... (35.1174, -89.9711),
2937 ... (35.9728, -83.9422),
2938 ... (36.1667, -86.7833)]
2939 >>> distance.cdist(coords, coords, 'euclidean')
2940 array([[ 0. , 4.7044, 1.6172, 1.8856],
2941 [ 4.7044, 0. , 6.0893, 3.3561],
2942 [ 1.6172, 6.0893, 0. , 2.8477],
2943 [ 1.8856, 3.3561, 2.8477, 0. ]])
2946 Find the Manhattan distance from a 3-D point to the corners of the unit
2947 cube:
2949 >>> a = np.array([[0, 0, 0],
2950 ... [0, 0, 1],
2951 ... [0, 1, 0],
2952 ... [0, 1, 1],
2953 ... [1, 0, 0],
2954 ... [1, 0, 1],
2955 ... [1, 1, 0],
2956 ... [1, 1, 1]])
2957 >>> b = np.array([[ 0.1, 0.2, 0.4]])
2958 >>> distance.cdist(a, b, 'cityblock')
2959 array([[ 0.7],
2960 [ 0.9],
2961 [ 1.3],
2962 [ 1.5],
2963 [ 1.5],
2964 [ 1.7],
2965 [ 2.1],
2966 [ 2.3]])
2968 """
2969 # You can also call this as:
2970 # Y = cdist(XA, XB, 'test_abc')
2971 # where 'abc' is the metric being tested. This computes the distance
2972 # between all pairs of vectors in XA and XB using the distance metric 'abc'
2973 # but with a more succinct, verifiable, but less efficient implementation.
2975 XA = np.asarray(XA)
2976 XB = np.asarray(XB)
2978 s = XA.shape
2979 sB = XB.shape
2981 if len(s) != 2:
2982 raise ValueError('XA must be a 2-dimensional array.')
2983 if len(sB) != 2:
2984 raise ValueError('XB must be a 2-dimensional array.')
2985 if s[1] != sB[1]:
2986 raise ValueError('XA and XB must have the same number of columns '
2987 '(i.e. feature dimension.)')
2989 mA = s[0]
2990 mB = sB[0]
2991 n = s[1]
2993 if callable(metric):
2994 mstr = getattr(metric, '__name__', 'Unknown')
2995 metric_info = _METRIC_ALIAS.get(mstr, None)
2996 if metric_info is not None:
2997 XA, XB, typ, kwargs = _validate_cdist_input(
2998 XA, XB, mA, mB, n, metric_info, **kwargs)
2999 return _cdist_callable(XA, XB, metric=metric, out=out, **kwargs)
3000 elif isinstance(metric, str):
3001 mstr = metric.lower()
3002 metric_info = _METRIC_ALIAS.get(mstr, None)
3003 if metric_info is not None:
3004 cdist_fn = metric_info.cdist_func
3005 _extra_windows_error_checks(XA, out, (mA, mB), **kwargs)
3006 return cdist_fn(XA, XB, out=out, **kwargs)
3007 elif mstr.startswith("test_"):
3008 metric_info = _TEST_METRICS.get(mstr, None)
3009 if metric_info is None:
3010 raise ValueError(f'Unknown "Test" Distance Metric: {mstr[5:]}')
3011 XA, XB, typ, kwargs = _validate_cdist_input(
3012 XA, XB, mA, mB, n, metric_info, **kwargs)
3013 return _cdist_callable(
3014 XA, XB, metric=metric_info.dist_func, out=out, **kwargs)
3015 else:
3016 raise ValueError('Unknown Distance Metric: %s' % mstr)
3017 else:
3018 raise TypeError('2nd argument metric must be a string identifier '
3019 'or a function.')