如何计算R中的varimax旋转主成分?


13

我对25个变量运行PCA,并使用选择了前7台PC prcomp

prc <- prcomp(pollutions, center=T, scale=T, retx=T)

然后,我对这些组件进行了varimax旋转。

varimax7 <- varimax(prc$rotation[,1:7])

现在,我希望使用varimax旋转PCA旋转的数据(因为它不是varimax对象的一部分-仅包含加载矩阵和旋转矩阵)。我读到要做到这一点,您需要将旋转矩阵的转置乘以数据的转置,所以我会这样做:

newData <- t(varimax7$rotmat) %*% t(prc$x[,1:7])

但这没有意义,因为上面转置的矩阵的尺寸分别是7 × 16933,所以我将只剩下7行矩阵,而不是16933行...有人知道吗?在这里做错了还是我的最后一行应该是什么?之后是否只需要移调回位?7×77×16933716933

Answers:


22

“轮换”是因子分析中开发的一种方法;在此,将旋转(例如varimax)应用于载荷,而不应用于协方差矩阵的特征向量。载荷是通过各自特征值的平方根缩放的特征向量。在varimax旋转之后,加载向量不再正交(即使旋转称为“正交”),因此不能简单地计算数据在旋转的加载方向上的正交投影。

@FTusell的答案假定将varimax旋转应用于特征向量(而不是载荷)。这将非常不合常规。请查看我对PCA + varimax的详细说明以获取详细信息:PCA后跟旋转(例如varimax)是否仍然是PCA?简单地说,如果我们看数据矩阵的SVD ,然后以旋转负荷装置插入- [R [R 一段旋转矩阵[R ,如下所示:X = Û - [R ) - [R 小号V X=USVRRRX=(UR)(RSV).

如果将旋转应用于载荷(通常如此),那么至少有三种简单的方法可以计算R中的varimax旋转的PC:

  1. 通过函数可以很容易地获得它们psych::principal(表明这确实是标准方法)。请注意,它返回标准化分数,即所有PC均具有单位差异。

  2. 可以手动使用varimax功能旋转载荷,然后使用新的旋转载荷获得分数。一个人需要用旋转载荷的转置伪逆来倍增数据(请参阅@ttnphns在此答案中的公式)。这也将产生标准化分数。

  3. 可以使用varimax函数旋转载荷,然后使用$rotmat旋转矩阵旋转通过获得的标准化分数prcomp

这三种方法均产生相同的结果:

irisX <- iris[,1:4]      # Iris data
ncomp <- 2

pca_iris_rotated <- psych::principal(irisX, rotate="varimax", nfactors=ncomp, scores=TRUE)
print(pca_iris_rotated$scores[1:5,])  # Scores returned by principal()

pca_iris        <- prcomp(irisX, center=T, scale=T)
rawLoadings     <- pca_iris$rotation[,1:ncomp] %*% diag(pca_iris$sdev, ncomp, ncomp)
rotatedLoadings <- varimax(rawLoadings)$loadings
invLoadings     <- t(pracma::pinv(rotatedLoadings))
scores          <- scale(irisX) %*% invLoadings
print(scores[1:5,])                   # Scores computed via rotated loadings

scores <- scale(pca_iris$x[,1:2]) %*% varimax(rawLoadings)$rotmat
print(scores[1:5,])                   # Scores computed via rotating the scores

这将产生三个相同的输出:

1 -1.083475  0.9067262
2 -1.377536 -0.2648876
3 -1.419832  0.1165198
4 -1.471607 -0.1474634
5 -1.095296  1.0949536

注意:varimax R中的函数normalize = TRUE, eps = 1e-5默认情况下使用参数(请参阅文档)。eps将结果与其他软件(例如SPSS)进行比较时,可能要更改这些参数(降低公差并注意Kaiser归一化)。感谢@GottfriedHelms引起我的注意。[注意:这些参数在传递给varimax函数时起作用,但在传递给psych::principal函数时不起作用。这似乎是一个已修复的错误。]


1
我现在看到了,我认为您是正确的。我将编辑原始答案(或添加另一个答案)以跟踪差异的来源。我非常喜欢您和@ttnphns的答案,这些答案非常完整且令人耳目一新,提供了书中通常找不到的详细解释。
F. Tusell

@amoeba我试图做一个PCA +方差最大使用principalprcompprincomp,但由此产生的负载/研究结论是彼此非常不同。据我了解,prcomp和princomp不会返回标准化分数或加载。我的问题是:最好的方法是什么?我真的想要标准化的结果吗?我的代码pca_iris <- prcomp(irisX, center=T, scale=T)varimax(pca_iris$rotation)$loadings上面的代码不一样吗?
JMarcelino

@JMarcelino,不,您的代码在特征向量上而不是在载荷上进行varimax-rotation。这不是通常理解或应用varimax旋转的方式。
变形虫说恢复莫妮卡

1
X=USVRRRX=URRSVL=VSR/n1,因此X=Ť大号你知道XL; 如何获得T?那么,答案是Ť=X大号+=X大号+T=URn1
X=TL.
XLT
T=X(L)+=X(L+).
变形虫说恢复莫妮卡

1
我得到了软件包Revelle的维护者的答复。在处理过程中的参数时似乎是一个错误,该principal过程始终使用Kaiser归一化和eps = 1e-5进行计算。到目前为止,没有任何信息,为什么在r-fiddle.org上该版本可以正常工作。因此,我们应该等待更新-我应该删除所有现在过时的注释。变形虫-最好相应地更新答案中的备注。感谢您的合作!
戈特弗里德·赫尔姆斯

9

您需要使用矩阵 $loadings,而不是$rotmat

 x <- matrix(rnorm(600),60,10)
 prc <- prcomp(x, center=TRUE, scale=TRUE)
 varimax7 <- varimax(prc$rotation[,1:7])
 newData <- scale(x) %*% varimax7$loadings

矩阵$rotmat是正交矩阵,它从未旋转的载荷中产生新的载荷。

截至2015年2月12日的修改:

n×mX

X=USVT
VXX
X=(UST)(TTVT)=UV
TVVUX(V)Tk<mkX
X(UkSk)(VkT)
X(UkSkTk)(TkTVkT)=UkVk
Vkk×nXVk,但是我们需要诉诸@amoeba描述的解决方案之一。

换句话说,我提出的解决方案仅在无用且无意义的特定情况下才是正确的。

衷心感谢@amoeba向我澄清这件事;多年来,我一直对这种误解感到困惑。

SVLVSviTX (i=1,,m)vi=1。我认为,任何一种方式都是可以接受的,介于两者之间的所有内容(如双图分析中)。

进一步编辑2015年2月12日

VkVk(Vk)TX(Vk)TUk


1
啊对了。我很困惑,因为prcomp的加载称为“旋转”,应该更好地阅读帮助。因为我在prcomp方法中使用“ center = TRUE,scale = TRUE”,这是否意味着我真的应该在将数据乘以varimax $ loadings之前对数据进行居中和缩放?
斯科特,

1
是的,很好,我的错。居中并不重要,就好像只移动点一样,但缩放比例应与用于计算主分量的比例相同,而缩放的比例不变。
F. Tusell

2
我忘了提一下,如果您还没有看过函数,可能要看一下。它进行因子分析,而不是主要成分,但将直接返回分数。
F. Tusell

2
-1。我相信这个答案是不正确的,我发表了自己的答案来证明这一点。人们无法通过正交投影投射到旋转的载荷上来获得旋转的分数(因为它们不再正交)。获得正确分数的最简单方法是使用psych::principal。[除此之外,我编辑了您的答案以插入缩放比例,如上面的评论中所述。]
变形虫说Reinstate Monica

1
Vkk×nV(TkTVkT)(VkTk)

0

我一直在寻找一种适用于使用ade4执行的PCA的解决方案。

请在下面找到功能:

library(ade4)

irisX <- iris[,1:4]      # Iris data
ncomp <- 2
# With ade4
dudi_iris <- dudi.pca(irisX, scannf = FALSE, nf = ncomp)

rotate_dudi.pca <- function(pca, ncomp = 2) {

  rawLoadings <- as.matrix(pca$c1[,1:ncomp]) %*% diag(sqrt(pca$eig), ncomp, ncomp)
  pca$c1 <- rawLoadings
  pca$li <- scale(pca$li[,1:ncomp]) %*% varimax(rawLoadings)$rotmat

  return(pca)
} 
rot_iris <- rotate_dudi.pca(pca = dudi_iris, ncomp = ncomp)
print(rot_iris$li[1:5,])                   # Scores computed via rotating the scores
#>        [,1]       [,2]
#> 1 -1.083475 -0.9067262
#> 2 -1.377536  0.2648876
#> 3 -1.419832 -0.1165198
#> 4 -1.471607  0.1474634
#> 5 -1.095296 -1.0949536

reprex软件包(v0.3.0)创建于2020-01-14

希望有帮助!


您需要使用此空间作为答案。
Michael R. Chernick

在我看来,增加完整性的答案是正确的。像这个问题一样:stackoverflow.com/questions/6862742/draw-a-circle-with-ggplot2。如有必要,我将很乐意提出我的建议。
阿兰·戴内

我误解了,因为听起来您正在对其中一个答案中的错误进行更正。我看到它是特定软件包ad4的补充。交叉验证不会查看仅与代码有关的问题或答案。堆栈溢出是解决软件问题的地方。
Michael R. Chernick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.