GPA: Rotation Optimization

GPAR Documentation

Rotation Optimization


Gradient projection rotation optimization routine used by various rotation objective.


    GPFRSorth(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, 
       method="varimax", methodArgs=NULL, randomStarts=0)
    GPFRSoblq(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, 
       method="quartimin", methodArgs=NULL, randomStarts=0)

    GPForth(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, 
       method="varimax", methodArgs=NULL)
    GPFoblq(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, 
       method="quartimin", methodArgs=NULL)



initial factor loadings matrix for which the rotation criterian is to be optimized.


initial rotation matrix.


see details.


convergence is assumed when the norm of the gradient is smaller than eps.


maximum number of iterations allowed in the main loop.


rotation objective criterian.


a list ofmethodArgs arguments passed to the rotation objective


number of random starts (GPFRSorth and GPFRSoblq)


Gradient projection (GP) rotation optimization routines developed by Jennrich (2001, 2002) and Bernaards and Jennrich (2005). These functions can be used directly to rotate a loadings matrix, or indirectly through a rotation objective passed to a factor estimation routine such as factanal. A rotation of a matrix A is defined as A %*% solve(t(Th)). In case of orthogonal rotation, the factors the rotation matrix Tmat is orthonormal, and the rotation simplifies to A %*% Th. The rotation matrix Th is computed by GP rotation.

The GPFRsorth and GPFRSoblq functions are the primary functions for orthogonal and oblique rotations, respectively. These two functions serve as wrapper functions for GPForth and GPFoblq, with the added functionality of multiple random starts. GPForth is the main GP algorithm for orthogonal rotation. GPFoblq is the main GP algorithm for oblique rotation. The GPForth and GPFoblq may be also be called directly.

Arguments in the wrapper functions GPFRsorth and GPFRSoblq are passed to GP algorithms. Functions require an initial loadings matrix A which fixes the equivalence class over which the optimization is done. It must be the solution to the orthogonal factor analysis problem as obtained from factanal or other factor estimation routines. The initial rotation matrix is given by the Tmat. By default the GP algorithm use the identity matrix as the initial rotation matrix.

For some rotation criteria local minima may exist. To start from random initial rotation matrices, the randomStarts argument is available in GPFRSorth and GPFRSoblq. The returned object includes the rotated loadings matrix with the lowest criterion value f among attemnpted starts.Technically, this does not have to be the global minimum. The randomStarts argument is not available GPForth and GPFoblq. However, for GPForth and GPFoblq a single random initial rotation matrix may be set by Tmat = Random.Start(ncol(A)).

The argument method can be used to specify a string indicating the rotation objective. Oblique rotation defaults to "quartimin" and orthogonal rotation defaults to "varimax". Available rotation objectives are "oblimin", "quartimin", "target", "pst", "oblimax", "entropy", "quartimax", "varimax", "simplimax", "bentler", "tandemI", "tandemII", "geomin", "cf", "infomax", "mccammon", bifactor, and "varimin". The string is prefixed with "vgQ." to give the actual function call. See vgQ for details.

Some rotation criteria ("oblimin", "target", "pst", "simplimax", "geomin", "cf") require one or more additional arguments. See link{rotations} for details and default values, if applicable.

For examples of the indirect use see rotations.

The argument normalize gives an indication of if and how any normalization should be done before rotation, and then undone after rotation. If normalize is FALSE (the default) no normalization is done. If normalize is TRUE then Kaiser normalization is done. (So squared row entries of normalized A sum to 1.0. This is sometimes called Horst normalization.) If normalize is a vector of length equal to the number of indicators (= number of rows of A) then the colums are divided by normalize before rotation and multiplied by normalize after rotation. If normalize is a function then it should take A as an argument and return a vector which is used like the vector above. See Nguyen and Waller (2022) for detailed investigation of normalization on factor rotations, including potential effect on qualitative interpretation of loadings.


A GPArotation object which is a list with elements


The rotated loadings, one column for each factor. If randomStarts were requested then this is the rotated loadings matrix with the lowest criterion value.


The rotation matrix, loadings %*% t(Th) = A.


A matrix recording the iterations of the rotation optimization.


A string indicating the rotation objective function.


A logical indicating if the rotation is orthogonal.


A logical indicating if convergence was obtained.


t(Th) %*% Th. The covariance matrix of the rotated factors. This will be the identity matrix for orthogonal rotations so is omitted (NULL) for the result from GPFRSorth and GPForth.


