class: title-slide, middle <div style = "position:fixed; visibility: hidden"> `$$\require{color}\definecolor{red}{rgb}{0.698039215686274, 0.133333333333333, 0.133333333333333}$$` `$$\require{color}\definecolor{green}{rgb}{0.125490196078431, 0.698039215686274, 0.666666666666667}$$` `$$\require{color}\definecolor{blue}{rgb}{0.274509803921569, 0.509803921568627, 0.705882352941177}$$` `$$\require{color}\definecolor{yellow}{rgb}{0.823529411764706, 0.411764705882353, 0.117647058823529}$$` `$$\require{color}\definecolor{purple}{rgb}{0.866666666666667, 0.627450980392157, 0.866666666666667}$$` </div> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ TeX: { Macros: { red: ["{\\color{red}{#1}}", 1], green: ["{\\color{green}{#1}}", 1], blue: ["{\\color{blue}{#1}}", 1], yellow: ["{\\color{yellow}{#1}}", 1], purple: ["{\\color{purple}{#1}}", 1] }, loader: {load: ['[tex]/color']}, tex: {packages: {'[+]': ['color']}} } }); </script> <style> .red {color: #B22222;} .green {color: #20B2AA;} .blue {color: #4682B4;} .yellow {color: #D2691E;} .purple {color: #DDA0DD;} </style> ### Statistical Modeling in Experimental Psychology # W02 Exploratory Factor Analysis (EFA) ## Concepts and the Executive Workflow #### Han Hao @ Tarleton State University --- ## Today’s roadmap - 1) EFA mindset: what it claims and what it doesn't (re-iteration of Week 01) - 2) Manual translation (a simple example with a 3-variables correlation matrix) *** - 3) EFA executive workflow: stages and decisions - 4) Reading psych::fa output **.red[using a simulated dataset]** - 5) Bridge to next week’s in-class demo --- ## EFA as an explanation of correlations We observe a pattern of **correlations (or covariances)** among measured variables EFA proposes an initial **.red[data-driven]** explanation to the patterns - It (**.red[imperfectly]**) estimates a small number of latent variables and their corresponding **factor loading solution** (loading matrix) that approximately reproduces the original cor/cov A EFA factor loading solution provides a initial **measurement structure** of the manifest variables to the latent variables (as a "codebook" to the latent variables) - It also decomposes shared variance and unique variance --- ## The one-factor model (conceptual) For all (standardized) manifest variables in an estimated one-factor model, we have: $$ x_i = \lambda_i f + \varepsilon_i $$ - \\(x_i\\): the *i* th manifest variable; \\(f\\): latent variable (common cause) - \\(\lambda_i\\): factor loading for \\(x_i\\) - \\(\varepsilon_i\\): residuals term for \\(x_i\\) Assumptions for this model (one-factor, standardized): - \\(Var(f)=1\\): The "Standardized" latent factor - \\(Cov(f,\varepsilon_i)=0\\): residual terms should be uncorrelated with the latent factor - \\(Cov(\varepsilon_i, \varepsilon_j)=0\\): residual terms should be uncorrelated across manifest variables --- ## Model-implied correlations Off-diagonal correlations (standardized covariances) can be reproduced: $$ r_{ij} \approx \lambda_i \lambda_j $$ Variance can be decomposed for each standardized manifest variable: $$ 1 = \lambda_i^2 + Var(\varepsilon_i) $$ Definitions: - Communality: \\(h_i^2 = \lambda_i^2\\) (only valid in the one-factor case) - Uniqueness: \\(u_i^2 = Var(\varepsilon_i) = 1 - h_i^2\\) --- ## Extending to multi-factor models A similar equation for the manifest variables **after the model is estimated**: $$ x_i = {\lambda_i}_1 f_1 + {\lambda_i}_2 f_2 + \cdots + \varepsilon_i $$ - \\(x_i\\): the *i* th manifest variable - \\(f_k\\): the *k* th latent factor - \\(\lambda i_k\\): factor loading for \\(x_i\\) on \\(f_k\\) - \\(\varepsilon_i\\): residuals term for \\(x_i\\) --- ## Assumptions in multi-factor models A similar equation for the manifest variables **after the model is estimated**: $$ x_i = {\lambda_i}_1 f_1 + {\lambda_i}_2 f_2 + \cdots + \varepsilon_i $$ - \\(Var(f_k)=1\\): "Standardized" latent factors - \\(Cov(f_k,\varepsilon_i)=0\\): residuals terms are uncorrelated with the latent factors - \\(Cov(\varepsilon_i, \varepsilon_k)=0\\): residuals terms are uncorrelated with each other - Factors can be either uncorrelated \\(Cov(f_k, f_l) = 0\\) or correlated \\(Cov(f_k, f_l) \neq 0\\) - .red[It depends on the prior specification before the model estimation] - If factors are not correlated, \\(h_i^2 = \sum{\lambda_i}_k^2\\) --- ## From variable equations to matrices .pull-left[ **At the data-frame level (.red[Not required])** Multi-factor model for variable \(i\): $$ x_i = {\lambda_i}_1 f_1 + {\lambda_i}_2 f_2 + \cdots + \varepsilon_i $$ Stack all .red[p] observed variables (vectors with a length of .red[N], why?) into a matrix \\(X\\), and all .red[m] latent variables (vectors of the same length) into a matrix \\(F\\): $$ X = F \Lambda^\top + E $$ ] .pull-right[ Where: - \\(X\\) is \\(N \times p\\) (observed variables, the data matrix) - \\(\Lambda^\top\\) is \\(m \times p\\) (transpose of the loadings matrix, why \\(m \times p\\)?) - \\(F\\) is \\(N \times m\\) (latent factor matrix, the estimated factor) - \\(E\\) is \\(N \times p\\) (residuals matrix) ] --- ## A Typical Factor Loading Matrix <table> <caption></caption> <thead> <tr> <th style="text-align:left;"> Vs.Fs </th> <th style="text-align:right;"> F1 </th> <th style="text-align:right;"> F2 </th> <th style="text-align:right;"> F3 </th> <th style="text-align:right;"> h2 </th> <th style="text-align:right;"> u2 </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> V1 </td> <td style="text-align:right;"> 0.15 </td> <td style="text-align:right;"> 0.35 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 0.19 </td> <td style="text-align:right;"> 0.8123 </td> </tr> <tr> <td style="text-align:left;"> V2 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 0.99 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 1.00 </td> <td style="text-align:right;"> 0.0043 </td> </tr> <tr> <td style="text-align:left;"> V3 </td> <td style="text-align:right;"> 0.46 </td> <td style="text-align:right;"> -0.12 </td> <td style="text-align:right;"> 0.09 </td> <td style="text-align:right;"> 0.23 </td> <td style="text-align:right;"> 0.7740 </td> </tr> <tr> <td style="text-align:left;"> V4 </td> <td style="text-align:right;"> 0.45 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.39 </td> <td style="text-align:right;"> 0.6123 </td> </tr> <tr> <td style="text-align:left;"> V5 </td> <td style="text-align:right;"> 0.06 </td> <td style="text-align:right;"> 0.09 </td> <td style="text-align:right;"> 0.56 </td> <td style="text-align:right;"> 0.40 </td> <td style="text-align:right;"> 0.5984 </td> </tr> <tr> <td style="text-align:left;"> V6 </td> <td style="text-align:right;"> -0.01 </td> <td style="text-align:right;"> -0.03 </td> <td style="text-align:right;"> 0.77 </td> <td style="text-align:right;"> 0.57 </td> <td style="text-align:right;"> 0.4322 </td> </tr> <tr> <td style="text-align:left;"> V7 </td> <td style="text-align:right;"> 0.60 </td> <td style="text-align:right;"> -0.01 </td> <td style="text-align:right;"> 0.04 </td> <td style="text-align:right;"> 0.38 </td> <td style="text-align:right;"> 0.6203 </td> </tr> <tr> <td style="text-align:left;"> V8 </td> <td style="text-align:right;"> 0.74 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> -0.08 </td> <td style="text-align:right;"> 0.49 </td> <td style="text-align:right;"> 0.5125 </td> </tr> <tr> <td style="text-align:left;"> V9 </td> <td style="text-align:right;"> 0.46 </td> <td style="text-align:right;"> 0.08 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.35 </td> <td style="text-align:right;"> 0.6506 </td> </tr> </tbody> </table> --- ## EFA as a "codebook" to the latents .pull-left[ A EFA factor loading solution provides a initial **measurement structure** of the manifest variables to the latent variables (as a "codebook" to the lantent variables) $$ V_1 \approx 0.15F_1 + 0.35F_2 + 0.00F_3 $$ $$ V_2 \approx 0.00F_1 + 0.99F_2 + 0.00F_3 $$ $$ V_3 \approx 0.46F_1 - 0.12F_2 + 0.09F_3 $$ ] .pull-right[ <table> <caption></caption> <thead> <tr> <th style="text-align:left;"> Vs.Fs </th> <th style="text-align:right;"> F1 </th> <th style="text-align:right;"> F2 </th> <th style="text-align:right;"> F3 </th> <th style="text-align:right;"> h2 </th> <th style="text-align:right;"> u2 </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> V1 </td> <td style="text-align:right;"> 0.15 </td> <td style="text-align:right;"> 0.35 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 0.19 </td> <td style="text-align:right;"> 0.8123 </td> </tr> <tr> <td style="text-align:left;"> V2 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 0.99 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> 1.00 </td> <td style="text-align:right;"> 0.0043 </td> </tr> <tr> <td style="text-align:left;"> V3 </td> <td style="text-align:right;"> 0.46 </td> <td style="text-align:right;"> -0.12 </td> <td style="text-align:right;"> 0.09 </td> <td style="text-align:right;"> 0.23 </td> <td style="text-align:right;"> 0.7740 </td> </tr> <tr> <td style="text-align:left;"> V4 </td> <td style="text-align:right;"> 0.45 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.39 </td> <td style="text-align:right;"> 0.6123 </td> </tr> <tr> <td style="text-align:left;"> V5 </td> <td style="text-align:right;"> 0.06 </td> <td style="text-align:right;"> 0.09 </td> <td style="text-align:right;"> 0.56 </td> <td style="text-align:right;"> 0.40 </td> <td style="text-align:right;"> 0.5984 </td> </tr> <tr> <td style="text-align:left;"> V6 </td> <td style="text-align:right;"> -0.01 </td> <td style="text-align:right;"> -0.03 </td> <td style="text-align:right;"> 0.77 </td> <td style="text-align:right;"> 0.57 </td> <td style="text-align:right;"> 0.4322 </td> </tr> <tr> <td style="text-align:left;"> V7 </td> <td style="text-align:right;"> 0.60 </td> <td style="text-align:right;"> -0.01 </td> <td style="text-align:right;"> 0.04 </td> <td style="text-align:right;"> 0.38 </td> <td style="text-align:right;"> 0.6203 </td> </tr> <tr> <td style="text-align:left;"> V8 </td> <td style="text-align:right;"> 0.74 </td> <td style="text-align:right;"> 0.00 </td> <td style="text-align:right;"> -0.08 </td> <td style="text-align:right;"> 0.49 </td> <td style="text-align:right;"> 0.5125 </td> </tr> <tr> <td style="text-align:left;"> V9 </td> <td style="text-align:right;"> 0.46 </td> <td style="text-align:right;"> 0.08 </td> <td style="text-align:right;"> 0.14 </td> <td style="text-align:right;"> 0.35 </td> <td style="text-align:right;"> 0.6506 </td> </tr> </tbody> </table> ] --- ## From variable equations to matrices In EFA practices, factors are not observed, but estimated using the **observed correlation matrix** (or covariance matrix). The common-factor model implies a reproduced cor/cov structure: $$ R \approx \Lambda \Phi \Lambda^\top + \Psi $$ - \\(\Lambda\\): loadings (\\(p \times m\\)) - \\(\Phi\\): factor correlation matrix (\\(m \times m\\); \\(\Phi = I\\) if orthogonal) - \\(\Psi\\): uniqueness matrix (\\(p \times p\\); typically diagonal with \\(\psi_i = Var(\varepsilon_i)\\)) - \\(\Lambda \Phi \Lambda^\top\\) explains the **shared** correlations (the explained standardized covariances) - \\(\Psi\\) accounts for the **residual** variance and covariances (if any) --- .center[## `$$R \approx \Lambda \Phi \Lambda^\top + \Psi$$`] ### EFA estimates .red[a small number of latent variables] and their corresponding factor loading solution (loading matrix) that approximately reproduces the original corrlations/covariances matrix (as a .red[dimension reduction] tool). --- class: inverse, middle ## Manual illustration example ### 3-variable correlation matrix → one-factor model --- ## The example Assume there are three standardized variables (V1, V2, and V3) with equal pairwise correlations (covariances): $$ R= `\begin{bmatrix} 1 & .64 & .64\\ .64 & 1 & .64\\ .64 & .64 & 1 \end{bmatrix}` $$ Given the observed correlation matrix we can assume a 1-factor model with a standardized factor `\(Var(f)=1\)`: $$ x_i = \lambda_i f + \varepsilon_i,\quad i=1,2,3 $$ --- ## The example At the correlation level, the general model-implied equation is written as: $$ R = \Lambda \Phi \Lambda^\top + \Psi $$ For the 1-factor case, there is only one factor and the variance is standardized, so `\(\Phi = [\,1\,]\)`, and: $$ \Lambda= `\begin{bmatrix} \lambda_1\\ \lambda_2\\ \lambda_3 \end{bmatrix}` $$ --- ## Full illustration of the implied matrix Compute the common-factor part explicitly: $$ \Lambda \Phi \Lambda^\top = `\begin{bmatrix} \lambda_1\\ \lambda_2\\ \lambda_3 \end{bmatrix}` [\,1\,] `\begin{bmatrix} \lambda_1 & \lambda_2 & \lambda_3 \end{bmatrix}` = `\begin{bmatrix} \lambda_1^2 & \lambda_1\lambda_2 & \lambda_1\lambda_3\\ \lambda_2\lambda_1 & \lambda_2^2 & \lambda_2\lambda_3\\ \lambda_3\lambda_1 & \lambda_3\lambda_2 & \lambda_3^2 \end{bmatrix}` $$ Since $$ \Psi= `\begin{bmatrix} \psi_1 & 0 & 0\\ 0 & \psi_2 & 0\\ 0 & 0 & \psi_3 \end{bmatrix}` $$ --- ## Full illustration of the implied matrix The full decomposition should be: $$ R= `\begin{bmatrix} \lambda_1^2+\psi_1 & \lambda_1\lambda_2 & \lambda_1\lambda_3\\ \lambda_2\lambda_1 & \lambda_2^2+\psi_2 & \lambda_2\lambda_3\\ \lambda_3\lambda_1 & \lambda_3\lambda_2 & \lambda_3^2+\psi_3 \end{bmatrix}` = `\begin{bmatrix} 1 & .64 & .64\\ .64 & 1 & .64\\ .64 & .64 & 1 \end{bmatrix}` $$ --- ### Match the observed R by solving for \\(\Lambda\\) and \\(\Psi\\) Match off-diagonal entries of \(R\) with the model-implied form: $$ \lambda_1\lambda_2=.64,\quad \lambda_1\lambda_3=.64,\quad \lambda_2\lambda_3=.64 $$ So we can easily get: $$ \lambda_1=\lambda_2=\lambda_3= .80 $$ Thus: $$ \Lambda= `\begin{bmatrix} .80\\ .80\\ .80 \end{bmatrix}` $$ --- ### Match the observed R by solving for \\(\Lambda\\) and \\(\Psi\\) Now we can get \\(\psi_i = 1 - \lambda_i^2 =1-.64 = .36\\) and thus: $$ \Psi= `\begin{bmatrix} .36 & 0 & 0\\ 0 & .36 & 0\\ 0 & 0 & .36 \end{bmatrix}` $$ --- ## The full decomposition $$ R = \Lambda[\,1\,]\Lambda^\top + \Psi = `\begin{bmatrix} .64 & .64 & .64\\ .64 & .64 & .64\\ .64 & .64 & .64 \end{bmatrix}` + `\begin{bmatrix} .36 & 0 & 0\\ 0 & .36 & 0\\ 0 & 0 & .36 \end{bmatrix}` = `\begin{bmatrix} 1 & .64 & .64\\ .64 & 1 & .64\\ .64 & .64 & 1 \end{bmatrix}` $$ ### Clarifications: - Sign indeterminacy: Technically `\(\lambda\)` could all be -.80 too, but we conventionally choose the sign so most (if not all) loadings are positive. - This exact recovery works because the matrix has perfect “equal-correlation” structure; real data will only approximate this. --- ## The full decomposition ### In this example (.purple[Interpretations?]): $$ Communality: h^2 = \lambda^2 = .80^2 = .64 $$ $$ Uniqueness: u^2 = 1 - h^2 = 1 - .64 = .36 $$ --- ## EFA in practice In real-world practice **.red[we cannot "guess" the best factor structure]** (number of factors, correlations among factors, etc.) by only eyeballing the data Real datasets also **.red[don't have this "balanced-correlation" structure with an easy solution]** of `\(\Lambda\)` and `\(\Psi\)`, so we need certain techiniques to find optimized solutions for us Real datasets are complex, imperfect, and with noises, so we need to evaluate residuals and fit and compare multiple solutions --- ## Lastly but probably most importantly... In most psychological research, the purpose of EFA is **.red[not limited to]** finding a data-driven solution We also need a reliable and valid measurement structure that **.red["makes most sense"]** out of the observed correlations/covariances We want to interpret the latent factors as the estimated attribute of the corresponding unobservable constructs, defined by the manifest variables **.red[and the corresponding factor loadings]** --- class: inverse, middle ## EFA workflow and executive steps ### Important decisions in each EFA stage using an example --- ## The simulated dataset
--- .pull-left[ ## The Story “Files - Week 02 - EFASimData.csv” N = 250, Test-level scores on 9 cognitive tests - Fluid reasoning: F1, F2, F3 - Verbal reasoning: V1, V2, V3 - Spatial reasoning: S1, S2, S3 ``` r SimDat <- read.csv("EFASimData.csv") library(psych) describe(SimDat[,-1], range = FALSE) ``` ] .pull-right[ <table style = 'width: 75%;'> <caption>Descriptive statistics for EFASimData (N = 250)</caption> <thead> <tr> <th style="text-align:left;"> </th> <th style="text-align:right;"> mean </th> <th style="text-align:right;"> sd </th> <th style="text-align:right;"> skew </th> <th style="text-align:right;"> kurtosis </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> F1 </td> <td style="text-align:right;"> 99.95 </td> <td style="text-align:right;"> 18.59 </td> <td style="text-align:right;"> -0.30 </td> <td style="text-align:right;"> 0.42 </td> </tr> <tr> <td style="text-align:left;"> F2 </td> <td style="text-align:right;"> 100.23 </td> <td style="text-align:right;"> 19.93 </td> <td style="text-align:right;"> 0.07 </td> <td style="text-align:right;"> 0.07 </td> </tr> <tr> <td style="text-align:left;"> F3 </td> <td style="text-align:right;"> 99.22 </td> <td style="text-align:right;"> 19.36 </td> <td style="text-align:right;"> 0.02 </td> <td style="text-align:right;"> -0.23 </td> </tr> <tr> <td style="text-align:left;"> V1 </td> <td style="text-align:right;"> 100.50 </td> <td style="text-align:right;"> 21.57 </td> <td style="text-align:right;"> 0.20 </td> <td style="text-align:right;"> -0.36 </td> </tr> <tr> <td style="text-align:left;"> V2 </td> <td style="text-align:right;"> 100.00 </td> <td style="text-align:right;"> 21.25 </td> <td style="text-align:right;"> -0.10 </td> <td style="text-align:right;"> -0.57 </td> </tr> <tr> <td style="text-align:left;"> V3 </td> <td style="text-align:right;"> 101.84 </td> <td style="text-align:right;"> 19.95 </td> <td style="text-align:right;"> -0.10 </td> <td style="text-align:right;"> 0.02 </td> </tr> <tr> <td style="text-align:left;"> S1 </td> <td style="text-align:right;"> 101.16 </td> <td style="text-align:right;"> 20.58 </td> <td style="text-align:right;"> 0.19 </td> <td style="text-align:right;"> 0.25 </td> </tr> <tr> <td style="text-align:left;"> S2 </td> <td style="text-align:right;"> 102.37 </td> <td style="text-align:right;"> 20.85 </td> <td style="text-align:right;"> -0.19 </td> <td style="text-align:right;"> -0.51 </td> </tr> <tr> <td style="text-align:left;"> S3 </td> <td style="text-align:right;"> 101.31 </td> <td style="text-align:right;"> 19.63 </td> <td style="text-align:right;"> -0.03 </td> <td style="text-align:right;"> -0.27 </td> </tr> </tbody> </table> ] --- ### Step 1: Eyeball your data! .pull-left[ ``` r # This is good enough! *Dat <- na.omit(SimDat[,-1]) cortable <- cor(Dat) # Some visualization ideas library(psych) cor.plot(cortable, numbers = TRUE, upper = FALSE, main = "") ``` ] .pull-right[ <!-- --> ] --- ### Step 1: Eyeball your data! .pull-left[ ``` r # Give this function a try # and find more settings in # the R documentation page library(corrplot) corrplot.mixed(cortable, tl.col = "black", title = "") ``` ] .pull-right[ <!-- --> ] --- ## Step 2: Factorability Checks ### Bartlett's test of sphericity In intuitive terms, it tests whether there are enough correlations among the items to “factor analyze” with] In mathematical terms, it tests whether the correlation matrix is significantly different from an identity matrix ``` r cortest.bartlett(cortable, n = nrow(SimDat)) ``` --- ### Bartlett's test of sphericity ``` r cortest.bartlett(cortable, n = nrow(SimDat)) ``` ``` $chisq [1] 858.1438 $p.value [1] 7.514478e-157 $df [1] 36 ``` It is a \\(\chi^2\\) test: \\(\chi^2(36) = 858.14, p < .001\\). What does the significance mean? -- **There are some correlations to “extract” factors from.** --- ## Step 2: Factorability Checks ### The Kaiser-Meyer-Olkin (KMO) sampling adequacy test In intuitive terms, it tests whether the sample of manifest variables (not the sample of observations) share common patterns with each other In mathematical terms, it estimates the amount of variances in each of the manifest variables that might be common (with all other variables), as well as the overall amount of variances that might be common. --- ### The KMO test .pull-left[ The test gives a measure of sampling adequacy (MSA) for each variable as well as for the entire dataset, ranged from 0 to 1. ``` r KMO(cortable) ``` ``` Kaiser-Meyer-Olkin factor adequacy Call: KMO(r = cortable) Overall MSA = 0.83 MSA for each item = F1 F2 F3 V1 V2 V3 S1 S2 S3 0.87 0.84 0.83 0.79 0.85 0.81 0.82 0.83 0.81 ``` ] .pull-right[ Kaiser (1970)'s rule: - KMO > 0.9, "Marvelous" - KMO > 0.8, "Meritorious" - KMO > 0.7, "Middling" - KMO > 0.6, "Mediocre" - KMO > 0.5, "Miserable" MSAs < .70 usually indicate inappropriate sampling of variables and MSAs > .90 are preferred. ] --- ## Step 2: Other Assumptions **Determinant of the correlation matrix** - Avoid singularity or extremely high multicollinearity **Sample size** - Not necessarily always valid but a rule of thumb is 5 to 20 subjects per variable with total > 150 preferable **Measurement scales and distributions of the observed variables** - Binary, Ordinal or continuous (Interval or Ratio)? - Normal? Slightly skewed? Or something "weird"? --- ## Step 3: Decisions before fitting **Factor extraction methods** determines how the factor solution is estimated. - Unweighted least square (**minres**): minimizes the entire residuals matrix (default by "psych") - Maximum likelihood (**ml**): Works well with normal data - Principal axis (**pa**): Classical default choice in SPSS - Weighted least squares (**wls**): suggested for ordinal data (Poly-cor) - .red[PCA is not considered here.] ??? Extraction is about estimation target and assumptions. Rotation is about interpretability constraints and whether factors can correlate. --- ## Step 3: Decisions before fitting **Rotation methods** improves the interpretability of the factor structure provided by the solution (while not changing the reproduced correlation matrix) Orthogonal rotations assumes that the extracted factors are not correlated with each other - **varimax** is the most common orthogonal rotation approach Oblique rotations assumes that the extracted factors are correlated with each other - **oblimin** is the most common oblique rotation approach (default by "psych") --- ## Step 3: Decisions before fitting **Number of factors** needs to be choosed before running the current solution (does not need to be determined as a final decision) 1. Eigenvalues (a set of numbers, each approximately indicates the amount of variances attributes to an extra potential factor) - The total number of Eigenvalues = the total number of observed variables - Kaiser’s rule: Eigenvalues > 1 indicate meaningful factor 2. "Elbow" approach on Scree plot (plotting the eigen values) 3. Parallel analysis (concurrent and recommended) --- ## Step 3: Decisions before fitting[ ``` r # Parallel analysis for factor analysis (FA) fa.parallel(SimDat[,-1], fm = "ml", fa = "fa", n.iter = 100, error.bars = T) ``` <!-- --> --- class: inverse, middle ## The current decisions - Extration method: Maximum Likelihood (ml) - Rotation method: Oblique rotation (oblimin) - Number of factors: 3 #### Given the exploratory nature, we may need to conduct and compare different solutions before making a "best" choice. --- class: scrollable-slide ## Step 4: Fit the EFA solutions ``` r efa.fit <- fa(SimDat[,-1], nfactors = 3, fm = "ml", rotate = "oblimin") efa.fit ``` ``` Factor Analysis using method = ml Call: fa(r = SimDat[, -1], nfactors = 3, rotate = "oblimin", fm = "ml") Standardized loadings (pattern matrix) based upon correlation matrix ML1 ML2 ML3 h2 u2 com F1 0.68 0.12 0.10 0.67 0.33 1.1 F2 0.85 0.02 -0.06 0.68 0.32 1.0 F3 0.88 -0.06 0.02 0.74 0.26 1.0 V1 0.00 0.81 -0.05 0.64 0.36 1.0 V2 0.02 0.64 0.05 0.44 0.56 1.0 V3 0.02 0.64 0.06 0.45 0.55 1.0 S1 0.00 0.10 0.67 0.51 0.49 1.0 S2 0.03 -0.07 0.70 0.49 0.51 1.0 S3 -0.01 -0.01 0.70 0.48 0.52 1.0 ML1 ML2 ML3 SS loadings 2.04 1.56 1.51 Proportion Var 0.23 0.17 0.17 Cumulative Var 0.23 0.40 0.57 Proportion Explained 0.40 0.31 0.30 Cumulative Proportion 0.40 0.70 1.00 With factor correlations of ML1 ML2 ML3 ML1 1.00 0.55 0.58 ML2 0.55 1.00 0.31 ML3 0.58 0.31 1.00 Mean item complexity = 1 Test of the hypothesis that 3 factors are sufficient. df null model = 36 with the objective function = 3.5 with Chi Square = 858.14 df of the model are 12 and the objective function was 0.07 The root mean square of the residuals (RMSR) is 0.02 The df corrected root mean square of the residuals is 0.03 The harmonic n.obs is 250 with the empirical chi square 3.56 with prob < 0.99 The total n.obs was 250 with Likelihood Chi Square = 15.86 with prob < 0.2 Tucker Lewis Index of factoring reliability = 0.986 RMSEA index = 0.036 and the 90 % confidence intervals are 0 0.078 BIC = -50.4 Fit based upon off diagonal values = 1 Measures of factor score adequacy ML1 ML2 ML3 Correlation of (regression) scores with factors 0.80 0.81 0.78 Multiple R square of scores with factors 0.63 0.65 0.61 Minimum correlation of possible factor scores 0.27 0.30 0.22 ``` --- ## Factor Loadings > The association between a manifest and a factor: how much the observed variable can reflect the factor Common rules of thumb: - At least 2 observed variables on each factor (3 or more is preferred) - Each observed item should (ideally) has one and only one large loading (common cutoffs: 0.1, 0.3, 0.7) - Communality (0 to 1): close to 1 is preferred - Complexity (1 to +inf): closer to 1 is preferred --- ## Factor Loadings ``` r # Omit the weak loadings (<.30 are not printed) print(efa.fit$loadings, cutoff = 0.30, sort = TRUE) ``` ``` Loadings: ML1 ML2 ML3 F1 0.683 F2 0.847 F3 0.882 V1 0.813 V2 0.638 V3 0.638 S1 0.674 S2 0.704 S3 0.702 ML1 ML2 ML3 SS loadings 1.965 1.507 1.465 Proportion Var 0.218 0.167 0.163 Cumulative Var 0.218 0.386 0.549 ``` ??? Prompts: - “Which variables define each factor?” - “Any cross-loadings that complicate naming?” - “How would you label factors 1–3?” - “Which variables are well explained (high h2) vs not (low h2)?” - “Do factor correlations make substantive sense?” Explain variance accounted for conceptually as a summary of what the factor space captures (do not treat it as identical to PCA percent variance explained). --- ## Residuals (optional diagnostic output) ``` r # Residual correlation matrix: observed R minus reproduced R residmat <- efa.fit$residual round(residmat, 2) ``` ``` F1 F2 F3 V1 V2 V3 S1 S2 S3 F1 0.33 0.00 0.00 0.01 -0.03 0.01 -0.01 0.02 -0.01 F2 0.00 0.32 0.00 0.00 0.02 -0.02 0.00 -0.02 0.02 F3 0.00 0.00 0.26 -0.01 0.00 0.01 0.01 0.00 -0.01 V1 0.01 0.00 -0.01 0.36 -0.01 0.00 0.03 0.00 -0.03 V2 -0.03 0.02 0.00 -0.01 0.56 0.02 0.02 0.00 -0.01 V3 0.01 -0.02 0.01 0.00 0.02 0.55 -0.07 0.00 0.06 S1 -0.01 0.00 0.01 0.03 0.02 -0.07 0.49 0.00 0.01 S2 0.02 -0.02 0.00 0.00 0.00 0.00 0.00 0.51 -0.01 S3 -0.01 0.02 -0.01 -0.03 -0.01 0.06 0.01 -0.01 0.52 ``` --- ## Step 5: Explore the different solutions - Compare number of factors (1 vs 3, or other numbers?), same extraction and rotation - Compare extraction methods (minres vs ml vs pa), same factor num and rotation - Compare rotation (oblimin vs varimax), same factor num and extraction - More considerations in real-world practice --- ## Step 6: Visualize with diagram .pull-left[ ``` r fa.diagram(efa.fit, digits = 2, cut = .0, adj = 3, main = "Full") ``` ] .pull-right[ <!-- --> ] --- ## Step 6: Visualize with diagram .pull-left[ ``` r fa.diagram(efa.fit, digits = 2, cut = .3, adj = 3, main = "Clean") ``` ] .pull-right[ <!-- --> ] --- ## Summary - Step 1: Eyeballing your data - Step 2: Assumption (Factorability) Checks - Step 3: Priori decisions (Extraction, Rotation, Num of Factors) - Step 4: Fitting the EFA solutions - Step 5: Exploring the different solutions - Step 6: Finalizing and visualizing with diagram --- ## Next Week - PCA vs. EFA and ordinal data solution - What and How to Report EFA - Real-world Example (Demo for Lab 1) - Grouping for Paper Critique Seminars --- ## Readings Fabrigar, L. R., Wegener, D. T., MacCallum, R. C., & Strahan, E. J. (1999). Evaluating the use of exploratory factor analysis in psychological research. *Psychological methods*, 4(3), 272. Revelle, W. (2025). How to: Use the psych package for factor analysis and data reduction. Northwestern University, Department of Psychology: Evanston, IL, USA.