FactoMineR::PCA()与base::prcomp()结果不一致问题问询
为什么FactoMineR::PCA和base::prcomp的PCA结果不一致?
你遇到的这个差异其实是两个函数在PCA实现细节上的几个关键不同点导致的,我来逐一拆解:
1. 主成分的符号差异
主成分本身的方向是任意的——只要它能解释相同的方差,正负方向都是有效的。你看到的“数值相似但不完全相同”很可能是主成分的符号相反,比如prcomp的第一主成分是[1.2, -3.4, ...],而FactoMineR的是[-1.2, 3.4, ...],这属于正常现象,完全不影响PCA的解释效果。
2. 标准化(缩放)的计算细节不同
这是最容易导致数值差异的核心原因:
prcomp(scale. = TRUE)使用样本标准差计算标准化,也就是除以n-1(无偏估计);FactoMineR::PCA(scale.unit = TRUE)使用总体标准差计算标准化,也就是除以n(有偏估计)。
你尝试用scale(df)后再传入FactoMineR的PCA,但scale()默认也是用样本标准差(除以n-1),这时候如果设置scale.unit = FALSE,理论上应该和prcomp的标准化结果一致,但可能因为后续计算路径的不同,还存在微小的浮点精度差异。
验证这一点可以手动计算:
# 手动计算两种标准差 sd_sample <- apply(df, 2, sd) # 样本标准差(n-1) sd_pop <- apply(df, 2, function(x) sqrt(mean((x-mean(x))^2))) # 总体标准差(n) # 对比两者的比值,n=64时应该接近sqrt(64/63)≈1.0079 head(sd_sample / sd_pop)
3. 主成分数量的差异
当样本数n小于特征数p时(比如NCI60的64个样本,6830个特征),PCA最多只能生成n-1个有意义的主成分(因为协方差矩阵的秩最多是n-1):
prcomp会自动返回所有n-1个主成分;FactoMineR::PCA的ncp参数如果设置大于n-1,实际只会返回n-1个主成分,但你看到的“缺失一列”可能是因为浮点精度问题,某个方差接近0的主成分被函数自动过滤,或是两者对矩阵秩的判断略有不同。
4. 底层计算方法的差异
prcomp采用**奇异值分解(SVD)**来计算PCA,这种方法数值稳定性更好;FactoMineR::PCA则是基于协方差矩阵的特征值分解,当特征数远大于样本数时,协方差矩阵的计算可能引入更多数值误差,导致结果和SVD方法有微小差异。
如何让两者结果一致?
如果你想让两个函数的结果尽可能对齐,可以这样做:
# 方法1:prcomp使用总体标准差标准化 df_scaled_pop <- scale(df, center = TRUE, scale = apply(df, 2, function(x) sqrt(mean((x-mean(x))^2)))) pca_prcomp_pop <- prcomp(df_scaled_pop, scale. = FALSE) # 方法2:FactoMineR使用样本标准差标准化 df_scaled_sample <- scale(df) pca_facto_sample <- FactoMineR::PCA(df_scaled_sample, scale.unit = FALSE, graph = FALSE, ncp = 63) # 调整符号后对比,数值绝对值应该几乎一致 head(pca_prcomp_pop$x[,1] * -1) head(pca_facto_sample$ind$coord[,1])
内容的提问来源于stack exchange,提问作者MLEN




