Last data update: 2014.03.03

R: Choose a Transformation in Exploratory Factor Analysis
RotateR Documentation

Choose a Transformation in Exploratory Factor Analysis

Description

This function is intended for users and finds an optimal rotation of preliminary factor loadings extracted via exploratory factor analysis. Unlike other software, Rotate finds a rotation that is optimal with respect to an intersection of criteria, one of which is a “analytic” criterion and the rest are “constraints”. Similar to make_restrictions, much of the functionality of Rotate is implemented via pop-up menus, which is the strongly recommended way to proceed. Also, the vignette details what all these options mean in substantive terms; execute vignette("FAiR") to read it.

Usage

Rotate(FAobject, criteria = list(), methodArgs = list(), 
       normalize = rep(1, nrow(loadings(FAobject))), seeds = 12345, 
       NelderMead = TRUE, ...)

Arguments

FAobject

An object of FA.EFA-class produced by Factanal.

criteria

An optional list whose elements are functions or character strings naming functions to be used in the lexical optimization process. If unspecified, Rotate will prompt you with pop-up menus, which is the recommended way to proceed. See the Details section otherwise.

methodArgs

an option list with named elements for additional arguments needed by some criterion functions; see the Details section

normalize

a vector with the same length as the number of manifest variables, or a function that takes the preliminary primary pattern matrix as its first argument and produces such a vector, or a character string that is either "kaiser" or "cureton-mulaik", which are discussed more in the Details section. The rows of the preliminary primary pattern matrix are divided by this vector before the optimal transformation is found. Note that row-normalization may not be sensible, especially if the objective function optimizes the reference structure matrix or the factor contribution matrix.

seeds

A vector of length one or two to be used as the random number generator seeds corresponding to the unif.seed and int.seed arguments to genoud respectively. If seeds is a single number, this seed is used for both unif.seed and int.seed. These seeds override the defaults for genoud and make it easier to replicate an analysis exactly. However, if seeds = NULL, then the default seeds are used, which is absolutely necessary during simulations.

NelderMead

Logical indicating whether to call optim with method = "Nelder-Mead" when the genetic algorithm has finished to further polish the solution.

...

Further arguments that are passed to genoud. Note that several of the default arguments to genoud are silently overridden by Factanal out of logical necissitity:

argument value why?
nvars FAobject@restrictions@factors[1]^2
max FALSE minimizing the objective
hessian FALSE not meaningful
lexical TRUE resticted optimization
Domains NULL
default.domains 1 parameters are cosines
data.type.int FALSE parameters are doubles
fn wrapper around an internal function
BFGSfn wrapper around an internal function
gn NULL analytic gradients are unknown
BFGShelp wrapper around an internal function
unif.seed taken from seeds replicability
int.seed taken from seeds replicability

The following arguments to genoud default to values that differ from those documented at genoud but can be overridden by specifying them explicitly in the ... :

argument value why?
boundary.enforcement 1 usually 2 can cause problems
MemoryMatrix FALSE runs faster
print.level 1 output is not that helpful for >= 2
P9mix 1 to always accept the BFGS result
BFGSburnin 5 to have a little burnin
max.generations 1000 big number is often necessary
project.path contains "Rotate.txt"

The arguments to genoud that remain at their defaults but you may want to consider tweaking are pop.size, wait.generations, and solution.tolerance.

Details

This help page should really only be used as a reminder for what the various choices are, which are normally indicated by leaving criteria and methodArgs unspecified and responding to pop-up menus. The vignette provides a step-by-step guide to the pop-up menus and formally defines the criteria; execute vignette("FAiR") to read it.

The basic problem is to choose a transformation of the factors that is optimal with respect to some intersection of criteria. Since the objective function is vector valued, lexical optimization is performed via a genetic algorithm, which is tantamount to constrained optimization; see genoud.

The following functions can be named as constraints but must not be the last element of criteria:

name methodArgs reminder of what function does
"no_factor_collapse" nfc_threshold to prevent factor collapse
"limit_correlations" lower and upper limits factor intercorrelations
"positive_manifold" pm_threshold forces “positive” manifold
"ranks_rows_1st" row_ranks row-wise ordering constraints
"ranks_cols_1st" col_ranks column-wise ordering constraints
"indicators_1st" indicators designate which is the best indicator of a factor
"evRF_1st" none restrict effective variance of reference factors
"evPF_1st" none restrict effective variance of primary factors
"h2_over_FC_1st" none communalities >= factor contributions
"no_neg_suppressors_1st" FC_threshold no negative suppressors
"gv_1st" none generalized variance of primary <= reference factors
"distinguishability_1st" none best indicators have no negative suppressors

In fact, "no_factor_collapse" is always included and is listed above only to emphasize that one must specify methodArgs$nfc_threshold to avoid seeing the associated pop-up menu. This restriction to avoid factor collapse makes it possible to utilize one of the following “analytic” criteria that would otherwise result in factor collapse much of the time. One of the following can be named as the last element of criteria:

name methodArgs
"phi" c
"varphi" weights
"LS" eps, scale, and E
"minimaximin"
"geomin" delta
"quartimin"
"target" Target
"pst" Target
"oblimax"
"simplimax" k
"bentler"
"cf" kappa
"infomax"
"mccammon"
"oblimin" gam

