This function performs factor analysis using the Principal Axis Factoring (PAF) method. The process involves extracting factors from an initial correlation matrix and iteratively refining the factor estimates until convergence is achieved.

factor.analysis(
  data,
  nfact = 1,
  iter.max = 1000,
  criterion = 0.001,
  cor.type = "pearson",
  use = "pairwise.complete.obs"
)

Arguments

data

A data.frame or matrix of response If the matrix is square, it is assumed to be a correlation matrix. Otherwise, correlations (with pairwise deletion) will be computed.

nfact

The number of factors to extract. (default = 1)

iter.max

The maximum number of iterations for the factor extraction process. Default is 1000.

criterion

The convergence criterion for the iterative process. The extraction process will stop when the change in communalities is less than this value. Default is 0.001

cor.type

A character string indicating which correlation coefficient (or covariance) is to be computed. One of "pearson" (default), "kendall", or "spearman". @seealso cor.

use

An optional character string giving a method for computing covariances in the presence of missing values. This must be one of the strings "everything", "all.obs", "complete.obs", "na.or.complete", or "pairwise.complete.obs" (default). @seealso cor.

Value

A list containing:

loadings

The extracted factor loadings.

eigen.value

The eigenvalues of the correlation matrix.

H2

A vector that contains the explanatory power of the factor model for all items.

Details

The Principal Axis Factoring (PAF) method involves the following steps:

Step 1. **Basic Principle**: The core principle of factor analysis using Principal Axis Factoring (PAF) is expressed as: $$\mathbf{R} = \mathbf{\Lambda} \mathbf{\Lambda}^T + \mathbf{\Phi}$$ $$R_{ii} = H_i^2 + \Phi_{ii}$$ where \(\mathbf{\Lambda}\) is the matrix of factor loadings, and \(\mathbf{\Phi}\) is the diagonal matrix of unique variances. Here, \(H_i^2\) represents the portion of the i-th item's variance explained by the factor model. \(\mathbf{H}^2\) reflects the amount of total variance in the variable accounted for by the factors in the model, indicating the explanatory power of the factor model for that variable.

Step 2. **Factor Extraction by Iteratoin**:

- Initial Communalities: Compute the initial communalities as the squared multiple correlations: $$H_{i(t)}^2 = R_{ii(t)}$$ where \(H_{i(t)}^2\) is the communality of i-th item in the \(t\)-th iteration, and \(R_{ii(t)}\) is the i-th diagonal element of the correlation matrix in the \(t\)-th iteration.

- Extract Factors and Update Communalities: $$\Lambda_{ij} = \sqrt{\lambda_j} \times v_{ij}$$ $$H_{i(t+1)}^2 = \sum_j \Lambda_{ij}^2$$ $$R_{ii(t+1)} = H_{i(t+1)}^2$$ where \(\Lambda_{ij}\) represents the j-th factor loading for the i-th item, \(\lambda_j\) is the j-th eigenvalue, \(H_{i(t+1)}^2\) is the communality of i-th item in the \(t+1\)-th iteration, and \(v_{ij}\) is the j-th value of the i-th item in the eigen vector matrix \(\mathbf{v}\).

Step 3. **Iterative Refinement**:

- Calculate the Change between \(\mathbf{H}_{t}^2\) and \(\mathbf{H}_{t+1}^2\): $$\Delta H_i^2 = \lvert H_{i(t+1)}^2 - H_{i(t)}^2 \lvert$$ where \(\Delta H_i^2\) represents the change in communalities between iterations \(t\) and \(t+1\).

- Convergence Criterion: Continue iterating until the change in communalities is less than the specified criterion \(criterion\): $$\sum_i \Delta H_i^2 < criterion$$

The iterative process is implemented using C++ code to ensure computational speed.

Author

Haijiang Qin <Haijiang133@outlook.com>

Examples

library(EFAfactors)
set.seed(123)

##Take the data.bfi dataset as an example.
data(data.bfi)

response <- as.matrix(data.bfi[, 1:25]) ## loading data
response <- na.omit(response) ## Remove samples with NA/missing values

## Transform the scores of reverse-scored items to normal scoring
response[, c(1, 9, 10, 11, 12, 22, 25)] <- 6 - response[, c(1, 9, 10, 11, 12, 22, 25)] + 1


## Run factor.analysis function to extract 5 factors
# \donttest{
 PAF.obj <- factor.analysis(response, nfact = 5)


 ## Get the loadings, eigen.value and  H2 results.
 loadings <- PAF.obj$loadings
 eigen.value <- PAF.obj$eigen.value
 H2 <- PAF.obj$H2

 print(loadings)
