A dirty little secret of factor rotation algorithms is the problem of local minima (Nguyen and Waller,2022). Following ideas in that article, we allow for multiple random restarts and then return the global optimal solution. Used as part of the fa function or available as a stand alone function.

faRotations(loadings, r = NULL, rotate = "oblimin", hyper = 0.15, n.rotations = 10,...)

Arguments

loadings

Factor loadings matrix from fa or pca or any N x k loadings matrix

r

The correlation matrix used to find the factors. (Used to find the factor indeterminancy of the solution)

rotate

"none", "varimax", "quartimax", "bentlerT", "equamax", "varimin", "geominT" and "bifactor" are orthogonal rotations. "Promax", "promax", "oblimin", "simplimax", "bentlerQ, "geominQ" and "biquartimin" and "cluster" are possible oblique transformations of the solution. Defaults to oblimin.

hyper

The value defining when a loading is in the “hyperplane".

n.rotations

The number of random restarts to use.

...

additional parameters, specifically, keys may be passed if using the target rotation, or delta if using geominQ, or whether to normalize if using Varimax

Details

Nguyen and Waller review the problem of local minima in factor analysis. This is a problem for all rotation algorithms, but is more so for some. faRotate generates n.rotations different starting values and then applies the specified rotation to the original loadings using multiple start values. Hyperplane counts and complexity indices are reported for each starting matrix, and the one with the highest hyoerplane count and the lowest complexity is returned.

Value

loadings

The best rotated solution

Phi

Factor correlations

rotation.stats

Hyperplane count, complexity.

rot.mat

The rotation matrix used.

References

Nguyen, H. V., & Waller, N. G. (2022, January 6). Local Minima and Factor Rotations in Exploratory Factor Analysis. Psychological Methods. Advance online publication. doi 10.1037/met0000467

Author

William Revelle

Note

Adapted from the fungible package by Waller

See also

Examples