The first four are defined only on the reference structure matrix. The remainder are copied from the GPArotation package and have the same arguments, with the exception of "pst" which uses NA in the target matrix for untargeted cells rather than also specifying a weight matrix (which is called W in the GPArotation package). In addition, one can specify methodArgs$matrix as one of "PP", "RS", or "FC" to use the primary pattern, reference structure, or factor contribution matrix in conjunction with the criteria from the GPArotation package, although these criteria are technically defined with respect to the primary pattern matrix.

Row-standardization should not be necessary. Row-standardization was originally intended to counteract some tendencies in the transformation process that can now be accomplished directly through lexical (i.e. constrained) optimization. Nevertheless, Kaiser normalization divides each row of the preliminary primary pattern matrix by its length and Cureton-Mulaik normalization favors rows that are thought to have only one large loading after transformation. Both schemes are thoroughly discussed in Browne (2001), which also discusses most of the continuous analytic criteria available in FAiR with the exceptions of those in Thurstone (1935) and Lorenzo-Seva (2003).

It is not necessary to provide starting values for the parameters. But a matrix of starting values can be passed to through the dots to genoud. This matrix should have rows equal to the pop.size argument in genoud and columns equal the number of factors squared. The columns correspond to the cells of the transformation matrix in column-major order. In contrast to some texts, the transformation matrix in Rotate has unit-length columns, rather than unit-length rows.

Value

An object of FA.EFA-class.

Note

The underlying genetic algorithm will print a variety of output as it progresses. On Windows, you have to move the scrollbar periodically to flush the output to the screen. The output will look something like this

Generation First Second ... Last Analytic
number constraint constraint constraint criterion
0 -1.0 -1.0 ... -1.0 double
1 -1.0 -1.0 ... -1.0 double
... ... ... ... ... ...
42 -1.0 -1.0 ... -1.0 double

The integer on the very left indicates the generation number. If it appears to skip one or more generations, that signifies that the best individual in the “missing” generation was no better than the best individual in the previous generation. The sequence of negative ones indicates that various constraints specified by the user are being satisfied by the best individual in the generation. The curious are referred to the source code and / or the, vignette, but for the most part users need not worry about them provided they are -1.0. If any but the last are not -1.0 after the first few generations, there is a problem because no individual is satisfying all the constraints. The last number is a double-precision number and is typically the (logarithm of the) analytic criterion specified by the user. This number will, decrease, sometimes painfully slowly, sometimes intermittently, over the generations since the criterion is being minimized subject to the aforementioned constraints. Finally, do not be particularly concerned if there are messages indicating a gradient check has failed because there is no strong reason to expect the gradient of the (last) criterion with respect to all the cells of the transformation matrix will be particularly small

Author(s)

Ben Goodrich

References

Browne, M.W. (2001) An overview of analytic rotation in exploratory factor analysis. Multivariate Behavioral Research, 36, 111–150.

Lorenzo-Seva, U. (2003) A factor simplicity index. Psychometrika, 68, 49–60.

Smith, G. A. and Stanley G. (1983) Clocking g: relating intelligence and measures of timed performance. Intelligence, 7, 353–368.

Thurstone, L. L. (1935) The Vectors of Mind. Cambridge University Press.

Venables, W. N. and Ripley, B. D. (2002) Modern Applied Statistics with S. Fourth edition. Springer.

See Also

Factanal

Examples

## Example from Venables and Ripley (2002, p. 323)
## Previously from Bartholomew and Knott  (1999, p. 68--72)
## Originally from Smith and Stanley (1983)
## Replicated from example(ability.cov)

man <- make_manifest(covmat = ability.cov)
res <- make_restrictions(man, factors = 2, model = "EFA")
efa <- Factanal(manifest = man, restrictions = res, impatient = TRUE)

show(efa); summary(efa)

# 'criteria' and 'methodArgs' would typically be left unspecified 
#  and equivalent choices would be made from the pop-up menus
efa.rotated <- Rotate(efa, criteria = list("phi"),
                      methodArgs = list(nfc_threshold = 0.25, c = 1.0))
summary(efa.rotated)
pairs(efa.rotated)
## See the example for Factanal() for more post-estimation commands

Results


R version 3.3.1 (2016-06-21) -- "Bug in Your Hair"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> library(FAiR)
Loading required package: rgenoud
##  rgenoud (Version 5.7-12.4, Build Date: 2015-07-19)
##  See http://sekhon.berkeley.edu/rgenoud for additional documentation.
##  Please cite software as:
##   Walter Mebane, Jr. and Jasjeet S. Sekhon. 2011.
##   ``Genetic Optimization Using Derivatives: The rgenoud package for R.''
##   Journal of Statistical Software, 42(11): 1-26. 
##

Loading required package: gWidgetsRGtk2
Loading required package: RGtk2
Loading required package: gWidgets
Loading required package: cairoDevice
Loading required package: stats4
Loading required package: rrcov
Loading required package: robustbase
Scalable Robust Estimators with High Breakdown Point (version 1.3-11)

