Skip to content

Commit c233ef6

Browse files
committed
Add format() method to parameters_efa objects
Fixes #1234
1 parent 98c4d47 commit c233ef6

4 files changed

Lines changed: 127 additions & 55 deletions

File tree

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,11 @@ S3method(format,equivalence_test_lm)
173173
S3method(format,p_calibrate)
174174
S3method(format,parameters_brms_meta)
175175
S3method(format,parameters_coef)
176+
S3method(format,parameters_efa)
176177
S3method(format,parameters_model)
178+
S3method(format,parameters_omega)
177179
S3method(format,parameters_p_function)
180+
S3method(format,parameters_pca)
178181
S3method(format,parameters_sem)
179182
S3method(format,parameters_simulate)
180183
S3method(format,parameters_standardized)

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
* `simulate_model()`, `simulate_parameters()` and `equivalence_test()` now work
66
for `lavaan` objects.
77

8+
* Added `format()` method for objects returned by `factor_analysis()` and
9+
`principal_components()`.
10+
811
## Bug fixes
912

1013
* Fixed issues with extracting wrong standard errors for model with frailty

R/format.R

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,30 @@ format.compare_parameters <- function(
478478
formatted_table
479479
}
480480

481+
# PCA/FA-models ---------------------------------
482+
483+
#' @export
484+
format.parameters_pca <- function(x, labels = NULL, threshold = NULL, ...) {
485+
# Labels
486+
if (!is.null(labels)) {
487+
x$Label <- labels
488+
x <- x[c("Variable", "Label", names(x)[!names(x) %in% c("Variable", "Label")])]
489+
}
490+
491+
# Replace by NA all cells below threshold
492+
if (!is.null(threshold)) {
493+
x <- .filter_loadings(x, threshold = threshold)
494+
}
495+
496+
x
497+
}
498+
499+
#' @export
500+
format.parameters_efa <- format.parameters_pca
501+
502+
#' @export
503+
format.parameters_omega <- format.parameters_pca
504+
481505
# sem-models ---------------------------------
482506

483507
#' @export

R/utils_pca_efa.R

Lines changed: 97 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ get_scores <- function(x, n_items = NULL) {
7979

8080
# model parameters -----------------------------------------------------------------
8181

82-
8382
#' @export
8483
model_parameters.parameters_efa <- function(model, ...) {
8584
x <- attributes(model)$summary
@@ -99,7 +98,6 @@ model_parameters.parameters_pca <- model_parameters.parameters_efa
9998

10099
# summary -----------------------------------------------------------------
101100

102-
103101
#' @export
104102
summary.parameters_efa <- function(object, ...) {
105103
x <- attributes(object)$summary
@@ -146,15 +144,16 @@ summary.parameters_omega <- function(object, ...) {
146144

147145
# predict -----------------------------------------------------------------
148146

149-
150147
#' @rdname principal_components
151148
#' @export
152-
predict.parameters_efa <- function(object,
153-
newdata = NULL,
154-
names = NULL,
155-
keep_na = TRUE,
156-
verbose = TRUE,
157-
...) {
149+
predict.parameters_efa <- function(
150+
object,
151+
newdata = NULL,
152+
names = NULL,
153+
keep_na = TRUE,
154+
verbose = TRUE,
155+
...
156+
) {
158157
attri <- attributes(object)
159158

160159
# handle if no data is provided
@@ -179,13 +178,29 @@ predict.parameters_efa <- function(object,
179178
# https://github.com/erichson/spca/issues/7
180179
newdata <- newdata[names(attri$model$center)]
181180
if (attri$standardize) {
182-
newdata <- sweep(newdata, MARGIN = 2, STATS = attri$model$center, FUN = "-", check.margin = TRUE)
183-
newdata <- sweep(newdata, MARGIN = 2, STATS = attri$model$scale, FUN = "/", check.margin = TRUE)
181+
newdata <- sweep(
182+
newdata,
183+
MARGIN = 2,
184+
STATS = attri$model$center,
185+
FUN = "-",
186+
check.margin = TRUE
187+
)
188+
newdata <- sweep(
189+
newdata,
190+
MARGIN = 2,
191+
STATS = attri$model$scale,
192+
FUN = "/",
193+
check.margin = TRUE
194+
)
184195
}
185196
out <- as.matrix(newdata) %*% as.matrix(attri$model$loadings)
186197
out <- stats::setNames(as.data.frame(out), paste0("Component", seq_len(ncol(out))))
187198
} else if (inherits(attri$model, c("psych", "fa", "principal"))) {
188-
out <- as.data.frame(stats::predict(attri$model, data = newdata[rownames(attri$model$weights)], ...))
199+
out <- as.data.frame(stats::predict(
200+
attri$model,
201+
data = newdata[rownames(attri$model$weights)],
202+
...
203+
))
189204
} else {
190205
out <- as.data.frame(stats::predict(attri$model, newdata = newdata, ...))
191206
}
@@ -221,21 +236,25 @@ predict.parameters_pca <- predict.parameters_efa
221236

222237
# print -------------------------------------------------------------------
223238

224-
225239
#' @export
226240
print.parameters_efa_summary <- function(x, digits = 3, ...) {
227241
# we may have factor correlations
228242
fc <- attributes(x)$factor_correlations
229243

230244
if ("Parameter" %in% names(x)) {
231245
x$Parameter <- c(
232-
"Eigenvalues", "Variance Explained", "Variance Explained (Cumulative)",
246+
"Eigenvalues",
247+
"Variance Explained",
248+
"Variance Explained (Cumulative)",
233249
"Variance Explained (Proportion)"
234250
)
235251
} else if ("Component" %in% names(x)) {
236252
names(x) <- c(
237-
"Component", "Eigenvalues", "Variance Explained",
238-
"Variance Explained (Cumulative)", "Variance Explained (Proportion)"
253+
"Component",
254+
"Eigenvalues",
255+
"Variance Explained",
256+
"Variance Explained (Cumulative)",
257+
"Variance Explained (Proportion)"
239258
)
240259
}
241260

@@ -258,7 +277,6 @@ print.parameters_efa_summary <- function(x, digits = 3, ...) {
258277
))
259278
}
260279

261-
262280
invisible(x)
263281
}
264282

@@ -269,12 +287,14 @@ print.parameters_pca_summary <- print.parameters_efa_summary
269287

270288
#' @rdname principal_components
271289
#' @export
272-
print.parameters_efa <- function(x,
273-
digits = 2,
274-
sort = FALSE,
275-
threshold = NULL,
276-
labels = NULL,
277-
...) {
290+
print.parameters_efa <- function(
291+
x,
292+
digits = 2,
293+
sort = FALSE,
294+
threshold = NULL,
295+
labels = NULL,
296+
...
297+
) {
278298
# extract attributes
279299
if (is.null(threshold)) {
280300
threshold <- attributes(x)$threshold
@@ -308,7 +328,6 @@ print.parameters_omega_summary <- function(x, ...) {
308328

309329
# print-helper ----------------------
310330

311-
312331
.print_omega_summary <- function(x, format = "text") {
313332
caption1 <- NULL
314333
caption2 <- NULL
@@ -318,8 +337,20 @@ print.parameters_omega_summary <- function(x, ...) {
318337
model <- attributes(x)$model
319338
if (!is.null(model)) {
320339
stats <- data.frame(
321-
Statistic = c("Alpha", "G.6", "Omega (hierarchical)", "Omega (asymptotic H)", "Omega (total)"),
322-
Coefficient = c(model$alpha, model$G6, model$omega_h, model$omega.lim, model$omega.tot)
340+
Statistic = c(
341+
"Alpha",
342+
"G.6",
343+
"Omega (hierarchical)",
344+
"Omega (asymptotic H)",
345+
"Omega (total)"
346+
),
347+
Coefficient = c(
348+
model$alpha,
349+
model$G6,
350+
model$omega_h,
351+
model$omega.lim,
352+
model$omega.tot
353+
)
323354
)
324355
if (format == "text") {
325356
caption1 <- c("# Omega Statistics", "blue")
@@ -335,7 +366,10 @@ print.parameters_omega_summary <- function(x, ...) {
335366
# rename columns
336367
if (!is.null(omega_coefficients)) {
337368
names(omega_coefficients) <- c(
338-
"Composite", "Omega (total)", "Omega (hierarchical)", "Omega (group)"
369+
"Composite",
370+
"Omega (total)",
371+
"Omega (hierarchical)",
372+
"Omega (group)"
339373
)
340374
if (format == "text") {
341375
caption2 <- c("# Omega Coefficients", "blue")
@@ -345,7 +379,9 @@ print.parameters_omega_summary <- function(x, ...) {
345379
}
346380
if (!is.null(variance_summary)) {
347381
names(variance_summary) <- c(
348-
"Composite", "Total (%)", "General Factor (%)",
382+
"Composite",
383+
"Total (%)",
384+
"General Factor (%)",
349385
"Group Factor (%)"
350386
)
351387
if (format == "text") {
@@ -379,21 +415,8 @@ print.parameters_omega_summary <- function(x, ...) {
379415
# Rotation
380416
rotation_name <- attr(x, "rotation", exact = TRUE)
381417

382-
# Labels
383-
if (!is.null(labels)) {
384-
x$Label <- labels
385-
x <- x[c("Variable", "Label", names(x)[!names(x) %in% c("Variable", "Label")])]
386-
}
387-
388-
# Sorting
389-
if (isTRUE(sort)) {
390-
x <- .sort_loadings(x)
391-
}
392-
393-
# Replace by NA all cells below threshold
394-
if (!is.null(threshold)) {
395-
x <- .filter_loadings(x, threshold = threshold)
396-
}
418+
# formatting
419+
x <- format(x, labels, threshold, ...)
397420

398421
# table caption
399422
if (is.null(rotation_name) || rotation_name == "none") {
@@ -403,16 +426,29 @@ print.parameters_omega_summary <- function(x, ...) {
403426
table_caption <- c(sprintf("# Loadings from %s (no rotation)", method), "blue")
404427
}
405428
} else if (format %in% c("markdown", "html")) {
406-
table_caption <- sprintf("Rotated loadings from %s (%s-rotation)", method, rotation_name)
429+
table_caption <- sprintf(
430+
"Rotated loadings from %s (%s-rotation)",
431+
method,
432+
rotation_name
433+
)
407434
} else {
408-
table_caption <- c(sprintf("# Rotated loadings from %s (%s-rotation)", method, rotation_name), "blue")
435+
table_caption <- c(
436+
sprintf("# Rotated loadings from %s (%s-rotation)", method, rotation_name),
437+
"blue"
438+
)
409439
}
410440

411441
# footer
412442
if (is.null(attributes(x)$type)) {
413443
footer <- NULL
414444
} else {
415-
footer <- c(.text_components_variance(x, sep = ifelse(format %in% c("markdown", "html"), "", "\n")), "yellow")
445+
footer <- c(
446+
.text_components_variance(
447+
x,
448+
sep = ifelse(format %in% c("markdown", "html"), "", "\n")
449+
),
450+
"yellow"
451+
)
416452
}
417453

418454
# alignment?
@@ -471,7 +507,6 @@ print.parameters_omega_summary <- function(x, ...) {
471507
text_variance <- paste0(text_variance, " (", attributes(x)$rotation, " rotation)")
472508
}
473509

474-
475510
text_variance <- paste0(
476511
text_variance,
477512
" accounted for ",
@@ -485,7 +520,8 @@ print.parameters_omega_summary <- function(x, ...) {
485520
text_variance <- paste0(
486521
text_variance,
487522
" (",
488-
paste0(cluster_summary$Component,
523+
paste0(
524+
cluster_summary$Component,
489525
" = ",
490526
sprintf("%.2f", cluster_summary$Variance * 100),
491527
"%",
@@ -560,14 +596,12 @@ sort.parameters_pca <- sort.parameters_efa
560596

561597
# Filter --------------------------------------------------------------------
562598

563-
564599
#' @keywords internal
565600
.filter_loadings <- function(loadings, threshold = 0.2, loadings_columns = NULL) {
566601
if (is.null(loadings_columns)) {
567602
loadings_columns <- attributes(loadings)$loadings_columns
568603
}
569604

570-
571605
if (threshold == "max" || threshold >= 1) {
572606
if (threshold == "max") {
573607
for (row in seq_len(nrow(loadings))) {
@@ -576,7 +610,10 @@ sort.parameters_pca <- sort.parameters_efa
576610
}
577611
} else {
578612
for (col in loadings_columns) {
579-
loadings[utils::tail(order(abs(loadings[, col]), decreasing = TRUE), -round(threshold)), col] <- NA
613+
loadings[
614+
utils::tail(order(abs(loadings[, col]), decreasing = TRUE), -round(threshold)),
615+
col
616+
] <- NA
580617
}
581618
}
582619
} else {
@@ -589,7 +626,6 @@ sort.parameters_pca <- sort.parameters_efa
589626

590627
# closest_component -------------------------------------------------------
591628

592-
593629
#' @rdname principal_components
594630
#' @export
595631
closest_component <- function(x) {
@@ -602,9 +638,15 @@ closest_component <- function(x) {
602638

603639

604640
.closest_component <- function(loadings, loadings_columns = NULL, variable_names = NULL) {
605-
if (is.matrix(loadings)) loadings <- as.data.frame(loadings)
606-
if (is.null(loadings_columns)) loadings_columns <- seq_len(ncol(loadings))
607-
if (is.null(variable_names)) variable_names <- row.names(loadings)
641+
if (is.matrix(loadings)) {
642+
loadings <- as.data.frame(loadings)
643+
}
644+
if (is.null(loadings_columns)) {
645+
loadings_columns <- seq_len(ncol(loadings))
646+
}
647+
if (is.null(variable_names)) {
648+
variable_names <- row.names(loadings)
649+
}
608650
component_columns <- apply(loadings[loadings_columns], 1, function(i) which.max(abs(i)))
609651
stats::setNames(component_columns, variable_names)
610652
}

0 commit comments

Comments
 (0)