跳转至

11.5   多维标度法

小率拿来一张城市距离表:每两个城市之间有多远都知道,但没有经纬度。他想只靠这张距离表,把城市的相对位置画出来。

图 11.5.1 小率用城市距离表还原位置

城市 A B C D
A 0 5 9 10
B 5 0 7 8
C 9 7 0 4
D 10 8 4 0
只有距离,没有坐标,也能画地图吗?
能。MDS 就是把距离矩阵还原成低维坐标。

11.5.1   从距离表反推坐标

多维尺度分析(Multidimensional Scaling, MDS)的输入不是原始变量表,而是样本两两之间的距离矩阵。它输出一组低维坐标,让新坐标里的点间距离尽量接近原来的距离。

图 11.5.2 MDS 从距离矩阵走向低维坐标

如果原始距离是 \(d_{ij}\),低维坐标是 \(z_i\)\(z_j\),MDS 希望:

\[ \|z_i-z_j\|\approx d_{ij} \]
它不是在看变量,而是在看“谁离谁近”。
对,所以 MDS 特别适合品牌相似度、城市距离、样本距离这类数据。

11.5.2   经典 MDS:欧氏距离的代数解

经典 MDS 适合欧氏距离。它先把距离矩阵转成内积矩阵,再做特征分解:

\[ B=-\frac12 JD^{(2)}J \]

其中:

\[ J=I-\frac1n\mathbf{1}\mathbf{1}^\top \]

\(B\) 做特征分解后,取前 \(k\) 个正特征值和对应特征向量,就能得到低维坐标。

你知道吗

如果距离来自原始数据的欧氏距离,经典 MDS 与 PCA 有很深的联系:一个从数据矩阵出发,一个从距离矩阵出发,最后都在寻找低维表示。

11.5.3   度量 MDS:用 Stress 衡量还原误差

度量 MDS 直接最小化距离误差。常用指标叫 Stress:

\[ \text{Stress}=\sqrt{\frac{\sum_{i<j}(\hat d_{ij}-d_{ij})^2}{\sum_{i<j}d_{ij}^2}} \]

Stress 越小,说明低维图越好地保留了原距离。

Stress 读法
< 0.05 很好
0.05-0.10 良好
0.10-0.20 勉强可用
> 0.20 低维图可能误导

11.5.4   方向和镜像不重要

MDS 只保留距离,所以输出图整体平移、旋转、翻转都不算错。城市图如果上下颠倒,只要城市之间的相对距离对,旋转一下就好。

也就是说,MDS 图的坐标轴本身没什么物理含义?
对。别执着坐标轴,先看距离结构。

11.5.5   用 Python 跑 MDS

完整脚本放在:

docs/assets/scripts/ch11_multivariate/05_multidimensional_scaling/main.py
import numpy as np
from sklearn.manifold import MDS

D = np.array([
    [0, 5, 9, 10],
    [5, 0, 7, 8],
    [9, 7, 0, 4],
    [10, 8, 4, 0],
], dtype=float)

mds = MDS(
    n_components=2,
    dissimilarity="precomputed",
    random_state=42,
    normalized_stress="auto",
)
Z = mds.fit_transform(D)

print("二维坐标:")
print(np.round(Z, 2))
print("Stress:", round(mds.stress_, 3))

11.5.6   MDS 和 t-SNE、UMAP 的关系

方法 主要保留 适合
PCA 方差 线性降维、解释主轴
MDS 两两距离 距离矩阵、相似度数据
t-SNE 局部邻域 只为看簇
UMAP 局部结构兼顾全局 大数据可视化

需要注意

t-SNE 图上簇之间的远近不一定可信;MDS 更直接地把“距离保留”作为目标,但高维复杂结构压到二维时也会有损失。

小率的笔记本

MDS 的输入是距离矩阵,输出是低维坐标。它尽量让低维图上的点间距离接近原距离;Stress 用来衡量还原误差。MDS 图可以整体旋转或镜像,坐标轴方向不需要过度解释。