Learn R Programming

GPArotation (version 2024.3-1)

GPA: Rotation Optimization

Description

Gradient projection rotation optimization routine used by various rotation objective.

Usage

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)

Value

A GPArotation object which is a list with elements

loadings

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

Th

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

Table

A matrix recording the iterations of the rotation optimization.

method

A string indicating the rotation objective function.

orthogonal

A logical indicating if the rotation is orthogonal.

convergence

A logical indicating if convergence was obtained.

Phi

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.

Gq

The gradient of the objective function at the rotated loadings.

randStartChar

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

Arguments

A

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

Tmat

initial rotation matrix.

normalize

see details.

eps

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

maxit

maximum number of iterations allowed in the main loop.

method

rotation objective criterian.

methodArgs

a list ofmethodArgs arguments passed to the rotation objective

randomStarts

number of random starts (GPFRSorth and GPFRSoblq)

Author

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

Details

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.

References

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. https://doi.org/10.1037/met0000467

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

Examples

Run this code
  # see rotations for more examples	
	
  data(Harman, package = "GPArotation")
  GPFRSorth(Harman8, method = "quartimax")
  quartimax(Harman8)
  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)
  Abor
  print(Abor)
  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)
  summary(Abor, Structure=FALSE)
  options(digits = origdigits$digits)
  
  # GPArotation output does sort loadings, but use print to obtain if needed
  set.seed(334)
  xusl <- quartimin(Harman8, normalize = TRUE, randomStarts=100)
  # loadings without ordering (default)
  loadings(xusl)
  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        
    Dv
  }
  quartimin(Harman8, normalize = NormalizingWeightCM(Harman8), randomStarts=100)
  quartimin(Harman8, normalize = TRUE, randomStarts=100)
	
  

Run the code above in your browser using DataLab