Skip to content

Commit e4eba41

Browse files
committed
add matrix method
1 parent 8ff744b commit e4eba41

File tree

5 files changed

+119
-11
lines changed

5 files changed

+119
-11
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
## Changes
1818

19+
* `factor_analysis()` gets a `.matrix` method, including arguments `n_obs` and
20+
`n_matrix`, to compute factor analysis for a correlation matrix or covariance
21+
matrix.
22+
1923
* New function `factor_scores()` to extract factor scores from EFA (`psych::fa()`
2024
or `factor_analysis()`).
2125

R/factor_analysis.R

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,43 @@ factor_analysis.data.frame <- function(x,
4242
}
4343

4444

45+
#' @rdname principal_components
4546
#' @export
46-
factor_analysis.matrix <- factor_analysis.data.frame
47+
factor_analysis.matrix <- function(x,
48+
n = "auto",
49+
rotation = "oblimin",
50+
n_obs = NULL,
51+
n_matrix = NULL,
52+
sort = FALSE,
53+
threshold = NULL,
54+
standardize = FALSE,
55+
...) {
56+
# check if we have a square matrix. in this case, we assume that
57+
# the user wants to do a factor analysis on the correlation matrix
58+
if ((dim(x)[1] == dim(x)[2]) && is.null(n_obs)) {
59+
insight::format_error(
60+
"You provided a square matrix, which is assumed to be a correlation matrix. Please specify the number of observations with `n_obs`. If your matrix is not a correlation matrix, please provide a data frame instead."
61+
)
62+
}
63+
64+
# the default n.obs argument in `psych::fa()` is `NA`, so we change
65+
# our default `NULL` to `NA` to avoid errors
66+
if (is.null(n_obs)) {
67+
n_obs <- NA
68+
}
69+
70+
factor_analysis.data.frame(
71+
as.data.frame(x),
72+
n = n,
73+
rotation = rotation,
74+
sort = sort,
75+
threshold = threshold,
76+
standardize = standardize,
77+
n.obs = n_obs,
78+
np.obs = n_matrix,
79+
...
80+
)
81+
}
4782

4883

4984
.is_oblique_rotation <- function(rotation) {

R/principal_components.R

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#' Principal Component Analysis (PCA) and Factor Analysis (FA)
22
#'
3-
#' The functions `principal_components()` and `factor_analysis()` can
4-
#' be used to perform a principal component analysis (PCA) or a factor analysis
5-
#' (FA). They return the loadings as a data frame, and various methods and
6-
#' functions are available to access / display other information (see the
7-
#' Details section).
3+
#' The functions `principal_components()` and `factor_analysis()` can be used to
4+
#' perform a principal component analysis (PCA) or a factor analysis (FA). They
5+
#' return the loadings as a data frame, and various methods and functions are
6+
#' available to access / display other information (see the 'Details' section).
87
#'
98
#' @param x A data frame or a statistical model.
109
#' @param n Number of components to extract. If `n="all"`, then `n` is set as
@@ -26,6 +25,19 @@
2625
#' interpretability and avoids overfitting. Can be `TRUE` or `"robust"` (see
2726
#' [`sparsepca::robspca()`]).
2827
#' @param sort Sort the loadings.
28+
#' @param n_obs Number of observations in the original data set if `x` is a
29+
#' correlation matrix. Required to compute correct fit indices.
30+
#' @param n_matrix This argument expects a matrix where each cell `[i, j]`
31+
#' specifies the number of pairwise complete observations used to compute the
32+
#' correlation between variable `i` and variable `j` in the input `x`. It is
33+
#' crucial when `x` is a correlation matrix (rather than raw data), especially
34+
#' if that matrix was derived from a dataset containing missing values using
35+
#' pairwise deletion. Providing `n_matrix` allows `psych::fa()` to accurately
36+
#' calculate statistical measures, such as chi-square fit statistics, by
37+
#' accounting for the varying sample sizes that contribute to each individual
38+
#' correlation coefficient. This precision is vital for methods that rely on
39+
#' these specific sample sizes for statistical inference, such as 'minimum
40+
#' chi-square' (minchi) solutions.
2941
#' @param threshold A value between 0 and 1 indicates which (absolute) values
3042
#' from the loadings should be removed. An integer higher than 1 indicates the
3143
#' n strongest loadings to retain. Can also be `"max"`, in which case it will

man/principal_components.Rd

Lines changed: 32 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-factor_analysis.R

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,36 @@ test_that("factor_analysis", {
5050
# check factor scores
5151
fc <- factor_scores(out)
5252
expect_identical(dim(fc), c(32L, 2L))
53+
54+
# works with correlation matrix
55+
skip_if_not_installed("correlation")
56+
skip_on_cran() # takes too long on CRAN
57+
58+
raq_poly <- correlation::correlation(raq_items, method = "polychoric")
59+
raq_poly_mtx <- as.matrix(raq_poly) # store correlation matrix
60+
61+
# needs n_obs
62+
expect_error(
63+
factor_analysis(raq_poly_mtx, n = 4),
64+
regex = "You provided a square matrix"
65+
)
66+
67+
out1 <- factor_analysis(raq_poly_mtx, n = 4, n_obs = 2571)
68+
expect_identical(dim(out1), c(23L, 7L))
69+
expect_named(
70+
out1,
71+
c("Variable", "MR1", "MR2", "MR4", "MR3", "Complexity", "Uniqueness")
72+
)
73+
74+
out2 <- factor_analysis(as.matrix(raq_items), n = 4)
75+
expect_identical(dim(out2), c(23L, 7L))
76+
expect_named(
77+
out2,
78+
c("Variable", "MR1", "MR2", "MR4", "MR3", "Complexity", "Uniqueness")
79+
)
80+
81+
# roughly equal results
82+
expect_equal(out1$MR1, out2$MR1, tolerance = 1e-1)
5383
})
5484

5585

0 commit comments

Comments
 (0)