scipy.spatial.distance.cdist computes the distance between every row of one array and every row of a second array. If the first array has mA rows and the second has mB rows, the result is an (mA, mB) matrix whose entry at position (i, j) is the distance between row i of the first array and row j of the second. The default metric is Euclidean.
The function signature and what it expects
The function is called as follows, based on SciPy’s v1.18.0 API reference for cdist:
As an Amazon Associate I earn from qualifying purchases.
scipy.spatial.distance.cdist(XA, XB, metric='euclidean', *, out=None, **kwargs)
Three rules govern every call:
- Both inputs must be two-dimensional. Each row is one observation and each column is one feature.
- The column counts must match. If
XA.shape[1]differs fromXB.shape[1], SciPy raises aValueError. The number of rows may differ. - Inputs are converted to floating point. Integer or Boolean arrays are accepted, but the metric is computed on float values, so interpret Boolean inputs with the metric choice in mind (see below).
A worked shape example
Take two small arrays with two observations in XA and three in XB, each having two features:
import numpy as np
from scipy.spatial.distance import cdist
XA = np.array([[0, 0], [1, 1]]) # shape (2, 2)
XB = np.array([[1, 0], [2, 2], [0, 2]]) # shape (3, 2)
D = cdist(XA, XB, metric="euclidean")
print(D.shape) # (2, 3)
The output has one row per observation in XA and one column per observation in XB. Working the Euclidean arithmetic by hand gives the following values, rounded to three decimals:
#1 Best Overall
| Row in XA | Distance to XB[0] = (1, 0) | Distance to XB[1] = (2, 2) | Distance to XB[2] = (0, 2) |
|---|---|---|---|
| XA[0] = (0, 0) | 1.000 | 2.828 | 2.000 |
| XA[1] = (1, 1) | 1.000 | 1.414 | 1.414 |
Each cell is a single pair comparison, so the matrix size is always the product of the two collection sizes. That property matters for memory, discussed later.
Choosing a distance metric
The metric argument determines what “distance” means. The same two arrays can produce very different matrices under different metrics, so the choice should follow from what each feature represents rather than from the default. The table below lists the common string names SciPy accepts and the situations each one fits. The definitions follow SciPy’s API reference; the table is a selection aid, not a ranking, because no metric is universally correct.
| Metric string | What it measures | Typical use | Extra arguments |
|---|---|---|---|
euclidean (default) |
Straight-line (L2) distance between feature vectors | Ordinary geometric distance in numeric feature space | None |
cityblock |
Sum of absolute coordinate differences (Manhattan distance) | Grid-like movement; features where axis-by-axis differences should add up | None |
cosine |
One minus the cosine similarity; ignores vector magnitude | Direction-based comparison, such as text or embedding vectors | None |
correlation |
Distance based on the correlation between the two vectors | Comparing profiles whose shape matters more than level | None |
hamming |
Proportion of positions where the two vectors disagree | Discrete or categorical vectors of equal length | None |
jaccard |
Disagreement among positions where at least one vector is nonzero | Set-like binary features, where shared absences should not count as similarity | None |
minkowski |
The general p-norm distance | Tuning sensitivity to large versus small differences | p; p=2 equals Euclidean |
seuclidean |
Euclidean distance with each feature divided by a standard deviation | Features on different scales | V, the variance vector |
mahalanobis |
Distance that accounts for covariance between features | Correlated features where covariance should shape the distance | VI, the inverse covariance matrix |
Arguments for metrics that need them
Some metrics accept parameters through **kwargs. For minkowski, the p value sets the norm. For seuclidean, V supplies per-feature variances. For mahalanobis, VI supplies the inverse covariance matrix. If you omit V or VI, SciPy can derive defaults from the stacked inputs. That convenience has a cost: the scale or covariance then reflects only the data you passed in this call. When the analysis needs a fixed reference (for example, a training-set covariance applied to new data), compute V or VI yourself and pass it explicitly.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallfrom scipy.spatial.distance import cdist
# Minkowski with p=3
D3 = cdist(XA, XB, metric="minkowski", p=3)
# Mahalanobis with an explicit inverse covariance matrix
VI = np.linalg.inv(np.cov(np.vstack([XA, XB]).T))
Dm = cdist(XA, XB, metric="mahalanobis", VI=VI)
Match the metric to the data type
Boolean and set metrics such as hamming and jaccard treat each position as a category or presence flag. Numeric metrics such as euclidean and cityblock treat each position as a magnitude. Applying a numeric metric to one-hot or presence/absence data can still run without error, but the distances then answer a different question. Also note that numeric metrics are sensitive to feature scale: a feature measured in thousands will dominate a feature measured in fractions unless you standardize first or use seuclidean.
Rank #3
cdist versus pdist and squareform
SciPy also provides pdist, which computes distances among observations within a single collection. The two functions answer different questions, and choosing between them mainly depends on whether the two sets are the same.
| Aspect | cdist(XA, XB) |
pdist(X) |
|---|---|---|
| Inputs | Two collections | One collection |
| Pairs compared | Every row of XA against every row of XB | Every unique pair of rows within X |
| Output | Full rectangular matrix, shape (mA, mB) |
Condensed one-dimensional vector of length m(m-1)/2 |
| Typical question | How does each new item compare with each reference item? | How far apart are the items in one dataset from each other? |
When pdist is the better fit
Use pdist when you need only the unique pairwise distances inside one dataset. It stores each pair once, so for a dataset of m observations it holds about half the values of a full square matrix. Clustering routines and similar workflows often consume this condensed form directly.
Rank #4
Converting with squareform
Use scipy.spatial.distance.squareform to move between the two representations. Passing a condensed vector returns a symmetric square matrix with zeros on the diagonal; passing a square matrix returns the condensed vector of its upper-triangle values.
Free tools Windows power users keep installed
One-click scans. No signup required.
from scipy.spatial.distance import pdist, squareform, cdist
X = np.array([[0, 0], [1, 1], [2, 0]])
condensed = pdist(X) # length 3 for m = 3
square = squareform(condensed) # shape (3, 3)
full = cdist(X, X) # shape (3, 3), same values as square
Why cdist(X, X) is not the same as pdist(X)
Passing the same array twice to cdist is valid and yields a square (m, m) matrix. That matrix includes the diagonal, where each observation is compared with itself; for Euclidean distance those entries are zero. Off-diagonal pairs appear twice, once in each direction, so the matrix is symmetric. pdist(X) stores each unique off-diagonal pair once and omits the diagonal. Both carry the same information, but they differ in size and layout, and code that expects one layout will break with the other.
Best Value
Common mistakes and checks
- Confirm column counts before the call. Check
XA.shape[1] == XB.shape[1]; a mismatch raisesValueError. - Pass a string name for built-in metrics. Write
metric="cityblock", not a hand-written Python function that reproduces it. SciPy’s documentation advises string names because a Python callable is invoked once for every pair, which is slower. - Plan for the size of the output. The result holds
mA * mBfloating-point values. For example, 50,000 rows against 50,000 rows produces 2.5 billion values, roughly 20 GB at 8 bytes each. Batch the rows ofXAwhen collections are large. - Standardize or set scale arguments deliberately. Review the meaning of
VandVIand where they were derived. - Do not expect symmetry from cdist with two different arrays. Only
cdist(X, X)yields a symmetric matrix.
Speed and memory notes
The documentation describes the performance trade-off qualitatively, not numerically. Built-in metrics given as strings use SciPy’s optimized implementations, while a Python callable adds per-pair overhead. This article does not report runtime or memory measurements for any metric, so treat the batching guidance above as a memory-planning rule derived from the output shape rather than a benchmark.
Version notes
The API described here matches SciPy’s v1.18.0 reference. Parameter names and available metrics can change between releases, so confirm the version you are running:
import scipy
print(scipy.__version__)
If the printed version differs from 1.18.0, check the cdist page for that release before relying on a specific keyword argument.
Quick Recap
“
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

