如何从scikit-learn MDS计算解释方差?预计算矩阵是否为经典MDS?
好问题!这确实是scikit-learn MDS模块的一个常见困惑点,我来逐一拆解你的问题:
问题1:如何从scikit-learn的MDS计算解释方差
首先明确:scikit-learn的MDS类实现的是SMACOF算法,属于迭代式的非经典度量MDS,它不像经典MDS那样直接基于特征分解输出特征值。所以你提到的那个针对经典MDS的特征值提取方法确实不适用。
不过,我们可以手动近似计算解释方差,核心思路是衡量SMACOF得到的低维嵌入对原始相异矩阵的拟合程度,具体步骤如下:
- 用MDS得到低维嵌入后,计算嵌入空间中的重构距离矩阵
- 计算原始相异矩阵与重构矩阵的平方误差(对应SMACOF的应力分子)
- 用经典MDS中的双重中心化矩阵的迹来代表原始数据的总方差
- 解释方差 = 1 - (平方误差 / 总方差)
下面是完整的代码示例:
from sklearn.manifold import MDS import numpy as np # 示例:预计算的对称相异矩阵 np.random.seed(42) D = np.random.rand(15, 15) D = (D + D.T) / 2 # 确保矩阵对称 np.fill_diagonal(D, 0) # 对角线元素为0 # 拟合MDS模型 mds = MDS(n_components=2, dissimilarity="precomputed", random_state=42) embedding = mds.fit_transform(D) # 步骤1:计算嵌入空间的重构距离矩阵 d_hat = np.sqrt(((embedding[:, np.newaxis] - embedding) ** 2).sum(axis=2)) # 步骤2:计算原始与重构矩阵的平方误差 sse = ((D - d_hat) ** 2).sum() # 步骤3:计算原始相异矩阵的总方差(基于经典MDS的双重中心化) D_sq = D ** 2 row_means = D_sq.mean(axis=1, keepdims=True) col_means = D_sq.mean(axis=0, keepdims=True) grand_mean = D_sq.mean() # 双重中心化后的矩阵B B = -0.5 * (D_sq - row_means - col_means + grand_mean) # B的迹等于所有特征值之和,即总方差 total_variance = np.trace(B) # 步骤4:计算解释方差 explained_variance = 1 - (sse / total_variance) print(f"近似解释方差: {explained_variance:.4f}")
注意:这个值是近似值,因为SMACOF的目标是最小化应力,而不是直接最大化方差解释率,但它能有效衡量嵌入的拟合质量。
问题2:使用预计算相异矩阵时,scikit-learn的MDS是否运行经典MDS?
答案是否定的。无论你使用dissimilarity='precomputed'还是'euclidean',scikit-learn的MDS始终使用SMACOF算法,不会切换到经典MDS的特征分解方法。
经典MDS其实是SMACOF的一个特例:当原始相异矩阵可以被完美嵌入到低维空间(即应力为0)时,SMACOF的迭代结果会和经典MDS一致,但算法本身仍然是通过迭代优化应力函数来求解,而非直接对双重中心化矩阵做特征分解。
如果你确实需要经典MDS的特征值和精确的方差解释率,你可以手动实现经典MDS的特征分解逻辑,或者使用其他工具来完成。
内容的提问来源于stack exchange,提问作者thestatnoob
相关产品推荐
相关产品推荐