f5 <- fa(bfi[,1:25],5,rotate="none")
faRotations(f5,n.rotations=10)   #note that the factor analysis needs to not do the rotation
#> Factor Analysis using method = 
#> Call: faRotations(loadings = f5, n.rotations = 10)
#> Standardized loadings (pattern matrix) based upon correlation matrix
#>      MR1   MR2   MR3   MR4   MR5   h2   u2
#> A1 -0.07 -0.21  0.17 -0.06 -0.41 0.19 0.81
#> A2 -0.08  0.02  0.00  0.03  0.64 0.45 0.55
#> A3 -0.02  0.03  0.12  0.03  0.66 0.52 0.48
#> A4 -0.19  0.06  0.06 -0.15  0.43 0.28 0.72
#> A5 -0.01  0.11  0.23  0.04  0.53 0.46 0.54
#> C1 -0.55 -0.07 -0.03  0.15 -0.02 0.33 0.67
#> C2 -0.67 -0.15 -0.09  0.04  0.08 0.45 0.55
#> C3 -0.57 -0.03 -0.06 -0.07  0.09 0.32 0.68
#> C4  0.61 -0.17  0.00 -0.05  0.04 0.45 0.55
#> C5  0.55 -0.19 -0.14  0.09  0.02 0.43 0.57
#> E1 -0.11  0.06 -0.56 -0.10 -0.08 0.35 0.65
#> E2  0.02 -0.10 -0.68 -0.06 -0.05 0.54 0.46
#> E3  0.00 -0.08  0.42  0.28  0.25 0.44 0.56
#> E4 -0.02 -0.01  0.59 -0.08  0.29 0.53 0.47
#> E5 -0.27 -0.15  0.42  0.21  0.05 0.40 0.60
#> N1  0.00 -0.81  0.10 -0.05 -0.11 0.65 0.35
#> N2 -0.01 -0.78  0.04  0.01 -0.09 0.60 0.40
#> N3  0.04 -0.71 -0.10  0.02  0.08 0.55 0.45
#> N4  0.14 -0.47 -0.39  0.08  0.09 0.49 0.51
#> N5  0.00 -0.49 -0.20 -0.15  0.21 0.35 0.65
#> O1 -0.07 -0.02  0.10  0.51  0.02 0.31 0.69
#> O2  0.08 -0.19  0.06 -0.46  0.16 0.26 0.74
#> O3 -0.02 -0.03  0.15  0.61  0.08 0.46 0.54
#> O4  0.02 -0.13 -0.32  0.37  0.17 0.25 0.75
#> O5  0.03 -0.13  0.10 -0.54  0.04 0.30 0.70
#> 
#>                        MR1  MR2  MR3  MR4  MR5
#> SS loadings           2.03 2.57 2.20 1.59 1.99
#> Proportion Var        0.08 0.10 0.09 0.06 0.08
#> Cumulative Var        0.08 0.18 0.27 0.34 0.41
#> Proportion Explained  0.20 0.25 0.21 0.15 0.19
#> Cumulative Proportion 0.20 0.44 0.66 0.81 1.00
#> 
#>  With factor correlations of 
#>       MR1   MR2   MR3   MR4   MR5
#> MR1  1.00 -0.19 -0.23 -0.19 -0.20
#> MR2 -0.19  1.00  0.21  0.01  0.04
#> MR3 -0.23  0.21  1.00  0.17  0.33
#> MR4 -0.19  0.01  0.17  1.00  0.19
#> MR5 -0.20  0.04  0.33  0.19  1.00
faRotations(f5$loadings)  #matrix input
#> 
#> Call: faRotations(loadings = f5$loadings)
#> Standardized loadings (pattern matrix) based upon correlation matrix
#>      MR1   MR2   MR3   MR4   MR5   h2   u2
#> A1  0.21 -0.17  0.41 -0.06 -0.07 0.19 0.81
#> A2 -0.02  0.00 -0.64  0.03 -0.08 0.45 0.55
#> A3 -0.03 -0.12 -0.66  0.03 -0.02 0.52 0.48
#> A4 -0.06 -0.06 -0.43 -0.15 -0.19 0.28 0.72
#> A5 -0.11 -0.23 -0.53  0.04 -0.01 0.46 0.54
#> C1  0.07  0.03  0.02  0.15 -0.55 0.33 0.67
#> C2  0.15  0.09 -0.08  0.04 -0.67 0.45 0.55
#> C3  0.03  0.06 -0.09 -0.07 -0.57 0.32 0.68
#> C4  0.17  0.00 -0.04 -0.05  0.61 0.45 0.55
#> C5  0.19  0.14 -0.02  0.09  0.55 0.43 0.57
#> E1 -0.06  0.56  0.08 -0.10 -0.11 0.35 0.65
#> E2  0.10  0.68  0.05 -0.06  0.02 0.54 0.46
#> E3  0.08 -0.42 -0.25  0.28  0.00 0.44 0.56
#> E4  0.01 -0.59 -0.29 -0.08 -0.02 0.53 0.47
#> E5  0.15 -0.42 -0.05  0.21 -0.27 0.40 0.60
#> N1  0.81 -0.10  0.11 -0.05  0.00 0.65 0.35
#> N2  0.78 -0.04  0.09  0.01 -0.01 0.60 0.40
#> N3  0.71  0.10 -0.08  0.02  0.04 0.55 0.45
#> N4  0.47  0.39 -0.09  0.08  0.14 0.49 0.51
#> N5  0.49  0.20 -0.21 -0.15  0.00 0.35 0.65
#> O1  0.02 -0.10 -0.02  0.51 -0.07 0.31 0.69
#> O2  0.19 -0.06 -0.16 -0.46  0.08 0.26 0.74
#> O3  0.03 -0.15 -0.08  0.61 -0.02 0.46 0.54
#> O4  0.13  0.32 -0.17  0.37  0.02 0.25 0.75
#> O5  0.13 -0.10 -0.04 -0.54  0.03 0.30 0.70
#> 
#>                        MR1  MR2  MR3  MR4  MR5
#> SS loadings           2.57 2.20 1.99 1.59 2.03
#> Proportion Var        0.10 0.09 0.08 0.06 0.08
#> Cumulative Var        0.10 0.19 0.27 0.33 0.41
#> Proportion Explained  0.25 0.21 0.19 0.15 0.20
#> Cumulative Proportion 0.25 0.46 0.65 0.80 1.00
#>       MR1   MR2   MR3   MR4   MR5
#> MR1  1.00  0.21  0.04 -0.01  0.19
#> MR2  0.21  1.00  0.33 -0.17  0.23
#> MR3  0.04  0.33  1.00 -0.19  0.20
#> MR4 -0.01 -0.17 -0.19  1.00 -0.19
#> MR5  0.19  0.23  0.20 -0.19  1.00
geo <- faRotations(f5,rotate="geominQ",n.rotation=10)
 # a popular alternative, but more sensitive to local minima
describe(geo$rotation.stats[,1:3]) 
#>            vars  n mean sd median trimmed mad  min  max range skew kurtosis se
#> hyperplane    1 10 0.61  0   0.61    0.61   0 0.61 0.61     0  NaN      NaN  0
#> fit           2 10 0.10  0   0.10    0.10   0 0.10 0.10     0    0    -2.16  0
#> complexity    3 10 1.45  0   1.45    1.45   0 1.45 1.45     0    0    -2.18  0