Loading required package: Matrix
##  FAiR Version 0.4-15 Build Date: 2014-02-08
## See http://wiki.r-project.org/rwiki/doku.php?id=packages:cran:fair for more info
FAiR  Copyright (C) 2008 -- 2012  Benjamin King Goodrich
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions, namely those specified in the LICENSE file
in the root directory of the source code.
> png(filename="/home/ddbj/snapshot/RGM3/R_CC/result/FAiR/04Rotate.Rd_%03d_medium.png", width=480, height=480)
> ### Name: Rotate
> ### Title: Choose a Transformation in Exploratory Factor Analysis
> ### Aliases: Rotate
> ### Keywords: multivariate models
> 
> ### ** Examples
> 
> ## Example from Venables and Ripley (2002, p. 323)
> ## Previously from Bartholomew and Knott  (1999, p. 68--72)
> ## Originally from Smith and Stanley (1983)
> ## Replicated from example(ability.cov)
> 
> man <- make_manifest(covmat = ability.cov)
Warning message:
In FAiR_make_manifest_list(covmat, shrink) :
  it is strongly preferable to pass the raw data to make_manifest()
> res <- make_restrictions(man, factors = 2, model = "EFA")
> efa <- Factanal(manifest = man, restrictions = res, impatient = TRUE)
> 
> show(efa); summary(efa)

Call:
Factanal(manifest = man, restrictions = res, impatient = TRUE)

Number of observations:  112 

Discrepancy:  6.344784 

Exploratory factor anaylsis
2 factors
4 degrees of freedom


Call:
Factanal(manifest = man, restrictions = res, impatient = TRUE)
        uniqueness
general      0.455
picture      0.589
blocks       0.218
maze         0.769
reading      0.052
vocab        0.334
> 
> # 'criteria' and 'methodArgs' would typically be left unspecified 
> #  and equivalent choices would be made from the pop-up menus
> efa.rotated <- Rotate(efa, criteria = list("phi"),
+                       methodArgs = list(nfc_threshold = 0.25, c = 1.0))


Mon Jul  4 17:53:21 2016
Domains:
 -1.000000e+00   <=  X1   <=    1.000000e+00 
 -1.000000e+00   <=  X2   <=    1.000000e+00 
 -1.000000e+00   <=  X3   <=    1.000000e+00 
 -1.000000e+00   <=  X4   <=    1.000000e+00 

Data Type: Floating Point
Operators (code number, name, population) 
	(1) Cloning........................... 	122
	(2) Uniform Mutation.................. 	125
	(3) Boundary Mutation................. 	125
	(4) Non-Uniform Mutation.............. 	125
	(5) Polytope Crossover................ 	125
	(6) Simple Crossover.................. 	126
	(7) Whole Non-Uniform Mutation........ 	125
	(8) Heuristic Crossover............... 	126
	(9) Local-Minimum Crossover........... 	0

HARD Maximum Number of Generations: 1000
Maximum Nonchanging Generations: 10
Population size       : 1000
Convergence Tolerance: 1.000000e-03

Using the BFGS Derivative Based Optimizer on the Best Individual Each Generation.
Checking Gradients before Stopping.
Not Using Out of Bounds Individuals But Allowing Trespassing.

Minimization Problem.


Generation#	    Solution Values (lexical)

      0 	-1.000000e+00  -1.000000e+00  -1.000000e+00  -2.830552e+00  

      1 	-1.000000e+00  -1.000000e+00  -1.000000e+00  -3.823367e+00  

      2 	-1.000000e+00  -1.000000e+00  -1.000000e+00  -3.828375e+00  

'wait.generations' limit reached.
No significant improvement in 10 generations.

Solution Lexical Fitness Value:
-1.000000e+00  -1.000000e+00  -1.000000e+00  -3.828876e+00  

Parameters at the Solution (parameter, gradient):

 X[ 1] :	9.003194e-01	G[ 1] :	7.944467e-07
 X[ 2] :	8.337576e-01	G[ 2] :	1.429784e-06
 X[ 3] :	-3.545071e-01	G[ 3] :	0.000000e+00
 X[ 4] :	3.513948e-01	G[ 4] :	0.000000e+00

Solution Found Generation 2
Number of Generations Run 13

Mon Jul  4 17:53:23 2016
Total run time : 0 hours 0 minutes and 2 seconds
Nelder-Mead resulted in no improvement;  convergence presumably achieved
> summary(efa.rotated)

Call:
Factanal(manifest = man, restrictions = res, impatient = TRUE)

Point estimates (blanks, if any, are exact zeros):
        F1     F2            Uniqueness
general  0.474  0.374         0.455    
picture  0.658 -0.035         0.589    
blocks   0.913 -0.060         0.218    
maze     0.498 -0.036         0.769    
reading -0.062  1.003         0.052    
vocab    0.034  0.798         0.334    
                                       
F1       1.000  0.510                  
F2       0.510  1.000                  
> pairs(efa.rotated)
> ## See the example for Factanal() for more post-estimation commands
> 
> 
> 
> 
> 
> dev.off()
null device 
          1 
>