The gradient of the objective function at the rotated loadings.


A vector with characteristics of random starts (GPFRSorth and GPFRSoblq only; omitted if randomStarts =< 1).


Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert


Bernaards, C.A. and Jennrich, R.I. (2005) Gradient Projection Algorithms and Software for Arbitrary Rotation Criteria in Factor Analysis. Educational and Psychological Measurement, 65, 676–696.

Jennrich, R.I. (2001). A simple general procedure for orthogonal rotation. Psychometrika, 66, 289–306.

Jennrich, R.I. (2002). A simple general method for oblique rotation. Psychometrika, 67, 7–19.

Nguyen, H.V. and Waller, N.G. (2022). Local minima and factor rotations in exploratory factor analysis. Psychological Methods. Advance online publication.

See Also

Random.Start, factanal, oblimin, quartimin, targetT, targetQ, pstT, pstQ, oblimax, entropy, quartimax, Varimax, varimax, simplimax, bentlerT, bentlerQ, tandemI, tandemII, geominT, geominQ, bigeominT, bigeominQ, cfT, cfQ, equamax, parsimax, infomaxT, infomaxQ, mccammon, varimin, bifactorT, bifactorQ, promax


  # see rotations for more examples	
  data(Harman, package = "GPArotation")
  GPFRSorth(Harman8, method = "quartimax")
  GPFRSoblq(Harman8, method = "quartimin", normalize = TRUE)
  loadings( quartimin(Harman8, normalize = TRUE) )

  # using random starts
  data("WansbeekMeijer", package = "GPArotation")
  fa.unrotated  <- factanal(factors = 3, covmat=NetherlandsTV, normalize=TRUE, rotation="none")
  GPFRSoblq(loadings(fa.unrotated), normalize = TRUE, method = "oblimin", randomStarts = 100)
  oblimin(loadings(fa.unrotated), randomStarts=100)
  data(Thurstone, package = "GPArotation")
  geominQ(box26, normalize = TRUE, randomStarts=100)
  # displaying results of factor analysis rotation output
  origdigits <- options("digits")
  Abor.unrotated <- factanal(factors = 2, covmat = ability.cov, rotation = "none")
  Abor <- oblimin(loadings(Abor.unrotated), randomStarts = 20)
  print(Abor, sortLoadings=FALSE) #this matches the output passed to factanal
  print(Abor, Table=TRUE)
  print(Abor, rotateMat=TRUE)
  print(Abor, digits=2)
  # by default provides the structure matrix for oblique rotation
  summary(Abor, Structure=FALSE)
  options(digits = origdigits$digits)
  # GPArotation output does sort loadings, but use print to obtain if needed
  xusl <- quartimin(Harman8, normalize = TRUE, randomStarts=100)
  # loadings without ordering (default)
  max(abs(print(xusl)$loadings - xusl$loadings)) == 0 # FALSE
  # output sorted loadings via print (not default)
  xsl <- print(xusl)
  max(abs(print(xsl)$loadings - xsl$loadings)) == 0 # TRUE
  # Kaiser normalization is used when normalize=TRUE
  factanal(factors = 2, covmat = ability.cov, rotation = "oblimin", 
  			control=list(rotate=list(normalize = TRUE)))
  # Cureton-Mulaik normalization can be done by passing values to the rotation
  # may result in convergence problems
  NormalizingWeightCM <- function (L) {
    Dk <- diag(sqrt(diag(L %*% t(L)))^-1) %*% L
    wghts <- rep(0, nrow(L))
    fpls <- Dk[, 1]
    acosi <- acos(ncol(L)^(-1/2))
    for (i in 1:nrow(L)) {
    	num <- (acosi - acos(abs(fpls[i])))
        dem <- (acosi - (function(a, m) ifelse(abs(a) < (m^(-1/2)), pi/2, 0))(fpls[i], ncol(L)))
        wghts[i] <- cos(num/dem * pi/2)^2 + 0.001
    Dv <- wghts * sqrt(diag(L %*% t(L)))^-1        
  quartimin(Harman8, normalize = NormalizingWeightCM(Harman8), randomStarts=100)
  quartimin(Harman8, normalize = TRUE, randomStarts=100)

GPArotation documentation built on May 29, 2024, 8:16 a.m.

Related to GPA in GPArotation...