Constructs coordinates from squared distances using Classical Multi-Dimensional Scaling.
CMDS is a coordinatization algorithm that generates d-dimensional coordinates from a Euclidean distance matrix D. Algorithmically, D is converted into a doubly-centered Gram matrix G whose eigen decomposition is used to produce coordinates minimizing a notion of ‘strain’.
Parameters
Name
Type
Description
Default
D
ArrayLike
Squared Euclidean distance matrix, or set of (squared) pairwise distances.
required
d
int
dimension of the embedding to produce.
2
coords
bool
whether to return the embedding (default = True), or just return the eigenvectors
True
Returns
Type
Description
Union[np.ndarray, tuple]
if coords = True, the coordinates from the largest d eigenvectors of G’s eigendecomposition. Otherwise, the eigenvalues and eigenvectors are returned. See the Examples section for more details.
Notes
PCA is dual to CMDS in the sense that the embedding produced by CMDS on the Euclidean distance matrix from X satisfies the same reconstruction loss as with PCA. In particular, when X comes from Euclidean space, the output of pca(…) will match the output of cmds(…) exactly up to rotation and translation.
import numpy as np from geomcover.linalg import pca, cmds## Start with a random set of points in R^3 + its distance matrixX = np.random.uniform(size=(50,3))D = np.linalg.norm(X - X[:,np.newaxis], axis=2)## Note that CMDS takes as input *squared* distancesY_pca = pca(X, d=2)Y_mds = cmds(D**2, d=2)## Get distance matrices for both embeddingsY_pca_D = np.linalg.norm(Y_pca - Y_pca[:,np.newaxis], axis=2)Y_mds_D = np.linalg.norm(Y_mds - Y_mds[:,np.newaxis], axis=2)## Up to rotation and translation, the coordinates are identicalall_close = np.allclose(Y_pca_D, Y_mds_D)print(f"PCA and MDS coord. distances identical? {all_close}")