#>              [,1]        [,2]        [,3]         [,4]         [,5]
#>  [1,]  0.22357173 -0.01953098  0.12660494 -0.001265153 -0.370873691
#>  [2,]  0.46670455 -0.28513259  0.17712939  0.129901063 -0.339853614
#>  [3,]  0.53396215 -0.30226843  0.25197180  0.111318131 -0.295441862
#>  [4,]  0.41741256 -0.11465787  0.12131972  0.269694510 -0.164523244
#>  [5,]  0.58068938 -0.18034639  0.26095073  0.044077725 -0.173909681
#>  [6,]  0.34316129 -0.13371810 -0.44626482  0.115457357  0.016601203
#>  [7,]  0.33602083 -0.19601674 -0.47722592  0.272536517 -0.023500731
#>  [8,]  0.31905932 -0.05461358 -0.35081689  0.309472702 -0.025715892
#>  [9,]  0.46544931  0.10484469 -0.45151459  0.210649185  0.028331007
#> [10,]  0.49263043  0.14999457 -0.28646250  0.275713391  0.110051703
#> [11,]  0.40807654 -0.17976152  0.26455941 -0.105054643  0.260638306
#> [12,]  0.61896104 -0.04383756  0.23054819 -0.056547517  0.322635148
#> [13,]  0.52739248 -0.32756004  0.11897565 -0.182384735  0.090580876
#> [14,]  0.59945583 -0.17290005  0.32858864  0.096178830  0.186583584
#> [15,]  0.51256108 -0.28690834 -0.09198988 -0.036812998  0.228677441
#> [16,] -0.44131379 -0.63607244 -0.02870967  0.100585215  0.266413125
#> [17,] -0.42276549 -0.61546676 -0.08221250  0.053073284  0.202240973
#> [18,] -0.40682567 -0.61080198 -0.03266493  0.067641478  0.016869525
#> [19,] -0.52771413 -0.41603609 -0.07610637 -0.040330943 -0.216378937
#> [20,] -0.34500799 -0.41288319  0.02839561  0.210625416 -0.121041679
#> [21,]  0.32758475 -0.20464733 -0.19673050 -0.359741437 -0.005177435
#> [22,]  0.19684736  0.06338051 -0.29479171 -0.369533612 -0.035190515
#> [23,]  0.40725856 -0.29552702 -0.14873003 -0.446230021 -0.013242230
#> [24,] -0.06444126 -0.25784289 -0.17877525 -0.232861770 -0.298673802
#> [25,]  0.20253806 -0.05545507 -0.26546622 -0.412000682 -0.109533526
 print(eigen.value)
#>               [,1]
#>  [1,]  4.599593867
#>  [2,]  2.268055523
#>  [3,]  1.548741899
#>  [4,]  1.218378873
#>  [5,]  0.955663870
#>  [6,]  0.459063349
#>  [7,]  0.238115633
#>  [8,]  0.190822770
#>  [9,]  0.100099853
#> [10,]  0.087434960
#> [11,]  0.064278564
#> [12,]  0.031680064
#> [13,] -0.004029095
#> [14,] -0.021917005
#> [15,] -0.048273722
#> [16,] -0.054108498
#> [17,] -0.060527873
#> [18,] -0.077308854
#> [19,] -0.087403216
#> [20,] -0.104476847
#> [21,] -0.118912871
#> [22,] -0.123562137
#> [23,] -0.140451747
#> [24,] -0.153335732
#> [25,] -0.177225065
 print(H2)
#>            [,1]
#>  [1,] 0.2039435
#>  [2,] 0.4628633
#>  [3,] 0.5396492
#>  [4,] 0.3019012
#>  [5,] 0.4700077
#>  [6,] 0.3483985
#>  [7,] 0.4539056
#>  [8,] 0.3242886
#>  [9,] 0.4766766
#> [10,] 0.4353731
#> [11,] 0.3478012
#> [12,] 0.5454780
#> [13,] 0.4410627
#> [14,] 0.5412760
#> [15,] 0.4071460
#> [16,] 0.6812636
#> [17,] 0.6080071
#> [18,] 0.5445131
#> [19,] 0.5058068
#> [20,] 0.3493235
#> [21,] 0.3173359
#> [22,] 0.2674616
#> [23,] 0.4746130
#> [24,] 0.2460269
#> [25,] 0.2963114

# }