rotations: Rotations Functions Using Gradient Projection Algorithms

rotationsR Documentation

Rotations Functions Using Gradient Projection Algorithms

Description

Optimize factor loading rotation objective.

Usage

    oblimin(A, Tmat=diag(ncol(A)), gam=0, normalize=FALSE, randomStarts=0, ...)
    quartimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    targetT(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    targetQ(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    pstT(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    pstQ(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, 
        maxit=1000, randomStarts=0, L=NULL, ...)
    oblimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    entropy(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    quartimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    Varimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    simplimax(A, Tmat=diag(ncol(A)), k=nrow(A), normalize=FALSE, randomStarts=0, ...)
    bentlerT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bentlerQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    tandemI(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    tandemII(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    geominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    geominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    bigeominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    bigeominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...)
    cfT(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...)
    cfQ(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...)
    equamax(A, Tmat=diag(ncol(A)), kappa=ncol(A)/(2*nrow(A)), normalize=FALSE,
        randomStarts=0, ...)
    parsimax(A, Tmat=diag(ncol(A)), kappa=(ncol(A)-1)/(ncol(A)+nrow(A)-2), 
        normalize=FALSE, randomStarts=0, ...)
    infomaxT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    infomaxQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    mccammon(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    varimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bifactorT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    bifactorQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...)
    lpT(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, 
            randomStarts=0, gpaiter=5) 
    lpQ(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, 
        randomStarts=0, gpaiter=5)
    

Arguments

A

an initial loadings matrix to be rotated.

Tmat

initial rotation matrix.

gam

Obliqueness parameter (\gamma in the mathematical definition). 0=Quartimin, .5=Biquartimin, 1=Covarimin.

Target

rotation target for objective calculation.

W

weighting of each element in target.

k

number of close to zero loadings.

delta

constant added to \Lambda^2 in the objective calculation.

kappa

see details.

normalize

parameter passed to optimization routine (GPForth or GPFoblq).

eps

convergence tolerance passed to GPForth or GPFoblq via .... Convergence is assumed when the norm of the gradient is smaller than eps. Default is 1e-5.

maxit

maximum number of iterations passed to GPForth or GPFoblq via .... Default is 1000.

...

additional arguments passed to GPForth or GPFoblq, including eps and maxit.

randomStarts

parameter passed to optimization routine (GPFRSorth or GPFRSoblq).

L

provided for backward compatibility in target rotations only. Use A going forward.

p

Component-wise L^p, where 0 < p =< 1.

gpaiter

Maximum iterations for GPA rotation loop in L^p rotation.

Details

These functions optimize a rotation objective. They can be used directly or the function name can be passed to factor analysis functions like factanal. Several of the function names end in T or Q, which indicates if they are orthogonal or oblique rotations (using GPFRSorth or GPFRSoblq respectively). The gradient projection algorithms are described in Bernaards and Jennrich (2005).

oblimin oblique oblimin family; gam controls obliqueness
quartimin oblique oblimin with gam = 0
targetT orthogonal rotation towards a target matrix
targetQ oblique rotation towards a target matrix
pstT orthogonal partially specified target rotation
pstQ oblique partially specified target rotation
oblimax oblique maximizes overall kurtosis of loadings
entropy orthogonal minimizes entropy of squared loadings
quartimax orthogonal maximizes variance of squared loadings within variables
Varimax orthogonal maximizes variance of squared loadings within factors
simplimax oblique minimizes the k smallest squared loadings
bentlerT orthogonal invariant pattern simplicity
bentlerQ oblique invariant pattern simplicity
tandemI orthogonal factors share high loadings on same variables
tandemII orthogonal factors do not share high loadings on same variables
geominT orthogonal minimizes geometric mean of squared loadings
geominQ oblique minimizes geometric mean of squared loadings
bigeominT orthogonal geomin with a general factor in column 1
bigeominQ oblique geomin with a general factor in column 1
cfT orthogonal Crawford-Ferguson family; kappa controls complexity
cfQ oblique Crawford-Ferguson family; kappa controls complexity
equamax orthogonal Crawford-Ferguson with kappa = m/(2p)
parsimax orthogonal Crawford-Ferguson with kappa = (m-1)/(p+m-2)
infomaxT orthogonal infomax information criterion
infomaxQ oblique infomax information criterion
mccammon orthogonal minimizes entropy ratio across factors
varimin orthogonal minimizes variance of squared loadings within factors
bifactorT orthogonal bifactor; general factor in column 1
bifactorQ oblique biquartimin; general factor in column 1
lpT orthogonal L^p sparsity rotation
lpQ oblique L^p sparsity rotation

The Varimax implementation in the list uses the gradient projection algorithm applied to vgQ.varimax. This implementation is different that the varimax rotation defined in the stats package. Additionally, varimax does Kaiser normalization by default whereas GPArotation::Varimax does not.

The argument kappa parameterizes the family for the Crawford-Ferguson method. If m is the number of factors and p is the number of indicators then kappa values having special names are 0=Quartimax, 1/p=Varimax, m/(2*p)=Equamax, (m-1)/(p+m-2)=Parsimax, 1=Factor parsimony.

Bifactor rotations, bifactorT and bifactorQ are called bifactor and biquartimin in Jennrich and Bentler (2011). For a comparison of exploratory bifactor analysis algorithms including those implemented here, see Garcia-Garzon, Abad and Garrido (2021).

The argument p is needed for L^p rotation. See Lp rotation for details on the rotation method.

Value

A GPArotation object which is a list with elements:

loadings

The rotated loadings matrix, one column per factor. If random starts were requested, this is the solution with the lowest criterion value.

Th

The rotation matrix, satisfying loadings %*% t(Th) = A for orthogonal rotation and loadings = A %*% solve(t(Th)) for oblique rotation.

Table

A matrix recording the iteration history: iteration number, criterion value, log10 of the gradient norm, and step size (alpha).

method

A string indicating the rotation criterion.

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. Omitted (NULL) for orthogonal rotations.

Gq

The gradient of the criterion at the rotated loadings.

randStartChar

A named vector summarising random start results: randomStarts, Converged, atMinimum, localMins. Only present when randomStarts > 1.

Author(s)

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

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. doi: 10.1177/0013164404272507

Bi, Y. and Barchard, K.A. (2024). Purchasing choices that reduce climate change: An exploratory factor analysis. Spectra Undergraduate Research Journal, 3(2), 8–14. doi: 10.9741/2766-7227.1028.

Fischer, R., & Fontaine, J. (2010). Methods for investigating structural equivalence. In D. Matsumoto & F. van de Vijver (Eds.), Cross-Cultural Research Methods in Psychology (pp. 179–215). Cambridge University Press. doi: 10.1017/CBO9780511779381.010

Garcia-Garzon, E., Abad, F.J. and Garrido, L.E. (2021). On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. Multivariate Behavioral Research, 56(1), 101–119. doi: 10.1080/00273171.2020.1736977

Jennrich, R.I. and Bentler, P.M. (2011). Exploratory bi-factor analysis. Psychometrika, 76(4), 537–549. doi: 10.1007/s11336-011-9218-4

For references to individual rotation criteria see vignette("GPA1guide", package = "GPArotation").

See Also

factanal, GPFRSorth, GPFRSoblq, vgQ, Harman8, NetherlandsTV, CCAI, box26

Examples

  # For extended examples see the vignettes:
  # vignette("GPA1guide",    package = "GPArotation")
  # vignette("GPA2local",    package = "GPArotation")
  # vignette("GPA3bifactor", package = "GPArotation")

  # --- Accessing rotated loadings ---
  data("Harman", package = "GPArotation") # 8 physical variables
  qHarman <- quartimax(Harman8)
  loadings(qHarman)                              # via extractor (recommended)
  qHarman$loadings                               # via direct list access
  all.equal(loadings(qHarman), qHarman$loadings) # identical

  # --- Rotating factanal loadings ---
  data("WansbeekMeijer", package = "GPArotation") # Netherlands TV viewership
  fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV,
                           normalize = TRUE, rotation = "none")
  quartimax(loadings(fa.unrotated), normalize = TRUE)
  geominQ(loadings(fa.unrotated), normalize = TRUE, randomStarts = 100)

  # --- Passing rotation to factanal ---
  # CCAI:Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory
  data("CCAI", package = "GPArotation") 
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT")
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT",
           control = list(rotate = list(normalize = TRUE, eps = 1e-6)))
           
  # --- Target rotation ---
  # Orthogonal target rotation of two varimax rotated matrices 
  # towards each other. Data from Fischer and Fontaine (2010).
  # See vignette("GPA1guide", package = "GPArotation") for further analyses.
  trBritain <- matrix(c(.783, -.163, .811, .202, .724, .209, .850, .064,
                       -.031, .592, -.028, .723, .388, .434, .141, .808,
                       .215, .709), byrow = TRUE, ncol = 2)

  trGermany <- matrix(c(.778, -.066, .875, .081, .751, .079, .739, .092,
                       .195, .574, -.030, .807, -.135, .717, .125, .738,
                       .060, .691), byrow = TRUE, ncol = 2)
  trx <- targetT(trGermany, Target = trBritain)
  round(trx$loadings - trBritain, 3)  # difference from target

  # --- Partially specified target rotation ---
  # See vignette("GPA1guide", package = "GPArotation") for full context.
  # Unrotated loadings matrix A and partially specified target SPA
  # NA entries in SPA are unspecified --- rotation is free there
  # Numeric entries are the target values the rotation aims towards
  A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322,
                .248, .304, -0.291, -0.314, -0.377, .397, .294, .428,
                -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3)
  SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7),
                  0, 0, NA, 0, rep(NA, 4)), ncol = 3)
  comparison <- cbind(round(A, 3), rep(NA, nrow(A)), SPA)
  colnames(comparison) <- c("A.F1", "A.F2", "A.F3", "|", "T.F1", "T.F2", "T.F3")
  cat("Unrotated loadings (A) and partially specified target (SPA):\n")
  print(comparison, na.print = "NA")
  targetT(A, Target = SPA)

  # --- Random starts ---
  # CCAI Climate-Friendly Purchasing Choices domain, 14 items, 3 oblique factors.
  # High factor intercorrelations make oblimin the natural choice.
  # Note: factanal uses MLE extraction; results differ somewhat from
  # PCA-based extraction used in Bi and Barchard (2024).
  data("CCAI", package = "GPArotation")
  fa.unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none")
  oblimin(loadings(fa.unrotated), Tmat = Random.Start(3))  # single random start
  oblimin(loadings(fa.unrotated), randomStarts = 1)        # equivalent
  oblimin(loadings(fa.unrotated), randomStarts = 100)      # multiple starts

  # Directly via factanal call 
  factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "oblimin",
      control = list(rotate = list(normalize = TRUE, gam = -0.1, randomStarts = 100)))

  # --- Assessing local minima ---
  # For detailed investigation of local minima across all random starts
  # see vignette("GPA2local", package = "GPArotation").
  data(Thurstone, package = "GPArotation")
  infomaxQ(box26, normalize = TRUE, randomStarts = 150)
  geominQ(box26,  normalize = TRUE, randomStarts = 150)

GPArotation documentation built on April 29, 2026, 9:08 a.m.