123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952 |
- """
- Distance computations (:mod:`scipy.spatial.distance`)
- =====================================================
- .. sectionauthor:: Damian Eads
- Function reference
- ------------------
- Distance matrix computation from a collection of raw observation vectors
- stored in a rectangular array.
- .. autosummary::
- :toctree: generated/
- pdist -- pairwise distances between observation vectors.
- cdist -- distances between two collections of observation vectors
- squareform -- convert distance matrix to a condensed one and vice versa
- directed_hausdorff -- directed Hausdorff distance between arrays
- Predicates for checking the validity of distance matrices, both
- condensed and redundant. Also contained in this module are functions
- for computing the number of observations in a distance matrix.
- .. autosummary::
- :toctree: generated/
- is_valid_dm -- checks for a valid distance matrix
- is_valid_y -- checks for a valid condensed distance matrix
- num_obs_dm -- # of observations in a distance matrix
- num_obs_y -- # of observations in a condensed distance matrix
- Distance functions between two numeric vectors ``u`` and ``v``. Computing
- distances over a large collection of vectors is inefficient for these
- functions. Use ``pdist`` for this purpose.
- .. autosummary::
- :toctree: generated/
- braycurtis -- the Bray-Curtis distance.
- canberra -- the Canberra distance.
- chebyshev -- the Chebyshev distance.
- cityblock -- the Manhattan distance.
- correlation -- the Correlation distance.
- cosine -- the Cosine distance.
- euclidean -- the Euclidean distance.
- jensenshannon -- the Jensen-Shannon distance.
- mahalanobis -- the Mahalanobis distance.
- minkowski -- the Minkowski distance.
- seuclidean -- the normalized Euclidean distance.
- sqeuclidean -- the squared Euclidean distance.
- Distance functions between two boolean vectors (representing sets) ``u`` and
- ``v``. As in the case of numerical vectors, ``pdist`` is more efficient for
- computing the distances between all pairs.
- .. autosummary::
- :toctree: generated/
- dice -- the Dice dissimilarity.
- hamming -- the Hamming distance.
- jaccard -- the Jaccard distance.
- kulsinski -- the Kulsinski distance.
- kulczynski1 -- the Kulczynski 1 distance.
- rogerstanimoto -- the Rogers-Tanimoto dissimilarity.
- russellrao -- the Russell-Rao dissimilarity.
- sokalmichener -- the Sokal-Michener dissimilarity.
- sokalsneath -- the Sokal-Sneath dissimilarity.
- yule -- the Yule dissimilarity.
- :func:`hamming` also operates over discrete numerical vectors.
- """
- # Copyright (C) Damian Eads, 2007-2008. New BSD License.
- __all__ = [
- 'braycurtis',
- 'canberra',
- 'cdist',
- 'chebyshev',
- 'cityblock',
- 'correlation',
- 'cosine',
- 'dice',
- 'directed_hausdorff',
- 'euclidean',
- 'hamming',
- 'is_valid_dm',
- 'is_valid_y',
- 'jaccard',
- 'jensenshannon',
- 'kulsinski',
- 'kulczynski1',
- 'mahalanobis',
- 'minkowski',
- 'num_obs_dm',
- 'num_obs_y',
- 'pdist',
- 'rogerstanimoto',
- 'russellrao',
- 'seuclidean',
- 'sokalmichener',
- 'sokalsneath',
- 'sqeuclidean',
- 'squareform',
- 'yule'
- ]
- import warnings
- import numpy as np
- import dataclasses
- from typing import List, Optional, Set, Callable
- from functools import partial
- from scipy._lib._util import _asarray_validated
- from . import _distance_wrap
- from . import _hausdorff
- from ..linalg import norm
- from ..special import rel_entr
- from . import _distance_pybind
- from .._lib.deprecation import _deprecated
- def _copy_array_if_base_present(a):
- """Copy the array if its base points to a parent array."""
- if a.base is not None:
- return a.copy()
- return a
- def _correlation_cdist_wrap(XA, XB, dm, **kwargs):
- XA = XA - XA.mean(axis=1, keepdims=True)
- XB = XB - XB.mean(axis=1, keepdims=True)
- _distance_wrap.cdist_cosine_double_wrap(XA, XB, dm, **kwargs)
- def _correlation_pdist_wrap(X, dm, **kwargs):
- X2 = X - X.mean(axis=1, keepdims=True)
- _distance_wrap.pdist_cosine_double_wrap(X2, dm, **kwargs)
- def _convert_to_type(X, out_type):
- return np.ascontiguousarray(X, dtype=out_type)
- def _nbool_correspond_all(u, v, w=None):
- if u.dtype == v.dtype == bool and w is None:
- not_u = ~u
- not_v = ~v
- nff = (not_u & not_v).sum()
- nft = (not_u & v).sum()
- ntf = (u & not_v).sum()
- ntt = (u & v).sum()
- else:
- dtype = np.result_type(int, u.dtype, v.dtype)
- u = u.astype(dtype)
- v = v.astype(dtype)
- not_u = 1.0 - u
- not_v = 1.0 - v
- if w is not None:
- not_u = w * not_u
- u = w * u
- nff = (not_u * not_v).sum()
- nft = (not_u * v).sum()
- ntf = (u * not_v).sum()
- ntt = (u * v).sum()
- return (nff, nft, ntf, ntt)
- def _nbool_correspond_ft_tf(u, v, w=None):
- if u.dtype == v.dtype == bool and w is None:
- not_u = ~u
- not_v = ~v
- nft = (not_u & v).sum()
- ntf = (u & not_v).sum()
- else:
- dtype = np.result_type(int, u.dtype, v.dtype)
- u = u.astype(dtype)
- v = v.astype(dtype)
- not_u = 1.0 - u
- not_v = 1.0 - v
- if w is not None:
- not_u = w * not_u
- u = w * u
- nft = (not_u * v).sum()
- ntf = (u * not_v).sum()
- return (nft, ntf)
- def _validate_cdist_input(XA, XB, mA, mB, n, metric_info, **kwargs):
- # get supported types
- types = metric_info.types
- # choose best type
- typ = types[types.index(XA.dtype)] if XA.dtype in types else types[0]
- # validate data
- XA = _convert_to_type(XA, out_type=typ)
- XB = _convert_to_type(XB, out_type=typ)
- # validate kwargs
- _validate_kwargs = metric_info.validator
- if _validate_kwargs:
- kwargs = _validate_kwargs((XA, XB), mA + mB, n, **kwargs)
- return XA, XB, typ, kwargs
- def _validate_weight_with_size(X, m, n, **kwargs):
- w = kwargs.pop('w', None)
- if w is None:
- return kwargs
- if w.ndim != 1 or w.shape[0] != n:
- raise ValueError("Weights must have same size as input vector. "
- f"{w.shape[0]} vs. {n}")
- kwargs['w'] = _validate_weights(w)
- return kwargs
- def _validate_hamming_kwargs(X, m, n, **kwargs):
- w = kwargs.get('w', np.ones((n,), dtype='double'))
- if w.ndim != 1 or w.shape[0] != n:
- raise ValueError("Weights must have same size as input vector. %d vs. %d" % (w.shape[0], n))
- kwargs['w'] = _validate_weights(w)
- return kwargs
- def _validate_mahalanobis_kwargs(X, m, n, **kwargs):
- VI = kwargs.pop('VI', None)
- if VI is None:
- if m <= n:
- # There are fewer observations than the dimension of
- # the observations.
- raise ValueError("The number of observations (%d) is too "
- "small; the covariance matrix is "
- "singular. For observations with %d "
- "dimensions, at least %d observations "
- "are required." % (m, n, n + 1))
- if isinstance(X, tuple):
- X = np.vstack(X)
- CV = np.atleast_2d(np.cov(X.astype(np.double, copy=False).T))
- VI = np.linalg.inv(CV).T.copy()
- kwargs["VI"] = _convert_to_double(VI)
- return kwargs
- def _validate_minkowski_kwargs(X, m, n, **kwargs):
- kwargs = _validate_weight_with_size(X, m, n, **kwargs)
- if 'p' not in kwargs:
- kwargs['p'] = 2.
- else:
- if kwargs['p'] <= 0:
- raise ValueError("p must be greater than 0")
- return kwargs
- def _validate_pdist_input(X, m, n, metric_info, **kwargs):
- # get supported types
- types = metric_info.types
- # choose best type
- typ = types[types.index(X.dtype)] if X.dtype in types else types[0]
- # validate data
- X = _convert_to_type(X, out_type=typ)
- # validate kwargs
- _validate_kwargs = metric_info.validator
- if _validate_kwargs:
- kwargs = _validate_kwargs(X, m, n, **kwargs)
- return X, typ, kwargs
- def _validate_seuclidean_kwargs(X, m, n, **kwargs):
- V = kwargs.pop('V', None)
- if V is None:
- if isinstance(X, tuple):
- X = np.vstack(X)
- V = np.var(X.astype(np.double, copy=False), axis=0, ddof=1)
- else:
- V = np.asarray(V, order='c')
- if len(V.shape) != 1:
- raise ValueError('Variance vector V must '
- 'be one-dimensional.')
- if V.shape[0] != n:
- raise ValueError('Variance vector V must be of the same '
- 'dimension as the vectors on which the distances '
- 'are computed.')
- kwargs['V'] = _convert_to_double(V)
- return kwargs
- def _validate_vector(u, dtype=None):
- # XXX Is order='c' really necessary?
- u = np.asarray(u, dtype=dtype, order='c')
- if u.ndim == 1:
- return u
- raise ValueError("Input vector should be 1-D.")
- def _validate_weights(w, dtype=np.double):
- w = _validate_vector(w, dtype=dtype)
- if np.any(w < 0):
- raise ValueError("Input weights should be all non-negative")
- return w
- def directed_hausdorff(u, v, seed=0):
- """
- Compute the directed Hausdorff distance between two 2-D arrays.
- Distances between pairs are calculated using a Euclidean metric.
- Parameters
- ----------
- u : (M,N) array_like
- Input array.
- v : (O,N) array_like
- Input array.
- seed : int or None
- Local `numpy.random.RandomState` seed. Default is 0, a random
- shuffling of u and v that guarantees reproducibility.
- Returns
- -------
- d : double
- The directed Hausdorff distance between arrays `u` and `v`,
- index_1 : int
- index of point contributing to Hausdorff pair in `u`
- index_2 : int
- index of point contributing to Hausdorff pair in `v`
- Raises
- ------
- ValueError
- An exception is thrown if `u` and `v` do not have
- the same number of columns.
- Notes
- -----
- Uses the early break technique and the random sampling approach
- described by [1]_. Although worst-case performance is ``O(m * o)``
- (as with the brute force algorithm), this is unlikely in practice
- as the input data would have to require the algorithm to explore
- every single point interaction, and after the algorithm shuffles
- the input points at that. The best case performance is O(m), which
- is satisfied by selecting an inner loop distance that is less than
- cmax and leads to an early break as often as possible. The authors
- have formally shown that the average runtime is closer to O(m).
- .. versionadded:: 0.19.0
- References
- ----------
- .. [1] A. A. Taha and A. Hanbury, "An efficient algorithm for
- calculating the exact Hausdorff distance." IEEE Transactions On
- Pattern Analysis And Machine Intelligence, vol. 37 pp. 2153-63,
- 2015.
- See Also
- --------
- scipy.spatial.procrustes : Another similarity test for two data sets
- Examples
- --------
- Find the directed Hausdorff distance between two 2-D arrays of
- coordinates:
- >>> from scipy.spatial.distance import directed_hausdorff
- >>> import numpy as np
- >>> u = np.array([(1.0, 0.0),
- ... (0.0, 1.0),
- ... (-1.0, 0.0),
- ... (0.0, -1.0)])
- >>> v = np.array([(2.0, 0.0),
- ... (0.0, 2.0),
- ... (-2.0, 0.0),
- ... (0.0, -4.0)])
- >>> directed_hausdorff(u, v)[0]
- 2.23606797749979
- >>> directed_hausdorff(v, u)[0]
- 3.0
- Find the general (symmetric) Hausdorff distance between two 2-D
- arrays of coordinates:
- >>> max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])
- 3.0
- Find the indices of the points that generate the Hausdorff distance
- (the Hausdorff pair):
- >>> directed_hausdorff(v, u)[1:]
- (3, 3)
- """
- u = np.asarray(u, dtype=np.float64, order='c')
- v = np.asarray(v, dtype=np.float64, order='c')
- if u.shape[1] != v.shape[1]:
- raise ValueError('u and v need to have the same '
- 'number of columns')
- result = _hausdorff.directed_hausdorff(u, v, seed)
- return result
- def minkowski(u, v, p=2, w=None):
- """
- Compute the Minkowski distance between two 1-D arrays.
- The Minkowski distance between 1-D arrays `u` and `v`,
- is defined as
- .. math::
- {\\|u-v\\|}_p = (\\sum{|u_i - v_i|^p})^{1/p}.
- \\left(\\sum{w_i(|(u_i - v_i)|^p)}\\right)^{1/p}.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- p : scalar
- The order of the norm of the difference :math:`{\\|u-v\\|}_p`. Note
- that for :math:`0 < p < 1`, the triangle inequality only holds with
- an additional multiplicative factor, i.e. it is only a quasi-metric.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- minkowski : double
- The Minkowski distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.minkowski([1, 0, 0], [0, 1, 0], 1)
- 2.0
- >>> distance.minkowski([1, 0, 0], [0, 1, 0], 2)
- 1.4142135623730951
- >>> distance.minkowski([1, 0, 0], [0, 1, 0], 3)
- 1.2599210498948732
- >>> distance.minkowski([1, 1, 0], [0, 1, 0], 1)
- 1.0
- >>> distance.minkowski([1, 1, 0], [0, 1, 0], 2)
- 1.0
- >>> distance.minkowski([1, 1, 0], [0, 1, 0], 3)
- 1.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if p <= 0:
- raise ValueError("p must be greater than 0")
- u_v = u - v
- if w is not None:
- w = _validate_weights(w)
- if p == 1:
- root_w = w
- elif p == 2:
- # better precision and speed
- root_w = np.sqrt(w)
- elif p == np.inf:
- root_w = (w != 0)
- else:
- root_w = np.power(w, 1/p)
- u_v = root_w * u_v
- dist = norm(u_v, ord=p)
- return dist
- def euclidean(u, v, w=None):
- """
- Computes the Euclidean distance between two 1-D arrays.
- The Euclidean distance between 1-D arrays `u` and `v`, is defined as
- .. math::
- {\\|u-v\\|}_2
- \\left(\\sum{(w_i |(u_i - v_i)|^2)}\\right)^{1/2}
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- euclidean : double
- The Euclidean distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.euclidean([1, 0, 0], [0, 1, 0])
- 1.4142135623730951
- >>> distance.euclidean([1, 1, 0], [0, 1, 0])
- 1.0
- """
- return minkowski(u, v, p=2, w=w)
- def sqeuclidean(u, v, w=None):
- """
- Compute the squared Euclidean distance between two 1-D arrays.
- The squared Euclidean distance between `u` and `v` is defined as
- .. math::
- {\\|u-v\\|}_2^2
- \\left(\\sum{(w_i |(u_i - v_i)|^2)}\\right)
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- sqeuclidean : double
- The squared Euclidean distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.sqeuclidean([1, 0, 0], [0, 1, 0])
- 2.0
- >>> distance.sqeuclidean([1, 1, 0], [0, 1, 0])
- 1.0
- """
- # Preserve float dtypes, but convert everything else to np.float64
- # for stability.
- utype, vtype = None, None
- if not (hasattr(u, "dtype") and np.issubdtype(u.dtype, np.inexact)):
- utype = np.float64
- if not (hasattr(v, "dtype") and np.issubdtype(v.dtype, np.inexact)):
- vtype = np.float64
- u = _validate_vector(u, dtype=utype)
- v = _validate_vector(v, dtype=vtype)
- u_v = u - v
- u_v_w = u_v # only want weights applied once
- if w is not None:
- w = _validate_weights(w)
- u_v_w = w * u_v
- return np.dot(u_v, u_v_w)
- def correlation(u, v, w=None, centered=True):
- """
- Compute the correlation distance between two 1-D arrays.
- The correlation distance between `u` and `v`, is
- defined as
- .. math::
- 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
- {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
- where :math:`\\bar{u}` is the mean of the elements of `u`
- and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- centered : bool, optional
- If True, `u` and `v` will be centered. Default is True.
- Returns
- -------
- correlation : double
- The correlation distance between 1-D array `u` and `v`.
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- if centered:
- umu = np.average(u, weights=w)
- vmu = np.average(v, weights=w)
- u = u - umu
- v = v - vmu
- uv = np.average(u * v, weights=w)
- uu = np.average(np.square(u), weights=w)
- vv = np.average(np.square(v), weights=w)
- dist = 1.0 - uv / np.sqrt(uu * vv)
- # Return absolute value to avoid small negative value due to rounding
- return np.abs(dist)
- def cosine(u, v, w=None):
- """
- Compute the Cosine distance between 1-D arrays.
- The Cosine distance between `u` and `v`, is defined as
- .. math::
- 1 - \\frac{u \\cdot v}
- {\\|u\\|_2 \\|v\\|_2}.
- where :math:`u \\cdot v` is the dot product of :math:`u` and
- :math:`v`.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- cosine : double
- The Cosine distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.cosine([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.cosine([100, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.cosine([1, 1, 0], [0, 1, 0])
- 0.29289321881345254
- """
- # cosine distance is also referred to as 'uncentered correlation',
- # or 'reflective correlation'
- # clamp the result to 0-2
- return max(0, min(correlation(u, v, w=w, centered=False), 2.0))
- def hamming(u, v, w=None):
- """
- Compute the Hamming distance between two 1-D arrays.
- The Hamming distance between 1-D arrays `u` and `v`, is simply the
- proportion of disagreeing components in `u` and `v`. If `u` and `v` are
- boolean vectors, the Hamming distance is
- .. math::
- \\frac{c_{01} + c_{10}}{n}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- hamming : double
- The Hamming distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.hamming([1, 0, 0], [0, 1, 0])
- 0.66666666666666663
- >>> distance.hamming([1, 0, 0], [1, 1, 0])
- 0.33333333333333331
- >>> distance.hamming([1, 0, 0], [2, 0, 0])
- 0.33333333333333331
- >>> distance.hamming([1, 0, 0], [3, 0, 0])
- 0.33333333333333331
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if u.shape != v.shape:
- raise ValueError('The 1d arrays must have equal lengths.')
- u_ne_v = u != v
- if w is not None:
- w = _validate_weights(w)
- return np.average(u_ne_v, weights=w)
- def jaccard(u, v, w=None):
- """
- Compute the Jaccard-Needham dissimilarity between two boolean 1-D arrays.
- The Jaccard-Needham dissimilarity between 1-D boolean arrays `u` and `v`,
- is defined as
- .. math::
- \\frac{c_{TF} + c_{FT}}
- {c_{TT} + c_{FT} + c_{TF}}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- jaccard : double
- The Jaccard distance between vectors `u` and `v`.
- Notes
- -----
- When both `u` and `v` lead to a `0/0` division i.e. there is no overlap
- between the items in the vectors the returned distance is 0. See the
- Wikipedia page on the Jaccard index [1]_, and this paper [2]_.
- .. versionchanged:: 1.2.0
- Previously, when `u` and `v` lead to a `0/0` division, the function
- would return NaN. This was changed to return 0 instead.
- References
- ----------
- .. [1] https://en.wikipedia.org/wiki/Jaccard_index
- .. [2] S. Kosub, "A note on the triangle inequality for the Jaccard
- distance", 2016, :arxiv:`1612.02696`
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.jaccard([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.jaccard([1, 0, 0], [1, 1, 0])
- 0.5
- >>> distance.jaccard([1, 0, 0], [1, 2, 0])
- 0.5
- >>> distance.jaccard([1, 0, 0], [1, 1, 1])
- 0.66666666666666663
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- nonzero = np.bitwise_or(u != 0, v != 0)
- unequal_nonzero = np.bitwise_and((u != v), nonzero)
- if w is not None:
- w = _validate_weights(w)
- nonzero = w * nonzero
- unequal_nonzero = w * unequal_nonzero
- a = np.double(unequal_nonzero.sum())
- b = np.double(nonzero.sum())
- return (a / b) if b != 0 else 0
- @_deprecated("Kulsinski has been deprecated from scipy.spatial.distance"
- " in SciPy 1.9.0 and it will be removed in SciPy 1.11.0."
- " It is superseded by scipy.spatial.distance.kulczynski1.")
- def kulsinski(u, v, w=None):
- """
- Compute the Kulsinski dissimilarity between two boolean 1-D arrays.
- The Kulsinski dissimilarity between two boolean 1-D arrays `u` and `v`,
- is defined as
- .. math::
- \\frac{c_{TF} + c_{FT} - c_{TT} + n}
- {c_{FT} + c_{TF} + n}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`.
- .. deprecated:: 0.12.0
- `kulsinski` has been deprecated from `scipy.spatial.distance` in
- SciPy 1.9.0 and it will be removed in SciPy 1.11.0. It is superseded
- by `scipy.spatial.distance.kulczynski1`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- kulsinski : double
- The Kulsinski distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.kulsinski([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.kulsinski([1, 0, 0], [1, 1, 0])
- 0.75
- >>> distance.kulsinski([1, 0, 0], [2, 1, 0])
- 0.33333333333333331
- >>> distance.kulsinski([1, 0, 0], [3, 1, 0])
- -0.5
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is None:
- n = float(len(u))
- else:
- w = _validate_weights(w)
- n = w.sum()
- (nff, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
- return (ntf + nft - ntt + n) / (ntf + nft + n)
- def kulczynski1(u, v, *, w=None):
- """
- Compute the Kulczynski 1 dissimilarity between two boolean 1-D arrays.
- The Kulczynski 1 dissimilarity between two boolean 1-D arrays `u` and `v`
- of length ``n``, is defined as
- .. math::
- \\frac{c_{11}}
- {c_{01} + c_{10}}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k \\in {0, 1, ..., n-1}`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- kulczynski1 : float
- The Kulczynski 1 distance between vectors `u` and `v`.
- Notes
- -----
- This measure has a minimum value of 0 and no upper limit.
- It is un-defined when there are no non-matches.
- .. versionadded:: 1.8.0
- References
- ----------
- .. [1] Kulczynski S. et al. Bulletin
- International de l'Academie Polonaise des Sciences
- et des Lettres, Classe des Sciences Mathematiques
- et Naturelles, Serie B (Sciences Naturelles). 1927;
- Supplement II: 57-203.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.kulczynski1([1, 0, 0], [0, 1, 0])
- 0.0
- >>> distance.kulczynski1([True, False, False], [True, True, False])
- 1.0
- >>> distance.kulczynski1([True, False, False], [True])
- 0.5
- >>> distance.kulczynski1([1, 0, 0], [3, 1, 0])
- -3.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- (_, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
- return ntt / (ntf + nft)
- def seuclidean(u, v, V):
- """
- Return the standardized Euclidean distance between two 1-D arrays.
- The standardized Euclidean distance between `u` and `v`.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- V : (N,) array_like
- `V` is an 1-D array of component variances. It is usually computed
- among a larger collection vectors.
- Returns
- -------
- seuclidean : double
- The standardized Euclidean distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [0.1, 0.1, 0.1])
- 4.4721359549995796
- >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [1, 0.1, 0.1])
- 3.3166247903553998
- >>> distance.seuclidean([1, 0, 0], [0, 1, 0], [10, 0.1, 0.1])
- 3.1780497164141406
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- V = _validate_vector(V, dtype=np.float64)
- if V.shape[0] != u.shape[0] or u.shape[0] != v.shape[0]:
- raise TypeError('V must be a 1-D array of the same dimension '
- 'as u and v.')
- return euclidean(u, v, w=1/V)
- def cityblock(u, v, w=None):
- """
- Compute the City Block (Manhattan) distance.
- Computes the Manhattan distance between two 1-D arrays `u` and `v`,
- which is defined as
- .. math::
- \\sum_i {\\left| u_i - v_i \\right|}.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- cityblock : double
- The City Block (Manhattan) distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.cityblock([1, 0, 0], [0, 1, 0])
- 2
- >>> distance.cityblock([1, 0, 0], [0, 2, 0])
- 3
- >>> distance.cityblock([1, 0, 0], [1, 1, 0])
- 1
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- l1_diff = abs(u - v)
- if w is not None:
- w = _validate_weights(w)
- l1_diff = w * l1_diff
- return l1_diff.sum()
- def mahalanobis(u, v, VI):
- """
- Compute the Mahalanobis distance between two 1-D arrays.
- The Mahalanobis distance between 1-D arrays `u` and `v`, is defined as
- .. math::
- \\sqrt{ (u-v) V^{-1} (u-v)^T }
- where ``V`` is the covariance matrix. Note that the argument `VI`
- is the inverse of ``V``.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- VI : array_like
- The inverse of the covariance matrix.
- Returns
- -------
- mahalanobis : double
- The Mahalanobis distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> iv = [[1, 0.5, 0.5], [0.5, 1, 0.5], [0.5, 0.5, 1]]
- >>> distance.mahalanobis([1, 0, 0], [0, 1, 0], iv)
- 1.0
- >>> distance.mahalanobis([0, 2, 0], [0, 1, 0], iv)
- 1.0
- >>> distance.mahalanobis([2, 0, 0], [0, 1, 0], iv)
- 1.7320508075688772
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- VI = np.atleast_2d(VI)
- delta = u - v
- m = np.dot(np.dot(delta, VI), delta)
- return np.sqrt(m)
- def chebyshev(u, v, w=None):
- """
- Compute the Chebyshev distance.
- Computes the Chebyshev distance between two 1-D arrays `u` and `v`,
- which is defined as
- .. math::
- \\max_i {|u_i-v_i|}.
- Parameters
- ----------
- u : (N,) array_like
- Input vector.
- v : (N,) array_like
- Input vector.
- w : (N,) array_like, optional
- Unused, as 'max' is a weightless operation. Here for API consistency.
- Returns
- -------
- chebyshev : double
- The Chebyshev distance between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.chebyshev([1, 0, 0], [0, 1, 0])
- 1
- >>> distance.chebyshev([1, 1, 0], [0, 1, 0])
- 1
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- has_weight = w > 0
- if has_weight.sum() < w.size:
- u = u[has_weight]
- v = v[has_weight]
- return max(abs(u - v))
- def braycurtis(u, v, w=None):
- """
- Compute the Bray-Curtis distance between two 1-D arrays.
- Bray-Curtis distance is defined as
- .. math::
- \\sum{|u_i-v_i|} / \\sum{|u_i+v_i|}
- The Bray-Curtis distance is in the range [0, 1] if all coordinates are
- positive, and is undefined if the inputs are of length zero.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- braycurtis : double
- The Bray-Curtis distance between 1-D arrays `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.braycurtis([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.braycurtis([1, 1, 0], [0, 1, 0])
- 0.33333333333333331
- """
- u = _validate_vector(u)
- v = _validate_vector(v, dtype=np.float64)
- l1_diff = abs(u - v)
- l1_sum = abs(u + v)
- if w is not None:
- w = _validate_weights(w)
- l1_diff = w * l1_diff
- l1_sum = w * l1_sum
- return l1_diff.sum() / l1_sum.sum()
- def canberra(u, v, w=None):
- """
- Compute the Canberra distance between two 1-D arrays.
- The Canberra distance is defined as
- .. math::
- d(u,v) = \\sum_i \\frac{|u_i-v_i|}
- {|u_i|+|v_i|}.
- Parameters
- ----------
- u : (N,) array_like
- Input array.
- v : (N,) array_like
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- canberra : double
- The Canberra distance between vectors `u` and `v`.
- Notes
- -----
- When `u[i]` and `v[i]` are 0 for given i, then the fraction 0/0 = 0 is
- used in the calculation.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.canberra([1, 0, 0], [0, 1, 0])
- 2.0
- >>> distance.canberra([1, 1, 0], [0, 1, 0])
- 1.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v, dtype=np.float64)
- if w is not None:
- w = _validate_weights(w)
- with np.errstate(invalid='ignore'):
- abs_uv = abs(u - v)
- abs_u = abs(u)
- abs_v = abs(v)
- d = abs_uv / (abs_u + abs_v)
- if w is not None:
- d = w * d
- d = np.nansum(d)
- return d
- def jensenshannon(p, q, base=None, *, axis=0, keepdims=False):
- """
- Compute the Jensen-Shannon distance (metric) between
- two probability arrays. This is the square root
- of the Jensen-Shannon divergence.
- The Jensen-Shannon distance between two probability
- vectors `p` and `q` is defined as,
- .. math::
- \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
- where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
- and :math:`D` is the Kullback-Leibler divergence.
- This routine will normalize `p` and `q` if they don't sum to 1.0.
- Parameters
- ----------
- p : (N,) array_like
- left probability vector
- q : (N,) array_like
- right probability vector
- base : double, optional
- the base of the logarithm used to compute the output
- if not given, then the routine uses the default base of
- scipy.stats.entropy.
- axis : int, optional
- Axis along which the Jensen-Shannon distances are computed. The default
- is 0.
- .. versionadded:: 1.7.0
- keepdims : bool, optional
- If this is set to `True`, the reduced axes are left in the
- result as dimensions with size one. With this option,
- the result will broadcast correctly against the input array.
- Default is False.
- .. versionadded:: 1.7.0
- Returns
- -------
- js : double or ndarray
- The Jensen-Shannon distances between `p` and `q` along the `axis`.
- Notes
- -----
- .. versionadded:: 1.2.0
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> import numpy as np
- >>> distance.jensenshannon([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], 2.0)
- 1.0
- >>> distance.jensenshannon([1.0, 0.0], [0.5, 0.5])
- 0.46450140402245893
- >>> distance.jensenshannon([1.0, 0.0, 0.0], [1.0, 0.0, 0.0])
- 0.0
- >>> a = np.array([[1, 2, 3, 4],
- ... [5, 6, 7, 8],
- ... [9, 10, 11, 12]])
- >>> b = np.array([[13, 14, 15, 16],
- ... [17, 18, 19, 20],
- ... [21, 22, 23, 24]])
- >>> distance.jensenshannon(a, b, axis=0)
- array([0.1954288, 0.1447697, 0.1138377, 0.0927636])
- >>> distance.jensenshannon(a, b, axis=1)
- array([0.1402339, 0.0399106, 0.0201815])
- """
- p = np.asarray(p)
- q = np.asarray(q)
- p = p / np.sum(p, axis=axis, keepdims=True)
- q = q / np.sum(q, axis=axis, keepdims=True)
- m = (p + q) / 2.0
- left = rel_entr(p, m)
- right = rel_entr(q, m)
- left_sum = np.sum(left, axis=axis, keepdims=keepdims)
- right_sum = np.sum(right, axis=axis, keepdims=keepdims)
- js = left_sum + right_sum
- if base is not None:
- js /= np.log(base)
- return np.sqrt(js / 2.0)
- def yule(u, v, w=None):
- """
- Compute the Yule dissimilarity between two boolean 1-D arrays.
- The Yule dissimilarity is defined as
- .. math::
- \\frac{R}{c_{TT} * c_{FF} + \\frac{R}{2}}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n` and :math:`R = 2.0 * c_{TF} * c_{FT}`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- yule : double
- The Yule dissimilarity between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.yule([1, 0, 0], [0, 1, 0])
- 2.0
- >>> distance.yule([1, 1, 0], [0, 1, 0])
- 0.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- (nff, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
- half_R = ntf * nft
- if half_R == 0:
- return 0.0
- else:
- return float(2.0 * half_R / (ntt * nff + half_R))
- def dice(u, v, w=None):
- """
- Compute the Dice dissimilarity between two boolean 1-D arrays.
- The Dice dissimilarity between `u` and `v`, is
- .. math::
- \\frac{c_{TF} + c_{FT}}
- {2c_{TT} + c_{FT} + c_{TF}}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input 1-D array.
- v : (N,) array_like, bool
- Input 1-D array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- dice : double
- The Dice dissimilarity between 1-D arrays `u` and `v`.
- Notes
- -----
- This function computes the Dice dissimilarity index. To compute the
- Dice similarity index, convert one to the other with similarity =
- 1 - dissimilarity.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.dice([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.dice([1, 0, 0], [1, 1, 0])
- 0.3333333333333333
- >>> distance.dice([1, 0, 0], [2, 0, 0])
- -0.3333333333333333
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- if u.dtype == v.dtype == bool and w is None:
- ntt = (u & v).sum()
- else:
- dtype = np.result_type(int, u.dtype, v.dtype)
- u = u.astype(dtype)
- v = v.astype(dtype)
- if w is None:
- ntt = (u * v).sum()
- else:
- ntt = (u * v * w).sum()
- (nft, ntf) = _nbool_correspond_ft_tf(u, v, w=w)
- return float((ntf + nft) / np.array(2.0 * ntt + ntf + nft))
- def rogerstanimoto(u, v, w=None):
- """
- Compute the Rogers-Tanimoto dissimilarity between two boolean 1-D arrays.
- The Rogers-Tanimoto dissimilarity between two boolean 1-D arrays
- `u` and `v`, is defined as
- .. math::
- \\frac{R}
- {c_{TT} + c_{FF} + R}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n` and :math:`R = 2(c_{TF} + c_{FT})`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- rogerstanimoto : double
- The Rogers-Tanimoto dissimilarity between vectors
- `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.rogerstanimoto([1, 0, 0], [0, 1, 0])
- 0.8
- >>> distance.rogerstanimoto([1, 0, 0], [1, 1, 0])
- 0.5
- >>> distance.rogerstanimoto([1, 0, 0], [2, 0, 0])
- -1.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- (nff, nft, ntf, ntt) = _nbool_correspond_all(u, v, w=w)
- return float(2.0 * (ntf + nft)) / float(ntt + nff + (2.0 * (ntf + nft)))
- def russellrao(u, v, w=None):
- """
- Compute the Russell-Rao dissimilarity between two boolean 1-D arrays.
- The Russell-Rao dissimilarity between two boolean 1-D arrays, `u` and
- `v`, is defined as
- .. math::
- \\frac{n - c_{TT}}
- {n}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- russellrao : double
- The Russell-Rao dissimilarity between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.russellrao([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.russellrao([1, 0, 0], [1, 1, 0])
- 0.6666666666666666
- >>> distance.russellrao([1, 0, 0], [2, 0, 0])
- 0.3333333333333333
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if u.dtype == v.dtype == bool and w is None:
- ntt = (u & v).sum()
- n = float(len(u))
- elif w is None:
- ntt = (u * v).sum()
- n = float(len(u))
- else:
- w = _validate_weights(w)
- ntt = (u * v * w).sum()
- n = w.sum()
- return float(n - ntt) / n
- def sokalmichener(u, v, w=None):
- """
- Compute the Sokal-Michener dissimilarity between two boolean 1-D arrays.
- The Sokal-Michener dissimilarity between boolean 1-D arrays `u` and `v`,
- is defined as
- .. math::
- \\frac{R}
- {S + R}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n`, :math:`R = 2 * (c_{TF} + c_{FT})` and
- :math:`S = c_{FF} + c_{TT}`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- sokalmichener : double
- The Sokal-Michener dissimilarity between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.sokalmichener([1, 0, 0], [0, 1, 0])
- 0.8
- >>> distance.sokalmichener([1, 0, 0], [1, 1, 0])
- 0.5
- >>> distance.sokalmichener([1, 0, 0], [2, 0, 0])
- -1.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if w is not None:
- w = _validate_weights(w)
- nff, nft, ntf, ntt = _nbool_correspond_all(u, v, w=w)
- return float(2.0 * (ntf + nft)) / float(ntt + nff + 2.0 * (ntf + nft))
- def sokalsneath(u, v, w=None):
- """
- Compute the Sokal-Sneath dissimilarity between two boolean 1-D arrays.
- The Sokal-Sneath dissimilarity between `u` and `v`,
- .. math::
- \\frac{R}
- {c_{TT} + R}
- where :math:`c_{ij}` is the number of occurrences of
- :math:`\\mathtt{u[k]} = i` and :math:`\\mathtt{v[k]} = j` for
- :math:`k < n` and :math:`R = 2(c_{TF} + c_{FT})`.
- Parameters
- ----------
- u : (N,) array_like, bool
- Input array.
- v : (N,) array_like, bool
- Input array.
- w : (N,) array_like, optional
- The weights for each value in `u` and `v`. Default is None,
- which gives each value a weight of 1.0
- Returns
- -------
- sokalsneath : double
- The Sokal-Sneath dissimilarity between vectors `u` and `v`.
- Examples
- --------
- >>> from scipy.spatial import distance
- >>> distance.sokalsneath([1, 0, 0], [0, 1, 0])
- 1.0
- >>> distance.sokalsneath([1, 0, 0], [1, 1, 0])
- 0.66666666666666663
- >>> distance.sokalsneath([1, 0, 0], [2, 1, 0])
- 0.0
- >>> distance.sokalsneath([1, 0, 0], [3, 1, 0])
- -2.0
- """
- u = _validate_vector(u)
- v = _validate_vector(v)
- if u.dtype == v.dtype == bool and w is None:
- ntt = (u & v).sum()
- elif w is None:
- ntt = (u * v).sum()
- else:
- w = _validate_weights(w)
- ntt = (u * v * w).sum()
- (nft, ntf) = _nbool_correspond_ft_tf(u, v, w=w)
- denom = np.array(ntt + 2.0 * (ntf + nft))
- if not denom.any():
- raise ValueError('Sokal-Sneath dissimilarity is not defined for '
- 'vectors that are entirely false.')
- return float(2.0 * (ntf + nft)) / denom
- _convert_to_double = partial(_convert_to_type, out_type=np.double)
- _convert_to_bool = partial(_convert_to_type, out_type=bool)
- # adding python-only wrappers to _distance_wrap module
- _distance_wrap.pdist_correlation_double_wrap = _correlation_pdist_wrap
- _distance_wrap.cdist_correlation_double_wrap = _correlation_cdist_wrap
- @dataclasses.dataclass(frozen=True)
- class CDistMetricWrapper:
- metric_name: str
- def __call__(self, XA, XB, *, out=None, **kwargs):
- XA = np.ascontiguousarray(XA)
- XB = np.ascontiguousarray(XB)
- mA, n = XA.shape
- mB, _ = XB.shape
- metric_name = self.metric_name
- metric_info = _METRICS[metric_name]
- XA, XB, typ, kwargs = _validate_cdist_input(
- XA, XB, mA, mB, n, metric_info, **kwargs)
- w = kwargs.pop('w', None)
- if w is not None:
- metric = metric_info.dist_func
- return _cdist_callable(
- XA, XB, metric=metric, out=out, w=w, **kwargs)
- dm = _prepare_out_argument(out, np.double, (mA, mB))
- # get cdist wrapper
- cdist_fn = getattr(_distance_wrap, f'cdist_{metric_name}_{typ}_wrap')
- cdist_fn(XA, XB, dm, **kwargs)
- return dm
- @dataclasses.dataclass(frozen=True)
- class CDistWeightedMetricWrapper:
- metric_name: str
- weighted_metric: str
- def __call__(self, XA, XB, *, out=None, **kwargs):
- XA = np.ascontiguousarray(XA)
- XB = np.ascontiguousarray(XB)
- mA, n = XA.shape
- mB, _ = XB.shape
- metric_name = self.metric_name
- XA, XB, typ, kwargs = _validate_cdist_input(
- XA, XB, mA, mB, n, _METRICS[metric_name], **kwargs)
- dm = _prepare_out_argument(out, np.double, (mA, mB))
- w = kwargs.pop('w', None)
- if w is not None:
- metric_name = self.weighted_metric
- kwargs['w'] = w
- # get cdist wrapper
- cdist_fn = getattr(_distance_wrap, f'cdist_{metric_name}_{typ}_wrap')
- cdist_fn(XA, XB, dm, **kwargs)
- return dm
- @dataclasses.dataclass(frozen=True)
- class PDistMetricWrapper:
- metric_name: str
- def __call__(self, X, *, out=None, **kwargs):
- X = np.ascontiguousarray(X)
- m, n = X.shape
- metric_name = self.metric_name
- metric_info = _METRICS[metric_name]
- X, typ, kwargs = _validate_pdist_input(
- X, m, n, metric_info, **kwargs)
- out_size = (m * (m - 1)) // 2
- w = kwargs.pop('w', None)
- if w is not None:
- metric = metric_info.dist_func
- return _pdist_callable(
- X, metric=metric, out=out, w=w, **kwargs)
- dm = _prepare_out_argument(out, np.double, (out_size,))
- # get pdist wrapper
- pdist_fn = getattr(_distance_wrap, f'pdist_{metric_name}_{typ}_wrap')
- pdist_fn(X, dm, **kwargs)
- return dm
- @dataclasses.dataclass(frozen=True)
- class PDistWeightedMetricWrapper:
- metric_name: str
- weighted_metric: str
- def __call__(self, X, *, out=None, **kwargs):
- X = np.ascontiguousarray(X)
- m, n = X.shape
- metric_name = self.metric_name
- X, typ, kwargs = _validate_pdist_input(
- X, m, n, _METRICS[metric_name], **kwargs)
- out_size = (m * (m - 1)) // 2
- dm = _prepare_out_argument(out, np.double, (out_size,))
- w = kwargs.pop('w', None)
- if w is not None:
- metric_name = self.weighted_metric
- kwargs['w'] = w
- # get pdist wrapper
- pdist_fn = getattr(_distance_wrap, f'pdist_{metric_name}_{typ}_wrap')
- pdist_fn(X, dm, **kwargs)
- return dm
- @dataclasses.dataclass(frozen=True)
- class MetricInfo:
- # Name of python distance function
- canonical_name: str
- # All aliases, including canonical_name
- aka: Set[str]
- # unvectorized distance function
- dist_func: Callable
- # Optimized cdist function
- cdist_func: Callable
- # Optimized pdist function
- pdist_func: Callable
- # function that checks kwargs and computes default values:
- # f(X, m, n, **kwargs)
- validator: Optional[Callable] = None
- # list of supported types:
- # X (pdist) and XA (cdist) are used to choose the type. if there is no
- # match the first type is used. Default double
- types: List[str] = dataclasses.field(default_factory=lambda: ['double'])
- # true if out array must be C-contiguous
- requires_contiguous_out: bool = True
- # Registry of implemented metrics:
- _METRIC_INFOS = [
- MetricInfo(
- canonical_name='braycurtis',
- aka={'braycurtis'},
- dist_func=braycurtis,
- cdist_func=_distance_pybind.cdist_braycurtis,
- pdist_func=_distance_pybind.pdist_braycurtis,
- ),
- MetricInfo(
- canonical_name='canberra',
- aka={'canberra'},
- dist_func=canberra,
- cdist_func=_distance_pybind.cdist_canberra,
- pdist_func=_distance_pybind.pdist_canberra,
- ),
- MetricInfo(
- canonical_name='chebyshev',
- aka={'chebychev', 'chebyshev', 'cheby', 'cheb', 'ch'},
- dist_func=chebyshev,
- cdist_func=_distance_pybind.cdist_chebyshev,
- pdist_func=_distance_pybind.pdist_chebyshev,
- ),
- MetricInfo(
- canonical_name='cityblock',
- aka={'cityblock', 'cblock', 'cb', 'c'},
- dist_func=cityblock,
- cdist_func=_distance_pybind.cdist_cityblock,
- pdist_func=_distance_pybind.pdist_cityblock,
- ),
- MetricInfo(
- canonical_name='correlation',
- aka={'correlation', 'co'},
- dist_func=correlation,
- cdist_func=CDistMetricWrapper('correlation'),
- pdist_func=PDistMetricWrapper('correlation'),
- ),
- MetricInfo(
- canonical_name='cosine',
- aka={'cosine', 'cos'},
- dist_func=cosine,
- cdist_func=CDistMetricWrapper('cosine'),
- pdist_func=PDistMetricWrapper('cosine'),
- ),
- MetricInfo(
- canonical_name='dice',
- aka={'dice'},
- types=['bool'],
- dist_func=dice,
- cdist_func=CDistMetricWrapper('dice'),
- pdist_func=PDistMetricWrapper('dice'),
- ),
- MetricInfo(
- canonical_name='euclidean',
- aka={'euclidean', 'euclid', 'eu', 'e'},
- dist_func=euclidean,
- cdist_func=_distance_pybind.cdist_euclidean,
- pdist_func=_distance_pybind.pdist_euclidean,
- ),
- MetricInfo(
- canonical_name='hamming',
- aka={'matching', 'hamming', 'hamm', 'ha', 'h'},
- types=['double', 'bool'],
- validator=_validate_hamming_kwargs,
- dist_func=hamming,
- cdist_func=CDistWeightedMetricWrapper('hamming', 'hamming'),
- pdist_func=PDistWeightedMetricWrapper('hamming', 'hamming'),
- ),
- MetricInfo(
- canonical_name='jaccard',
- aka={'jaccard', 'jacc', 'ja', 'j'},
- types=['double', 'bool'],
- dist_func=jaccard,
- cdist_func=CDistMetricWrapper('jaccard'),
- pdist_func=PDistMetricWrapper('jaccard'),
- ),
- MetricInfo(
- canonical_name='jensenshannon',
- aka={'jensenshannon', 'js'},
- dist_func=jensenshannon,
- cdist_func=CDistMetricWrapper('jensenshannon'),
- pdist_func=PDistMetricWrapper('jensenshannon'),
- ),
- MetricInfo(
- canonical_name='kulsinski',
- aka={'kulsinski'},
- types=['bool'],
- dist_func=kulsinski,
- cdist_func=CDistMetricWrapper('kulsinski'),
- pdist_func=PDistMetricWrapper('kulsinski'),
- ),
- MetricInfo(
- canonical_name='kulczynski1',
- aka={'kulczynski1'},
- types=['bool'],
- dist_func=kulczynski1,
- cdist_func=CDistMetricWrapper('kulczynski1'),
- pdist_func=PDistMetricWrapper('kulczynski1'),
- ),
- MetricInfo(
- canonical_name='mahalanobis',
- aka={'mahalanobis', 'mahal', 'mah'},
- validator=_validate_mahalanobis_kwargs,
- dist_func=mahalanobis,
- cdist_func=CDistMetricWrapper('mahalanobis'),
- pdist_func=PDistMetricWrapper('mahalanobis'),
- ),
- MetricInfo(
- canonical_name='minkowski',
- aka={'minkowski', 'mi', 'm', 'pnorm'},
- validator=_validate_minkowski_kwargs,
- dist_func=minkowski,
- cdist_func=_distance_pybind.cdist_minkowski,
- pdist_func=_distance_pybind.pdist_minkowski,
- ),
- MetricInfo(
- canonical_name='rogerstanimoto',
- aka={'rogerstanimoto'},
- types=['bool'],
- dist_func=rogerstanimoto,
- cdist_func=CDistMetricWrapper('rogerstanimoto'),
- pdist_func=PDistMetricWrapper('rogerstanimoto'),
- ),
- MetricInfo(
- canonical_name='russellrao',
- aka={'russellrao'},
- types=['bool'],
- dist_func=russellrao,
- cdist_func=CDistMetricWrapper('russellrao'),
- pdist_func=PDistMetricWrapper('russellrao'),
- ),
- MetricInfo(
- canonical_name='seuclidean',
- aka={'seuclidean', 'se', 's'},
- validator=_validate_seuclidean_kwargs,
- dist_func=seuclidean,
- cdist_func=CDistMetricWrapper('seuclidean'),
- pdist_func=PDistMetricWrapper('seuclidean'),
- ),
- MetricInfo(
- canonical_name='sokalmichener',
- aka={'sokalmichener'},
- types=['bool'],
- dist_func=sokalmichener,
- cdist_func=CDistMetricWrapper('sokalmichener'),
- pdist_func=PDistMetricWrapper('sokalmichener'),
- ),
- MetricInfo(
- canonical_name='sokalsneath',
- aka={'sokalsneath'},
- types=['bool'],
- dist_func=sokalsneath,
- cdist_func=CDistMetricWrapper('sokalsneath'),
- pdist_func=PDistMetricWrapper('sokalsneath'),
- ),
- MetricInfo(
- canonical_name='sqeuclidean',
- aka={'sqeuclidean', 'sqe', 'sqeuclid'},
- dist_func=sqeuclidean,
- cdist_func=_distance_pybind.cdist_sqeuclidean,
- pdist_func=_distance_pybind.pdist_sqeuclidean,
- ),
- MetricInfo(
- canonical_name='yule',
- aka={'yule'},
- types=['bool'],
- dist_func=yule,
- cdist_func=CDistMetricWrapper('yule'),
- pdist_func=PDistMetricWrapper('yule'),
- ),
- ]
- _METRICS = {info.canonical_name: info for info in _METRIC_INFOS}
- _METRIC_ALIAS = dict((alias, info)
- for info in _METRIC_INFOS
- for alias in info.aka)
- _METRICS_NAMES = list(_METRICS.keys())
- _TEST_METRICS = {'test_' + info.canonical_name: info for info in _METRIC_INFOS}
- def pdist(X, metric='euclidean', *, out=None, **kwargs):
- """
- Pairwise distances between observations in n-dimensional space.
- See Notes for common calling conventions.
- Parameters
- ----------
- X : array_like
- An m by n array of m original observations in an
- n-dimensional space.
- metric : str or function, optional
- The distance metric to use. The distance function can
- be 'braycurtis', 'canberra', 'chebyshev', 'cityblock',
- 'correlation', 'cosine', 'dice', 'euclidean', 'hamming',
- 'jaccard', 'jensenshannon', 'kulczynski1',
- 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto',
- 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath',
- 'sqeuclidean', 'yule'.
- **kwargs : dict, optional
- Extra arguments to `metric`: refer to each metric documentation for a
- list of all possible arguments.
- Some possible arguments:
- p : scalar
- The p-norm to apply for Minkowski, weighted and unweighted.
- Default: 2.
- w : ndarray
- The weight vector for metrics that support weights (e.g., Minkowski).
- V : ndarray
- The variance vector for standardized Euclidean.
- Default: var(X, axis=0, ddof=1)
- VI : ndarray
- The inverse of the covariance matrix for Mahalanobis.
- Default: inv(cov(X.T)).T
- out : ndarray.
- The output array
- If not None, condensed distance matrix Y is stored in this array.
- Returns
- -------
- Y : ndarray
- Returns a condensed distance matrix Y. For each :math:`i` and :math:`j`
- (where :math:`i<j<m`),where m is the number of original observations.
- The metric ``dist(u=X[i], v=X[j])`` is computed and stored in entry ``m
- * i + j - ((i + 2) * (i + 1)) // 2``.
- See Also
- --------
- squareform : converts between condensed distance matrices and
- square distance matrices.
- Notes
- -----
- See ``squareform`` for information on how to calculate the index of
- this entry or to convert the condensed distance matrix to a
- redundant square matrix.
- The following are common calling conventions.
- 1. ``Y = pdist(X, 'euclidean')``
- Computes the distance between m points using Euclidean distance
- (2-norm) as the distance metric between the points. The points
- are arranged as m n-dimensional row vectors in the matrix X.
- 2. ``Y = pdist(X, 'minkowski', p=2.)``
- Computes the distances using the Minkowski distance
- :math:`\\|u-v\\|_p` (:math:`p`-norm) where :math:`p > 0` (note
- that this is only a quasi-metric if :math:`0 < p < 1`).
- 3. ``Y = pdist(X, 'cityblock')``
- Computes the city block or Manhattan distance between the
- points.
- 4. ``Y = pdist(X, 'seuclidean', V=None)``
- Computes the standardized Euclidean distance. The standardized
- Euclidean distance between two n-vectors ``u`` and ``v`` is
- .. math::
- \\sqrt{\\sum {(u_i-v_i)^2 / V[x_i]}}
- V is the variance vector; V[i] is the variance computed over all
- the i'th components of the points. If not passed, it is
- automatically computed.
- 5. ``Y = pdist(X, 'sqeuclidean')``
- Computes the squared Euclidean distance :math:`\\|u-v\\|_2^2` between
- the vectors.
- 6. ``Y = pdist(X, 'cosine')``
- Computes the cosine distance between vectors u and v,
- .. math::
- 1 - \\frac{u \\cdot v}
- {{\\|u\\|}_2 {\\|v\\|}_2}
- where :math:`\\|*\\|_2` is the 2-norm of its argument ``*``, and
- :math:`u \\cdot v` is the dot product of ``u`` and ``v``.
- 7. ``Y = pdist(X, 'correlation')``
- Computes the correlation distance between vectors u and v. This is
- .. math::
- 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
- {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
- where :math:`\\bar{v}` is the mean of the elements of vector v,
- and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
- 8. ``Y = pdist(X, 'hamming')``
- Computes the normalized Hamming distance, or the proportion of
- those vector elements between two n-vectors ``u`` and ``v``
- which disagree. To save memory, the matrix ``X`` can be of type
- boolean.
- 9. ``Y = pdist(X, 'jaccard')``
- Computes the Jaccard distance between the points. Given two
- vectors, ``u`` and ``v``, the Jaccard distance is the
- proportion of those elements ``u[i]`` and ``v[i]`` that
- disagree.
- 10. ``Y = pdist(X, 'jensenshannon')``
- Computes the Jensen-Shannon distance between two probability arrays.
- Given two probability vectors, :math:`p` and :math:`q`, the
- Jensen-Shannon distance is
- .. math::
- \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
- where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
- and :math:`D` is the Kullback-Leibler divergence.
- 11. ``Y = pdist(X, 'chebyshev')``
- Computes the Chebyshev distance between the points. The
- Chebyshev distance between two n-vectors ``u`` and ``v`` is the
- maximum norm-1 distance between their respective elements. More
- precisely, the distance is given by
- .. math::
- d(u,v) = \\max_i {|u_i-v_i|}
- 12. ``Y = pdist(X, 'canberra')``
- Computes the Canberra distance between the points. The
- Canberra distance between two points ``u`` and ``v`` is
- .. math::
- d(u,v) = \\sum_i \\frac{|u_i-v_i|}
- {|u_i|+|v_i|}
- 13. ``Y = pdist(X, 'braycurtis')``
- Computes the Bray-Curtis distance between the points. The
- Bray-Curtis distance between two points ``u`` and ``v`` is
- .. math::
- d(u,v) = \\frac{\\sum_i {|u_i-v_i|}}
- {\\sum_i {|u_i+v_i|}}
- 14. ``Y = pdist(X, 'mahalanobis', VI=None)``
- Computes the Mahalanobis distance between the points. The
- Mahalanobis distance between two points ``u`` and ``v`` is
- :math:`\\sqrt{(u-v)(1/V)(u-v)^T}` where :math:`(1/V)` (the ``VI``
- variable) is the inverse covariance. If ``VI`` is not None,
- ``VI`` will be used as the inverse covariance matrix.
- 15. ``Y = pdist(X, 'yule')``
- Computes the Yule distance between each pair of boolean
- vectors. (see yule function documentation)
- 16. ``Y = pdist(X, 'matching')``
- Synonym for 'hamming'.
- 17. ``Y = pdist(X, 'dice')``
- Computes the Dice distance between each pair of boolean
- vectors. (see dice function documentation)
- 18. ``Y = pdist(X, 'kulczynski1')``
- Computes the kulczynski1 distance between each pair of
- boolean vectors. (see kulczynski1 function documentation)
- 19. ``Y = pdist(X, 'rogerstanimoto')``
- Computes the Rogers-Tanimoto distance between each pair of
- boolean vectors. (see rogerstanimoto function documentation)
- 20. ``Y = pdist(X, 'russellrao')``
- Computes the Russell-Rao distance between each pair of
- boolean vectors. (see russellrao function documentation)
- 21. ``Y = pdist(X, 'sokalmichener')``
- Computes the Sokal-Michener distance between each pair of
- boolean vectors. (see sokalmichener function documentation)
- 22. ``Y = pdist(X, 'sokalsneath')``
- Computes the Sokal-Sneath distance between each pair of
- boolean vectors. (see sokalsneath function documentation)
- 23. ``Y = pdist(X, 'kulczynski1')``
- Computes the Kulczynski 1 distance between each pair of
- boolean vectors. (see kulczynski1 function documentation)
- 24. ``Y = pdist(X, f)``
- Computes the distance between all pairs of vectors in X
- using the user supplied 2-arity function f. For example,
- Euclidean distance between the vectors could be computed
- as follows::
- dm = pdist(X, lambda u, v: np.sqrt(((u-v)**2).sum()))
- Note that you should avoid passing a reference to one of
- the distance functions defined in this library. For example,::
- dm = pdist(X, sokalsneath)
- would calculate the pair-wise distances between the vectors in
- X using the Python function sokalsneath. This would result in
- sokalsneath being called :math:`{n \\choose 2}` times, which
- is inefficient. Instead, the optimized C version is more
- efficient, and we call it using the following syntax.::
- dm = pdist(X, 'sokalsneath')
- """
- # You can also call this as:
- # Y = pdist(X, 'test_abc')
- # where 'abc' is the metric being tested. This computes the distance
- # between all pairs of vectors in X using the distance metric 'abc' but
- # with a more succinct, verifiable, but less efficient implementation.
- X = _asarray_validated(X, sparse_ok=False, objects_ok=True, mask_ok=True,
- check_finite=False)
- s = X.shape
- if len(s) != 2:
- raise ValueError('A 2-dimensional array must be passed.')
- m, n = s
- if callable(metric):
- mstr = getattr(metric, '__name__', 'UnknownCustomMetric')
- metric_info = _METRIC_ALIAS.get(mstr, None)
- if metric_info is not None:
- X, typ, kwargs = _validate_pdist_input(
- X, m, n, metric_info, **kwargs)
- return _pdist_callable(X, metric=metric, out=out, **kwargs)
- elif isinstance(metric, str):
- mstr = metric.lower()
- metric_info = _METRIC_ALIAS.get(mstr, None)
- if metric_info is not None:
- pdist_fn = metric_info.pdist_func
- return pdist_fn(X, out=out, **kwargs)
- elif mstr.startswith("test_"):
- metric_info = _TEST_METRICS.get(mstr, None)
- if metric_info is None:
- raise ValueError(f'Unknown "Test" Distance Metric: {mstr[5:]}')
- X, typ, kwargs = _validate_pdist_input(
- X, m, n, metric_info, **kwargs)
- return _pdist_callable(
- X, metric=metric_info.dist_func, out=out, **kwargs)
- else:
- raise ValueError('Unknown Distance Metric: %s' % mstr)
- else:
- raise TypeError('2nd argument metric must be a string identifier '
- 'or a function.')
- def squareform(X, force="no", checks=True):
- """
- Convert a vector-form distance vector to a square-form distance
- matrix, and vice-versa.
- Parameters
- ----------
- X : array_like
- Either a condensed or redundant distance matrix.
- force : str, optional
- As with MATLAB(TM), if force is equal to ``'tovector'`` or
- ``'tomatrix'``, the input will be treated as a distance matrix or
- distance vector respectively.
- checks : bool, optional
- If set to False, no checks will be made for matrix
- symmetry nor zero diagonals. This is useful if it is known that
- ``X - X.T1`` is small and ``diag(X)`` is close to zero.
- These values are ignored any way so they do not disrupt the
- squareform transformation.
- Returns
- -------
- Y : ndarray
- If a condensed distance matrix is passed, a redundant one is
- returned, or if a redundant one is passed, a condensed distance
- matrix is returned.
- Notes
- -----
- 1. ``v = squareform(X)``
- Given a square n-by-n symmetric distance matrix ``X``,
- ``v = squareform(X)`` returns a ``n * (n-1) / 2``
- (i.e. binomial coefficient n choose 2) sized vector `v`
- where :math:`v[{n \\choose 2} - {n-i \\choose 2} + (j-i-1)]`
- is the distance between distinct points ``i`` and ``j``.
- If ``X`` is non-square or asymmetric, an error is raised.
- 2. ``X = squareform(v)``
- Given a ``n * (n-1) / 2`` sized vector ``v``
- for some integer ``n >= 1`` encoding distances as described,
- ``X = squareform(v)`` returns a n-by-n distance matrix ``X``.
- The ``X[i, j]`` and ``X[j, i]`` values are set to
- :math:`v[{n \\choose 2} - {n-i \\choose 2} + (j-i-1)]`
- and all diagonal elements are zero.
- In SciPy 0.19.0, ``squareform`` stopped casting all input types to
- float64, and started returning arrays of the same dtype as the input.
- """
- X = np.ascontiguousarray(X)
- s = X.shape
- if force.lower() == 'tomatrix':
- if len(s) != 1:
- raise ValueError("Forcing 'tomatrix' but input X is not a "
- "distance vector.")
- elif force.lower() == 'tovector':
- if len(s) != 2:
- raise ValueError("Forcing 'tovector' but input X is not a "
- "distance matrix.")
- # X = squareform(v)
- if len(s) == 1:
- if s[0] == 0:
- return np.zeros((1, 1), dtype=X.dtype)
- # Grab the closest value to the square root of the number
- # of elements times 2 to see if the number of elements
- # is indeed a binomial coefficient.
- d = int(np.ceil(np.sqrt(s[0] * 2)))
- # Check that v is of valid dimensions.
- if d * (d - 1) != s[0] * 2:
- raise ValueError('Incompatible vector size. It must be a binomial '
- 'coefficient n choose 2 for some integer n >= 2.')
- # Allocate memory for the distance matrix.
- M = np.zeros((d, d), dtype=X.dtype)
- # Since the C code does not support striding using strides.
- # The dimensions are used instead.
- X = _copy_array_if_base_present(X)
- # Fill in the values of the distance matrix.
- _distance_wrap.to_squareform_from_vector_wrap(M, X)
- # Return the distance matrix.
- return M
- elif len(s) == 2:
- if s[0] != s[1]:
- raise ValueError('The matrix argument must be square.')
- if checks:
- is_valid_dm(X, throw=True, name='X')
- # One-side of the dimensions is set here.
- d = s[0]
- if d <= 1:
- return np.array([], dtype=X.dtype)
- # Create a vector.
- v = np.zeros((d * (d - 1)) // 2, dtype=X.dtype)
- # Since the C code does not support striding using strides.
- # The dimensions are used instead.
- X = _copy_array_if_base_present(X)
- # Convert the vector to squareform.
- _distance_wrap.to_vector_from_squareform_wrap(X, v)
- return v
- else:
- raise ValueError(('The first argument must be one or two dimensional '
- 'array. A %d-dimensional array is not '
- 'permitted') % len(s))
- def is_valid_dm(D, tol=0.0, throw=False, name="D", warning=False):
- """
- Return True if input array is a valid distance matrix.
- Distance matrices must be 2-dimensional numpy arrays.
- They must have a zero-diagonal, and they must be symmetric.
- Parameters
- ----------
- D : array_like
- The candidate object to test for validity.
- tol : float, optional
- The distance matrix should be symmetric. `tol` is the maximum
- difference between entries ``ij`` and ``ji`` for the distance
- metric to be considered symmetric.
- throw : bool, optional
- An exception is thrown if the distance matrix passed is not valid.
- name : str, optional
- The name of the variable to checked. This is useful if
- throw is set to True so the offending variable can be identified
- in the exception message when an exception is thrown.
- warning : bool, optional
- Instead of throwing an exception, a warning message is
- raised.
- Returns
- -------
- valid : bool
- True if the variable `D` passed is a valid distance matrix.
- Notes
- -----
- Small numerical differences in `D` and `D.T` and non-zeroness of
- the diagonal are ignored if they are within the tolerance specified
- by `tol`.
- """
- D = np.asarray(D, order='c')
- valid = True
- try:
- s = D.shape
- if len(D.shape) != 2:
- if name:
- raise ValueError(('Distance matrix \'%s\' must have shape=2 '
- '(i.e. be two-dimensional).') % name)
- else:
- raise ValueError('Distance matrix must have shape=2 (i.e. '
- 'be two-dimensional).')
- if tol == 0.0:
- if not (D == D.T).all():
- if name:
- raise ValueError(('Distance matrix \'%s\' must be '
- 'symmetric.') % name)
- else:
- raise ValueError('Distance matrix must be symmetric.')
- if not (D[range(0, s[0]), range(0, s[0])] == 0).all():
- if name:
- raise ValueError(('Distance matrix \'%s\' diagonal must '
- 'be zero.') % name)
- else:
- raise ValueError('Distance matrix diagonal must be zero.')
- else:
- if not (D - D.T <= tol).all():
- if name:
- raise ValueError(('Distance matrix \'%s\' must be '
- 'symmetric within tolerance %5.5f.')
- % (name, tol))
- else:
- raise ValueError('Distance matrix must be symmetric within'
- ' tolerance %5.5f.' % tol)
- if not (D[range(0, s[0]), range(0, s[0])] <= tol).all():
- if name:
- raise ValueError(('Distance matrix \'%s\' diagonal must be'
- ' close to zero within tolerance %5.5f.')
- % (name, tol))
- else:
- raise ValueError(('Distance matrix \'%s\' diagonal must be'
- ' close to zero within tolerance %5.5f.')
- % tol)
- except Exception as e:
- if throw:
- raise
- if warning:
- warnings.warn(str(e))
- valid = False
- return valid
- def is_valid_y(y, warning=False, throw=False, name=None):
- """
- Return True if the input array is a valid condensed distance matrix.
- Condensed distance matrices must be 1-dimensional numpy arrays.
- Their length must be a binomial coefficient :math:`{n \\choose 2}`
- for some positive integer n.
- Parameters
- ----------
- y : array_like
- The condensed distance matrix.
- warning : bool, optional
- Invokes a warning if the variable passed is not a valid
- condensed distance matrix. The warning message explains why
- the distance matrix is not valid. `name` is used when
- referencing the offending variable.
- throw : bool, optional
- Throws an exception if the variable passed is not a valid
- condensed distance matrix.
- name : bool, optional
- Used when referencing the offending variable in the
- warning or exception message.
- """
- y = np.asarray(y, order='c')
- valid = True
- try:
- if len(y.shape) != 1:
- if name:
- raise ValueError(('Condensed distance matrix \'%s\' must '
- 'have shape=1 (i.e. be one-dimensional).')
- % name)
- else:
- raise ValueError('Condensed distance matrix must have shape=1 '
- '(i.e. be one-dimensional).')
- n = y.shape[0]
- d = int(np.ceil(np.sqrt(n * 2)))
- if (d * (d - 1) / 2) != n:
- if name:
- raise ValueError(('Length n of condensed distance matrix '
- '\'%s\' must be a binomial coefficient, i.e.'
- 'there must be a k such that '
- '(k \\choose 2)=n)!') % name)
- else:
- raise ValueError('Length n of condensed distance matrix must '
- 'be a binomial coefficient, i.e. there must '
- 'be a k such that (k \\choose 2)=n)!')
- except Exception as e:
- if throw:
- raise
- if warning:
- warnings.warn(str(e))
- valid = False
- return valid
- def num_obs_dm(d):
- """
- Return the number of original observations that correspond to a
- square, redundant distance matrix.
- Parameters
- ----------
- d : array_like
- The target distance matrix.
- Returns
- -------
- num_obs_dm : int
- The number of observations in the redundant distance matrix.
- """
- d = np.asarray(d, order='c')
- is_valid_dm(d, tol=np.inf, throw=True, name='d')
- return d.shape[0]
- def num_obs_y(Y):
- """
- Return the number of original observations that correspond to a
- condensed distance matrix.
- Parameters
- ----------
- Y : array_like
- Condensed distance matrix.
- Returns
- -------
- n : int
- The number of observations in the condensed distance matrix `Y`.
- """
- Y = np.asarray(Y, order='c')
- is_valid_y(Y, throw=True, name='Y')
- k = Y.shape[0]
- if k == 0:
- raise ValueError("The number of observations cannot be determined on "
- "an empty distance matrix.")
- d = int(np.ceil(np.sqrt(k * 2)))
- if (d * (d - 1) / 2) != k:
- raise ValueError("Invalid condensed distance matrix passed. Must be "
- "some k where k=(n choose 2) for some n >= 2.")
- return d
- def _prepare_out_argument(out, dtype, expected_shape):
- if out is None:
- return np.empty(expected_shape, dtype=dtype)
- if out.shape != expected_shape:
- raise ValueError("Output array has incorrect shape.")
- if not out.flags.c_contiguous:
- raise ValueError("Output array must be C-contiguous.")
- if out.dtype != np.double:
- raise ValueError("Output array must be double type.")
- return out
- def _pdist_callable(X, *, out, metric, **kwargs):
- n = X.shape[0]
- out_size = (n * (n - 1)) // 2
- dm = _prepare_out_argument(out, np.double, (out_size,))
- k = 0
- for i in range(X.shape[0] - 1):
- for j in range(i + 1, X.shape[0]):
- dm[k] = metric(X[i], X[j], **kwargs)
- k += 1
- return dm
- def _cdist_callable(XA, XB, *, out, metric, **kwargs):
- mA = XA.shape[0]
- mB = XB.shape[0]
- dm = _prepare_out_argument(out, np.double, (mA, mB))
- for i in range(mA):
- for j in range(mB):
- dm[i, j] = metric(XA[i], XB[j], **kwargs)
- return dm
- def cdist(XA, XB, metric='euclidean', *, out=None, **kwargs):
- """
- Compute distance between each pair of the two collections of inputs.
- See Notes for common calling conventions.
- Parameters
- ----------
- XA : array_like
- An :math:`m_A` by :math:`n` array of :math:`m_A`
- original observations in an :math:`n`-dimensional space.
- Inputs are converted to float type.
- XB : array_like
- An :math:`m_B` by :math:`n` array of :math:`m_B`
- original observations in an :math:`n`-dimensional space.
- Inputs are converted to float type.
- metric : str or callable, optional
- The distance metric to use. If a string, the distance function can be
- 'braycurtis', 'canberra', 'chebyshev', 'cityblock', 'correlation',
- 'cosine', 'dice', 'euclidean', 'hamming', 'jaccard', 'jensenshannon',
- 'kulczynski1', 'mahalanobis', 'matching', 'minkowski',
- 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener',
- 'sokalsneath', 'sqeuclidean', 'yule'.
- **kwargs : dict, optional
- Extra arguments to `metric`: refer to each metric documentation for a
- list of all possible arguments.
- Some possible arguments:
- p : scalar
- The p-norm to apply for Minkowski, weighted and unweighted.
- Default: 2.
- w : array_like
- The weight vector for metrics that support weights (e.g., Minkowski).
- V : array_like
- The variance vector for standardized Euclidean.
- Default: var(vstack([XA, XB]), axis=0, ddof=1)
- VI : array_like
- The inverse of the covariance matrix for Mahalanobis.
- Default: inv(cov(vstack([XA, XB].T))).T
- out : ndarray
- The output array
- If not None, the distance matrix Y is stored in this array.
- Returns
- -------
- Y : ndarray
- A :math:`m_A` by :math:`m_B` distance matrix is returned.
- For each :math:`i` and :math:`j`, the metric
- ``dist(u=XA[i], v=XB[j])`` is computed and stored in the
- :math:`ij` th entry.
- Raises
- ------
- ValueError
- An exception is thrown if `XA` and `XB` do not have
- the same number of columns.
- Notes
- -----
- The following are common calling conventions:
- 1. ``Y = cdist(XA, XB, 'euclidean')``
- Computes the distance between :math:`m` points using
- Euclidean distance (2-norm) as the distance metric between the
- points. The points are arranged as :math:`m`
- :math:`n`-dimensional row vectors in the matrix X.
- 2. ``Y = cdist(XA, XB, 'minkowski', p=2.)``
- Computes the distances using the Minkowski distance
- :math:`\\|u-v\\|_p` (:math:`p`-norm) where :math:`p > 0` (note
- that this is only a quasi-metric if :math:`0 < p < 1`).
- 3. ``Y = cdist(XA, XB, 'cityblock')``
- Computes the city block or Manhattan distance between the
- points.
- 4. ``Y = cdist(XA, XB, 'seuclidean', V=None)``
- Computes the standardized Euclidean distance. The standardized
- Euclidean distance between two n-vectors ``u`` and ``v`` is
- .. math::
- \\sqrt{\\sum {(u_i-v_i)^2 / V[x_i]}}.
- V is the variance vector; V[i] is the variance computed over all
- the i'th components of the points. If not passed, it is
- automatically computed.
- 5. ``Y = cdist(XA, XB, 'sqeuclidean')``
- Computes the squared Euclidean distance :math:`\\|u-v\\|_2^2` between
- the vectors.
- 6. ``Y = cdist(XA, XB, 'cosine')``
- Computes the cosine distance between vectors u and v,
- .. math::
- 1 - \\frac{u \\cdot v}
- {{\\|u\\|}_2 {\\|v\\|}_2}
- where :math:`\\|*\\|_2` is the 2-norm of its argument ``*``, and
- :math:`u \\cdot v` is the dot product of :math:`u` and :math:`v`.
- 7. ``Y = cdist(XA, XB, 'correlation')``
- Computes the correlation distance between vectors u and v. This is
- .. math::
- 1 - \\frac{(u - \\bar{u}) \\cdot (v - \\bar{v})}
- {{\\|(u - \\bar{u})\\|}_2 {\\|(v - \\bar{v})\\|}_2}
- where :math:`\\bar{v}` is the mean of the elements of vector v,
- and :math:`x \\cdot y` is the dot product of :math:`x` and :math:`y`.
- 8. ``Y = cdist(XA, XB, 'hamming')``
- Computes the normalized Hamming distance, or the proportion of
- those vector elements between two n-vectors ``u`` and ``v``
- which disagree. To save memory, the matrix ``X`` can be of type
- boolean.
- 9. ``Y = cdist(XA, XB, 'jaccard')``
- Computes the Jaccard distance between the points. Given two
- vectors, ``u`` and ``v``, the Jaccard distance is the
- proportion of those elements ``u[i]`` and ``v[i]`` that
- disagree where at least one of them is non-zero.
- 10. ``Y = cdist(XA, XB, 'jensenshannon')``
- Computes the Jensen-Shannon distance between two probability arrays.
- Given two probability vectors, :math:`p` and :math:`q`, the
- Jensen-Shannon distance is
- .. math::
- \\sqrt{\\frac{D(p \\parallel m) + D(q \\parallel m)}{2}}
- where :math:`m` is the pointwise mean of :math:`p` and :math:`q`
- and :math:`D` is the Kullback-Leibler divergence.
- 11. ``Y = cdist(XA, XB, 'chebyshev')``
- Computes the Chebyshev distance between the points. The
- Chebyshev distance between two n-vectors ``u`` and ``v`` is the
- maximum norm-1 distance between their respective elements. More
- precisely, the distance is given by
- .. math::
- d(u,v) = \\max_i {|u_i-v_i|}.
- 12. ``Y = cdist(XA, XB, 'canberra')``
- Computes the Canberra distance between the points. The
- Canberra distance between two points ``u`` and ``v`` is
- .. math::
- d(u,v) = \\sum_i \\frac{|u_i-v_i|}
- {|u_i|+|v_i|}.
- 13. ``Y = cdist(XA, XB, 'braycurtis')``
- Computes the Bray-Curtis distance between the points. The
- Bray-Curtis distance between two points ``u`` and ``v`` is
- .. math::
- d(u,v) = \\frac{\\sum_i (|u_i-v_i|)}
- {\\sum_i (|u_i+v_i|)}
- 14. ``Y = cdist(XA, XB, 'mahalanobis', VI=None)``
- Computes the Mahalanobis distance between the points. The
- Mahalanobis distance between two points ``u`` and ``v`` is
- :math:`\\sqrt{(u-v)(1/V)(u-v)^T}` where :math:`(1/V)` (the ``VI``
- variable) is the inverse covariance. If ``VI`` is not None,
- ``VI`` will be used as the inverse covariance matrix.
- 15. ``Y = cdist(XA, XB, 'yule')``
- Computes the Yule distance between the boolean
- vectors. (see `yule` function documentation)
- 16. ``Y = cdist(XA, XB, 'matching')``
- Synonym for 'hamming'.
- 17. ``Y = cdist(XA, XB, 'dice')``
- Computes the Dice distance between the boolean vectors. (see
- `dice` function documentation)
- 18. ``Y = cdist(XA, XB, 'kulczynski1')``
- Computes the kulczynski distance between the boolean
- vectors. (see `kulczynski1` function documentation)
- 19. ``Y = cdist(XA, XB, 'rogerstanimoto')``
- Computes the Rogers-Tanimoto distance between the boolean
- vectors. (see `rogerstanimoto` function documentation)
- 20. ``Y = cdist(XA, XB, 'russellrao')``
- Computes the Russell-Rao distance between the boolean
- vectors. (see `russellrao` function documentation)
- 21. ``Y = cdist(XA, XB, 'sokalmichener')``
- Computes the Sokal-Michener distance between the boolean
- vectors. (see `sokalmichener` function documentation)
- 22. ``Y = cdist(XA, XB, 'sokalsneath')``
- Computes the Sokal-Sneath distance between the vectors. (see
- `sokalsneath` function documentation)
- 23. ``Y = cdist(XA, XB, f)``
- Computes the distance between all pairs of vectors in X
- using the user supplied 2-arity function f. For example,
- Euclidean distance between the vectors could be computed
- as follows::
- dm = cdist(XA, XB, lambda u, v: np.sqrt(((u-v)**2).sum()))
- Note that you should avoid passing a reference to one of
- the distance functions defined in this library. For example,::
- dm = cdist(XA, XB, sokalsneath)
- would calculate the pair-wise distances between the vectors in
- X using the Python function `sokalsneath`. This would result in
- sokalsneath being called :math:`{n \\choose 2}` times, which
- is inefficient. Instead, the optimized C version is more
- efficient, and we call it using the following syntax::
- dm = cdist(XA, XB, 'sokalsneath')
- Examples
- --------
- Find the Euclidean distances between four 2-D coordinates:
- >>> from scipy.spatial import distance
- >>> import numpy as np
- >>> coords = [(35.0456, -85.2672),
- ... (35.1174, -89.9711),
- ... (35.9728, -83.9422),
- ... (36.1667, -86.7833)]
- >>> distance.cdist(coords, coords, 'euclidean')
- array([[ 0. , 4.7044, 1.6172, 1.8856],
- [ 4.7044, 0. , 6.0893, 3.3561],
- [ 1.6172, 6.0893, 0. , 2.8477],
- [ 1.8856, 3.3561, 2.8477, 0. ]])
- Find the Manhattan distance from a 3-D point to the corners of the unit
- cube:
- >>> a = np.array([[0, 0, 0],
- ... [0, 0, 1],
- ... [0, 1, 0],
- ... [0, 1, 1],
- ... [1, 0, 0],
- ... [1, 0, 1],
- ... [1, 1, 0],
- ... [1, 1, 1]])
- >>> b = np.array([[ 0.1, 0.2, 0.4]])
- >>> distance.cdist(a, b, 'cityblock')
- array([[ 0.7],
- [ 0.9],
- [ 1.3],
- [ 1.5],
- [ 1.5],
- [ 1.7],
- [ 2.1],
- [ 2.3]])
- """
- # You can also call this as:
- # Y = cdist(XA, XB, 'test_abc')
- # where 'abc' is the metric being tested. This computes the distance
- # between all pairs of vectors in XA and XB using the distance metric 'abc'
- # but with a more succinct, verifiable, but less efficient implementation.
- XA = np.asarray(XA)
- XB = np.asarray(XB)
- s = XA.shape
- sB = XB.shape
- if len(s) != 2:
- raise ValueError('XA must be a 2-dimensional array.')
- if len(sB) != 2:
- raise ValueError('XB must be a 2-dimensional array.')
- if s[1] != sB[1]:
- raise ValueError('XA and XB must have the same number of columns '
- '(i.e. feature dimension.)')
- mA = s[0]
- mB = sB[0]
- n = s[1]
- if callable(metric):
- mstr = getattr(metric, '__name__', 'Unknown')
- metric_info = _METRIC_ALIAS.get(mstr, None)
- if metric_info is not None:
- XA, XB, typ, kwargs = _validate_cdist_input(
- XA, XB, mA, mB, n, metric_info, **kwargs)
- return _cdist_callable(XA, XB, metric=metric, out=out, **kwargs)
- elif isinstance(metric, str):
- mstr = metric.lower()
- metric_info = _METRIC_ALIAS.get(mstr, None)
- if metric_info is not None:
- cdist_fn = metric_info.cdist_func
- return cdist_fn(XA, XB, out=out, **kwargs)
- elif mstr.startswith("test_"):
- metric_info = _TEST_METRICS.get(mstr, None)
- if metric_info is None:
- raise ValueError(f'Unknown "Test" Distance Metric: {mstr[5:]}')
- XA, XB, typ, kwargs = _validate_cdist_input(
- XA, XB, mA, mB, n, metric_info, **kwargs)
- return _cdist_callable(
- XA, XB, metric=metric_info.dist_func, out=out, **kwargs)
- else:
- raise ValueError('Unknown Distance Metric: %s' % mstr)
- else:
- raise TypeError('2nd argument metric must be a string identifier '
- 'or a function.')
|