Skip to content

KMO values always at around 0.50 #80

Description

@andreassoteriadesmoj

Using numerous versions of my own data sets as well as data from various R packages, I've noticed that CAF barely leaves the 0.50 area (plus/minus, give or take). Therefore, I did a little experiment: calculate KMO for a residual matrix that has very small values, i.e. I was trying to reproduce a situation where the original correlation matrix and the model-implied correlation matrix are really close to each other. I was hoping to get a KMO near 0 (hence a CAF near 1), but got one near 0.5 instead:

res_mat <- matrix(0, 5, 5)
diag(res_mat) <- 1
res_mat [upper.tri(res_mat)] <- runif(10, 0.001, 0.01)
res_mat [lower.tri(res_mat)] <- res_mat [upper.tri(res_mat)]
res_mat <- (res_mat + t(res_mat)) / 2 # Ensures elements above and below diagonal have same precision
EFAtools::KMO(res_mat)$KMO

I think that the problem originates in the line where the diagonal of the residual matrix is set to be all ones (diag(res_mat)):

diag(delta_hat) <- 1

This step is necessary so that KMO considers res_mat a correlation matrix and skips step R <- stats::cor(x, use = use, method = cor_method). However, unless I'm mistaken, the diagonal of res_mat should be zero given that we take the difference between the original correlation matrix and the model-implied correlation matrix. Let's supply a res_mat with small numbers off the diagonal and zeroes on the diagonal and calculate KMO/CAF step by step and see what happens:

res_mat.csv

res_mat <- read.csv('res_mat.csv')
res_mat <- as.matrix(res_mat)

R <- res_mat
R_i <- try(solve(R), silent = TRUE)
diag(R_i) # The diag elements will not always be all positive
S <- diag(diag(R_i)^(-1/2))
Q <- S %*% R_i %*% S
diag(Q) <- 0
diag(R) <- 0
sumQ2 <- sum(Q^2)
sumR2 <- sum(R^2)
KMO <- sumR2/(sumR2 + sumQ2)
caf <- 1 - KMO
caf
# 0.999479

As expected, the CAF is very high given that the two matrices differ by very small amounts. Looks like KMO() will need to be modified to consider as a special case an input x that is not a correlation matrix or a raw dataset for which to calculate correlations. I wouldn't know how to handle a situation where diag(R_i) has negative elements though. As x isn't a correlation matrix in this case, smoothing it with R <- psych::cor.smooth(R) (where R <- x) isn't relevant. Would one set all diagonal elements to a fixed number for example? I don't know...

Note that this issue also relates to #72.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions