Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
strengejacke committed Jan 8, 2024
1 parent 527efce commit ab95e73
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 18 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ S3method(logLik,plm)
S3method(logLik,svycoxph)
S3method(mcdonalds_omega,data.frame)
S3method(mcdonalds_omega,matrix)
S3method(mcdonalds_omega,parameters_pca)
S3method(model_performance,Arima)
S3method(model_performance,BFBayesFactor)
S3method(model_performance,DirichletRegModel)
Expand Down Expand Up @@ -293,6 +294,7 @@ S3method(print,icc_decomposed)
S3method(print,item_difficulty)
S3method(print,item_discrimination)
S3method(print,looic)
S3method(print,mcdonalds_omega)
S3method(print,performance_accuracy)
S3method(print,performance_cv)
S3method(print,performance_hosmer)
Expand Down
5 changes: 2 additions & 3 deletions R/cronbachs_alpha.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#' @description Compute various measures of internal consistencies
#' for tests or item-scales of questionnaires.
#'
#' @param x A matrix or a data frame.
#' @param x A matrix or a data frame, or an object returned by
#' `[parameters::principal_components()]`.
#' @param ... Currently not used.
#'
#' @return The Cronbach's Alpha value for `x`.
Expand Down Expand Up @@ -50,14 +51,12 @@ cronbachs_alpha.data.frame <- function(x, verbose = TRUE, ...) {
}



#' @export
cronbachs_alpha.matrix <- function(x, verbose = TRUE, ...) {
cronbachs_alpha(as.data.frame(x), verbose = verbose, ...)
}



#' @export
cronbachs_alpha.parameters_pca <- function(x, verbose = TRUE, ...) {
# fetch data used for the PCA
Expand Down
108 changes: 95 additions & 13 deletions R/mcdonalds_omega.r
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
#' @description Compute various measures of internal consistencies
#' for tests or item-scales of questionnaires.
#'
#' @param x A matrix or a data frame.
#' @param ... Currently not used.
#' @param ci Confidence interval for the reliability estimate. If `NULL`,
#' no confidence interval is computed.
#' @inheritParams cronbachs_alpha
#'
#' @return The McDonald's Omega value for `x`.
#'
Expand Down Expand Up @@ -33,11 +34,24 @@ mcdonalds_omega <- function(x, ...) {

#' @export
mcdonalds_omega.data.frame <- function(x, ci = 0.95, verbose = TRUE, ...) {
varnames <- colnames(x)
n_params <- length(varnames)
name_loadings <- paste0("a", 1:n_params)
name_error <- paste0("b", 1:n_params)
# remove missings
.data <- stats::na.omit(x)

Check warning on line 38 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L38

Added line #L38 was not covered by tests

# we need at least two columns for Cronach's Alpha
if (is.null(ncol(.data)) || ncol(.data) < 2) {
if (verbose) {
insight::format_warning("Too few columns in `x` to compute McDonald's Omega.")

Check warning on line 43 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L41-L43

Added lines #L41 - L43 were not covered by tests
}
return(NULL)

Check warning on line 45 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L45

Added line #L45 was not covered by tests
}

# prepare names and formulas for lavaan
varnames <- colnames(.data)
name_loadings <- paste0("a", seq_len(ncol(.data)))
name_error <- paste0("b", seq_len(ncol(.data)))

Check warning on line 51 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L49-L51

Added lines #L49 - L51 were not covered by tests

# we need this specific formulation for lavaan to get the omega reliability estimate
# see code in MBESS
model <- paste0("f1 =~ NA*", varnames[1], " + ")
formula_loadings <- paste(paste0(name_loadings, "*", varnames), collapse = " + ")
formula_factors <- "f1 ~~ 1*f1\n"
Expand All @@ -60,34 +74,102 @@ mcdonalds_omega.data.frame <- function(x, ci = 0.95, verbose = TRUE, ...) {

insight::check_if_installed("lavaan")

Check warning on line 75 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L75

Added line #L75 was not covered by tests

fit <- lavaan::cfa(model, data = x, missing = "ml", estimator = "mlr", se = "default")
# fit CFA to get reliability estimate
fit <- lavaan::cfa(model, data = .data, missing = "ml", estimator = "mlr", se = "default")
out <- lavaan::parameterEstimates(fit)

Check warning on line 79 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L78-L79

Added lines #L78 - L79 were not covered by tests

# extract omega and related standard error
estimate <- as.vector(out$est[out$label == "relia"])
se <- as.vector(out$se[out$label == "relia"])

Check warning on line 83 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L82-L83

Added lines #L82 - L83 were not covered by tests

# if user requested CI, return data frame with omega and CI
if (!is.null(ci) && !is.na(ci)) {
crit <- stats::qnorm((1 + ci) / 2)

Check warning on line 87 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L86-L87

Added lines #L86 - L87 were not covered by tests

logest <- log(estimate / (1 - estimate))
logse <- se / (estimate * (1 - estimate))
loglower <- logest - crit * logse
logupper <- logest + crit * logse

Check warning on line 92 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L89-L92

Added lines #L89 - L92 were not covered by tests

if (logupper < loglower) {
temp <- loglower
loglower <- logupper
loguppper <- temp

Check warning on line 97 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L94-L97

Added lines #L94 - L97 were not covered by tests
}
ci_low <- 1 / (1 + exp(-loglower))
ci_high <- 1 / (1 + exp(-logupper))

omega <- data.frame(
Omega = estimate,
CI_low = 1 / (1 + exp(-loglower)),
CI_high = 1 / (1 + exp(-logupper)),
stringsAsFactors = FALSE

Check warning on line 104 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L100-L104

Added lines #L100 - L104 were not covered by tests
)
class(omega) <- c("mcdonalds_omega", "data.frame")

Check warning on line 106 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L106

Added line #L106 was not covered by tests
} else {
ci_low <- NA
ci_high <- NA
omega <- estimate

Check warning on line 108 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L108

Added line #L108 was not covered by tests
}

omega

Check warning on line 111 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L111

Added line #L111 was not covered by tests
}


#' @export
mcdonalds_omega.matrix <- function(x, verbose = TRUE, ...) {
mcdonalds_omega(as.data.frame(x), verbose = verbose, ...)
mcdonalds_omega.matrix <- function(x, ci = 0.95, verbose = TRUE, ...) {
mcdonalds_omega(as.data.frame(x), ci = ci, verbose = verbose, ...)

Check warning on line 117 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L117

Added line #L117 was not covered by tests
}


#' @export
mcdonalds_omega.parameters_pca <- function(x, verbose = TRUE, ...) {
# fetch data used for the PCA
pca_data <- attributes(x)$dataset

Check warning on line 124 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L124

Added line #L124 was not covered by tests

# if NULL, can we get from environment?
if (is.null(pca_data)) {
pca_data <- attr(x, "data")
if (is.null(pca_data)) {
if (verbose) {
insight::format_warning("Could not find data frame that was used for the PCA.")

Check warning on line 131 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L127-L131

Added lines #L127 - L131 were not covered by tests
}
return(NULL)

Check warning on line 133 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L133

Added line #L133 was not covered by tests
}
pca_data <- get(pca_data, envir = parent.frame())

Check warning on line 135 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L135

Added line #L135 was not covered by tests
}

# get assignment of columns to extracted components, based on the max loading
factor_assignment <- attributes(x)$closest_component

Check warning on line 139 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L139

Added line #L139 was not covered by tests

# sort and get unique IDs so we only get data from relevant columns
unique_factors <- sort(unique(factor_assignment))

Check warning on line 142 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L142

Added line #L142 was not covered by tests

# apply cronbach's alpha for each component,
# only for variables with max loading
omegas <- sapply(unique_factors, function(i) {
mcdonalds_omega(
pca_data[, as.vector(x$Variable[factor_assignment == i]), drop = FALSE],
ci = NULL,
verbose = verbose,

Check warning on line 150 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L146-L150

Added lines #L146 - L150 were not covered by tests
...
)
})

names(omegas) <- paste0("PC", unique_factors)
unlist(omegas)

Check warning on line 156 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L155-L156

Added lines #L155 - L156 were not covered by tests
}


# methods ---------------------------------------------------------------------

#' @export
print.mcdonalds_omega <- function(x, digits = 3, ...) {
# print regular R2
out <- sprintf(
"Omega: %.*f %s",
digits,
x$omega,
insight::format_ci(ci_low, ci_high, digits = digits, ci = NULL)

Check warning on line 169 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L165-L169

Added lines #L165 - L169 were not covered by tests
)

cat(out)
cat("\n")
invisible(x)

Check warning on line 174 in R/mcdonalds_omega.r

View check run for this annotation

Codecov / codecov/patch

R/mcdonalds_omega.r#L172-L174

Added lines #L172 - L174 were not covered by tests
}
3 changes: 2 additions & 1 deletion man/cronbachs_alpha.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion man/mcdonalds_omega.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ab95e73

Please sign in to comment.