diff --git a/DESCRIPTION b/DESCRIPTION index fe4165f5..d07c5fba 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: effectsize Title: Indices of Effect Size -Version: 0.8.8.2 +Version: 0.8.9 Authors@R: c(person(given = "Mattan S.", family = "Ben-Shachar", @@ -72,10 +72,10 @@ Depends: R (>= 3.6) Imports: bayestestR (>= 0.13.2), - insight (>= 0.19.10), - parameters (>= 0.21.7), - performance (>= 0.11.0), - datawizard (>= 0.10.0), + insight (>= 0.20.1), + parameters (>= 0.22.0), + performance (>= 0.12.0), + datawizard (>= 0.11.0), stats, utils Suggests: @@ -112,4 +112,3 @@ Config/Needs/website: rstudio/bslib, r-lib/pkgdown, easystats/easystatstemplate -Remotes: easystats/insight, easystats/datawizard, easystats/bayestestR, easystats/parameters, easystats/performance diff --git a/NEWS.md b/NEWS.md index 07fccf60..cb8cfc07 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# effectsize 0.8.9 + +## Bug fixes + +- `interpret()` no longer returns transformed effect sizes ( #640 ) + # effectsize 0.8.8 ## Bug fixes diff --git a/R/cohens_g.R b/R/cohens_g.R index e219c210..7a66ad0c 100644 --- a/R/cohens_g.R +++ b/R/cohens_g.R @@ -76,17 +76,15 @@ cohens_g <- function(x, y = NULL, insight::format_error("'x' and 'y' must have the same number of levels (minimum 2)") } x <- table(x, y) - } else { - if ((nrow(x) < 2) || (ncol(x) != nrow(x))) { - insight::format_error("'x' must be square with at least two rows and columns") - } + } else if ((nrow(x) < 2) || (ncol(x) != nrow(x))) { + insight::format_error("'x' must be square with at least two rows and columns") } - b <- x[upper.tri(x)] - c <- t(x)[upper.tri(x)] + a <- x[upper.tri(x)] + b <- t(x)[upper.tri(x)] - P <- sum(pmax(b, c)) / (sum(b) + sum(c)) + P <- sum(pmax(a, b)) / (sum(a) + sum(b)) g <- P - 0.5 out <- data.frame(Cohens_g = g) @@ -94,7 +92,7 @@ cohens_g <- function(x, y = NULL, if (.test_ci(ci)) { out$CI <- ci - n <- sum(b) + sum(c) + n <- sum(a) + sum(b) k <- P * n res <- stats::prop.test(k, n, diff --git a/R/common_language.R b/R/common_language.R index 393c5648..39ff6443 100644 --- a/R/common_language.R +++ b/R/common_language.R @@ -369,8 +369,8 @@ wmw_odds <- function(x, y = NULL, data = NULL, y <- data[data$g == "y", "r"] .foo <- function(p) { - diff <- stats::quantile(x, probs = c(p, 1 - p)) - stats::quantile(y, probs = c(1 - p, p)) - min(abs(diff)) + difference <- stats::quantile(x, probs = c(p, 1 - p)) - stats::quantile(y, probs = c(1 - p, p)) + min(abs(difference)) } stats::optim( diff --git a/R/convert_between_odds_to_probs.R b/R/convert_between_odds_to_probs.R index 181f1d15..9eb4ae6a 100644 --- a/R/convert_between_odds_to_probs.R +++ b/R/convert_between_odds_to_probs.R @@ -78,10 +78,10 @@ probs_to_odds.data.frame <- function(probs, log = FALSE, select = NULL, exclude #' @keywords internal .odds_to_probs_df <- function(odds = NULL, probs = NULL, log = FALSE, select = NULL, exclude = NULL, ...) { # If vector - if (!is.null(odds)) { - df <- odds + if (is.null(odds)) { + mydata <- probs } else { - df <- probs + mydata <- odds } # check for formula notation, convert to character vector @@ -93,55 +93,55 @@ probs_to_odds.data.frame <- function(probs, log = FALSE, select = NULL, exclude } # Variable order - var_order <- names(df) + var_order <- names(mydata) # Keep subset - if (!is.null(select) && select %in% names(df)) { + if (!is.null(select) && select %in% names(mydata)) { select <- as.vector(select) - to_keep <- as.data.frame(df[!names(df) %in% select]) - df <- df[names(df) %in% select] + to_keep <- as.data.frame(mydata[!names(mydata) %in% select]) + mydata <- mydata[names(mydata) %in% select] } else { to_keep <- NULL } # Remove exceptions - if (!is.null(exclude) && exclude %in% names(df)) { + if (!is.null(exclude) && exclude %in% names(mydata)) { exclude <- as.vector(exclude) if (is.null(to_keep)) { - to_keep <- as.data.frame(df[exclude]) + to_keep <- as.data.frame(mydata[exclude]) } else { - to_keep <- cbind(to_keep, as.data.frame(df[exclude])) + to_keep <- cbind(to_keep, as.data.frame(mydata[exclude])) } - df <- df[!names(df) %in% exclude] + mydata <- mydata[!names(mydata) %in% exclude] } # Remove non-numerics - is_num <- vapply(df, is.numeric, logical(1)) - dfother <- df[!is_num] - dfnum <- df[is_num] + is_num <- vapply(mydata, is.numeric, logical(1)) + dfother <- mydata[!is_num] + dfnum <- mydata[is_num] # Tranform - if (!is.null(odds)) { - dfnum <- data.frame(lapply(dfnum, odds_to_probs.numeric, log = log)) - } else { + if (is.null(odds)) { dfnum <- data.frame(lapply(dfnum, probs_to_odds.numeric, log = log)) + } else { + dfnum <- data.frame(lapply(dfnum, odds_to_probs.numeric, log = log)) } # Add non-numerics if (is.null(ncol(dfother))) { - df <- dfnum + mydata <- dfnum } else { - df <- cbind(dfother, dfnum) + mydata <- cbind(dfother, dfnum) } # Add exceptions if (!is.null(select) || !is.null(exclude) && exists("to_keep")) { - df <- cbind(df, to_keep) + mydata <- cbind(mydata, to_keep) } # Reorder - df <- df[var_order] + mydata <- mydata[var_order] - return(df) + mydata } diff --git a/R/effectsize.htest.R b/R/effectsize.htest.R index a9b688c0..20586287 100644 --- a/R/effectsize.htest.R +++ b/R/effectsize.htest.R @@ -100,7 +100,7 @@ effectsize.htest <- function(model, type = NULL, verbose = TRUE, ...) { cl <- match.call() cl <- cl[-which(names(cl) == "subset")] - dots <- list(eval(cl, parent.frame())) + dots <- insight::compact_list(list(eval(cl, parent.frame()))) dots$alternative <- model$alternative dots$ci <- attr(model$conf.int, "conf.level") diff --git a/R/eta_squared-main.R b/R/eta_squared-main.R index 1587f634..3c9ec4a9 100644 --- a/R/eta_squared-main.R +++ b/R/eta_squared-main.R @@ -294,7 +294,7 @@ cohens_f <- function(model, es_name <- get_effectsize_name(colnames(res)) res[[es_name]] <- res[[es_name]] / (1 - res[[es_name]]) - if (grepl("_partial", es_name)) { + if (grepl("_partial", es_name, fixed = TRUE)) { colnames(res)[colnames(res) == es_name] <- "Cohens_f2_partial" } else { colnames(res)[colnames(res) == es_name] <- "Cohens_f2" @@ -430,7 +430,7 @@ cohens_f_squared <- function(model, # Estimate effect size --- - if (type == "eta") { + if (type == "eta") { # nolint if (isTRUE(generalized) || is.character(generalized)) { ## copied from afex obs <- logical(nrow(aov_table)) @@ -448,37 +448,36 @@ cohens_f_squared <- function(model, aov_table$Eta2_generalized <- aov_table$Sum_Squares / (aov_table$Sum_Squares + values$Sum_Squares_residuals + obs_SSn1 - obs_SSn2) - } else if (!isTRUE(partial)) { - aov_table$Eta2 <- aov_table$Sum_Squares / - values$Sum_Squares_total - } else { + } else if (isTRUE(partial)) { aov_table$Eta2_partial <- aov_table$Sum_Squares / (aov_table$Sum_Squares + values$Sum_Squares_residuals) + } else { + aov_table$Eta2 <- aov_table$Sum_Squares / values$Sum_Squares_total } } else if (type == "omega") { - if (!isTRUE(partial)) { - aov_table$Omega2 <- - (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / - (values$Sum_Squares_total + values$Mean_Square_residuals) - aov_table$Omega2 <- pmax(0, aov_table$Omega2) - } else { + if (isTRUE(partial)) { aov_table$Omega2_partial <- (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / (aov_table$Sum_Squares + (values$n - aov_table$df) * values$Mean_Square_residuals) aov_table$Omega2_partial <- pmax(0, aov_table$Omega2_partial) + } else { + aov_table$Omega2 <- + (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / + (values$Sum_Squares_total + values$Mean_Square_residuals) + aov_table$Omega2 <- pmax(0, aov_table$Omega2) } } else if (type == "epsilon") { - if (!isTRUE(partial)) { - aov_table$Epsilon2 <- - (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / - values$Sum_Squares_total - aov_table$Epsilon2 <- pmax(0, aov_table$Epsilon2) - } else { + if (isTRUE(partial)) { aov_table$Epsilon2_partial <- (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / (aov_table$Sum_Squares + values$Sum_Squares_residuals) aov_table$Epsilon2_partial <- pmax(0, aov_table$Epsilon2_partial) + } else { + aov_table$Epsilon2 <- + (aov_table$Sum_Squares - aov_table$df * values$Mean_Square_residuals) / + values$Sum_Squares_total + aov_table$Epsilon2 <- pmax(0, aov_table$Epsilon2) } } @@ -570,7 +569,7 @@ cohens_f_squared <- function(model, # Estimate effect size --- - if (type == "eta") { + if (type == "eta") { # nolint if (isTRUE(generalized) || is.character(generalized)) { ## copied from afex obs <- logical(nrow(aov_table)) @@ -589,12 +588,12 @@ cohens_f_squared <- function(model, aov_table$Eta2_generalized <- aov_table$Sum_Squares / (aov_table$Sum_Squares + sum(sapply(values, "[[", "Sum_Squares_residuals")) + obs_SSn1 - obs_SSn2) - } else if (!isTRUE(partial)) { - aov_table$Eta2 <- aov_table$Sum_Squares / Sum_Squares_total - } else { + } else if (isTRUE(partial)) { aov_table$Eta2_partial <- aov_table$Sum_Squares / (aov_table$Sum_Squares + Sum_Squares_residuals) + } else { + aov_table$Eta2 <- aov_table$Sum_Squares / Sum_Squares_total } } else if (type == "omega") { SSS_values <- values[[which(names(values) %in% DV_names)]] @@ -603,29 +602,29 @@ cohens_f_squared <- function(model, Mean_Squares_Subjects <- SSS_values$Mean_Square_residuals # implemented from https://www.jasonfinley.com/tools/OmegaSquaredQuickRef_JRF_3-31-13.pdf/ - if (!isTRUE(partial)) { - aov_table$Omega2 <- - (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / - (Sum_Squares_total + Mean_Squares_Subjects) - aov_table$Omega2 <- pmax(0, aov_table$Omega2) - } else { + if (isTRUE(partial)) { aov_table$Omega2_partial <- (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / (aov_table$Sum_Squares + is_within * Sum_Squares_residuals + Sum_Squares_Subjects + Mean_Squares_Subjects) aov_table$Omega2_partial <- pmax(0, aov_table$Omega2_partial) + } else { + aov_table$Omega2 <- + (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / + (Sum_Squares_total + Mean_Squares_Subjects) + aov_table$Omega2 <- pmax(0, aov_table$Omega2) } } else if (type == "epsilon") { - if (!isTRUE(partial)) { - aov_table$Epsilon2 <- - (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / - Sum_Squares_total - aov_table$Epsilon2 <- pmax(0, aov_table$Epsilon2) - } else { + if (isTRUE(partial)) { aov_table$Epsilon2_partial <- (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / (aov_table$Sum_Squares + Sum_Squares_residuals) aov_table$Epsilon2_partial <- pmax(0, aov_table$Epsilon2_partial) + } else { + aov_table$Epsilon2 <- + (aov_table$Sum_Squares - aov_table$df * Mean_Square_residuals) / + Sum_Squares_total + aov_table$Epsilon2 <- pmax(0, aov_table$Epsilon2) } } @@ -819,7 +818,7 @@ cohens_f_squared <- function(model, df_error = model[, df_errori], stringsAsFactors = FALSE ) - par_table <- par_table[!par_table[["Parameter"]] %in% "Residuals", ] + par_table <- par_table[par_table[["Parameter"]] != "Residuals", ] out <- .es_aov_table( @@ -833,7 +832,8 @@ cohens_f_squared <- function(model, include_intercept = include_intercept ) - attr(out, "anova_type") <- tryCatch(attr(parameters::model_parameters(model, verbose = FALSE, effects = "fixed", es_type = NULL), "anova_type"), + ## TODO: add back `effects = "fixed"` once the deprecation warning in parameters is removed + attr(out, "anova_type") <- tryCatch(attr(parameters::model_parameters(model, verbose = FALSE, es_type = NULL), "anova_type"), error = function(...) 1 ) attr(out, "approximate") <- TRUE @@ -864,7 +864,8 @@ cohens_f_squared <- function(model, # TODO this should be in .anova_es.anvoa # TODO the aoc method should convert to an anova table, then pass to anova - params <- parameters::model_parameters(model, verbose = verbose, effects = "fixed", es_type = NULL) + ## TODO: add back `effects = "fixed"` once the deprecation warning in parameters is removed + params <- parameters::model_parameters(model, verbose = verbose, es_type = NULL) out <- .es_aov_simple(as.data.frame(params), type = type, partial = partial, generalized = generalized, @@ -890,7 +891,8 @@ cohens_f_squared <- function(model, verbose = TRUE, include_intercept = FALSE, ...) { - params <- parameters::model_parameters(model, verbose = verbose, effects = "fixed", es_type = NULL) + ## TODO: add back `effects = "fixed"` once the deprecation warning in parameters is removed + params <- parameters::model_parameters(model, verbose = verbose, es_type = NULL) anova_type <- attr(params, "anova_type") params <- as.data.frame(params) @@ -944,11 +946,11 @@ cohens_f_squared <- function(model, df_residuals <- sum(params[iResid, "df"]) list( - "Mean_Square_residuals" = Mean_Square_residuals, - "Sum_Squares_residuals" = Sum_Squares_residuals, - "Sum_Squares_total" = Sum_Squares_total, - "n_terms" = N_terms, - "n" = N, - "df_residuals" = df_residuals + Mean_Square_residuals = Mean_Square_residuals, + Sum_Squares_residuals = Sum_Squares_residuals, + Sum_Squares_total = Sum_Squares_total, + n_terms = N_terms, + n = N, + df_residuals = df_residuals ) } diff --git a/R/eta_squared-methods.R b/R/eta_squared-methods.R index 50636016..944d5713 100644 --- a/R/eta_squared-methods.R +++ b/R/eta_squared-methods.R @@ -78,7 +78,9 @@ verbose = TRUE, include_intercept = FALSE, ...) { - suppressWarnings(aov_tab <- summary(model)$univariate.tests) + suppressWarnings({ + aov_tab <- summary(model)$univariate.tests + }) # if there are univariate.tests, will return a global effect size if (is.null(aov_tab)) { @@ -107,17 +109,17 @@ aov_tab <- aov_tab[c("Parameter", "Sum_Squares", "Error SS", "df", "den Df")] id <- "Subject" - within <- names(model$idata) - within <- lapply(within, function(x) c(NA, x)) - within <- do.call(expand.grid, within) - within <- apply(within, 1, stats::na.omit) - ns <- sapply(within, length) - within <- sapply(within, paste, collapse = ":") - within <- within[order(ns)] - within <- Filter(function(x) nchar(x) > 0, within) - l <- sapply(within, grepl, x = aov_tab$Parameter, simplify = TRUE) - l <- apply(l, 1, function(x) if (!any(x)) 0 else max(which(x))) - l <- c(NA, within)[l + 1] + within_subj <- names(model$idata) + within_subj <- lapply(within_subj, function(x) c(NA, x)) + within_subj <- do.call(expand.grid, within_subj) + within_subj <- apply(within_subj, 1, stats::na.omit) + ns <- lengths(within_subj) + within_subj <- sapply(within_subj, paste, collapse = ":") + within_subj <- within_subj[order(ns)] + within_subj <- Filter(function(x) nzchar(x, keepNA = TRUE), within_subj) + l <- sapply(within_subj, grepl, x = aov_tab$Parameter, simplify = TRUE) + l <- apply(l, 1, function(x) if (any(x)) max(which(x)) else 0) + l <- c(NA, within_subj)[l + 1] l <- sapply(l, function(x) paste0(stats::na.omit(c(id, x)), collapse = ":")) aov_tab$Group <- l @@ -132,10 +134,10 @@ aov_tab <- do.call(rbind, aov_tab) aov_tab[["Error SS"]] <- NULL aov_tab[["den Df"]] <- NULL - aov_tab$`F` <- ifelse(aov_tab$Parameter == "Residuals", NA, 1) + aov_tab[["F"]] <- ifelse(aov_tab$Parameter == "Residuals", NA, 1) aov_tab$Mean_Square <- aov_tab$Sum_Squares / aov_tab$df - DV_names <- c(id, setdiff(unlist(strsplit(model$terms, ":")), "(Intercept)")) + DV_names <- c(id, setdiff(unlist(strsplit(model$terms, ":", fixed = TRUE)), "(Intercept)")) out <- .es_aov_strata( @@ -172,7 +174,7 @@ out <- .anova_es(pars, ...) attr(out, "anova_type") <- attr(pars, "anova_type") attr(out, "approximate") <- TRUE - return(out) + out } @@ -255,7 +257,8 @@ ci = 0.95, alternative = "greater", verbose = TRUE, ...) { - params <- parameters::model_parameters(model, verbose = verbose, effects = "fixed", es_type = NULL) + ## TODO: add back `effects = "fixed"` once the deprecation warning in parameters is removed + params <- parameters::model_parameters(model, verbose = verbose, es_type = NULL) anova_type <- attr(params, "anova_type") params <- split(params, factor(params$Response, levels = unique(params$Response))) # make sure row order is not changed diff --git a/R/interpret.R b/R/interpret.R index 9afb4cbe..ca659ba7 100644 --- a/R/interpret.R +++ b/R/interpret.R @@ -91,6 +91,8 @@ is.rules <- function(x) inherits(x, "rules") #' frame of class `effectsize_table`. #' @param rules Set of [rules()]. When `x` is a data frame, can be a name of an #' established set of rules. +#' @param transform a function (or name of a function) to apply to `x` before +#' interpreting. See examples. #' @param ... Currently not used. #' @inheritParams rules #' @@ -109,6 +111,10 @@ is.rules <- function(x) inherits(x, "rules") #' interpret(c(0.35, 0.15), c("small" = 0.2, "large" = 0.4), name = "Cohen's Rules") #' interpret(c(0.35, 0.15), rules(c(0.2, 0.4), c("small", "medium", "large"))) #' +#' bigness <- rules(c(1, 10), c("small", "medium", "big")) +#' interpret(abs(-5), bigness) +#' interpret(-5, bigness, transform = abs) +#' #' # ---------- #' d <- cohens_d(mpg ~ am, data = mtcars) #' interpret(d, rules = "cohen1988") @@ -133,7 +139,17 @@ interpret <- function(x, ...) { #' @rdname interpret #' @export -interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"), ...) { +interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"), + transform = NULL, ...) { + # This is meant to circumvent https://github.com/easystats/report/issues/442 + if (is.character(transform)) { + transform <- match.fun(transform) + } else if (!is.function(transform)) { + transform <- identity + } + + x_tran <- transform(x) + if (!inherits(rules, "rules")) { rules <- rules(rules) } @@ -141,13 +157,13 @@ interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"), ...) { if (is.null(name)) name <- "Custom rules" attr(rules, "rule_name") <- name - if (length(x) > 1) { - out <- vapply(x, .interpret, rules = rules, FUN.VALUE = character(1L)) + if (length(x_tran) > 1) { + out <- vapply(x_tran, .interpret, rules = rules, FUN.VALUE = character(1L)) } else { - out <- .interpret(x, rules = rules) + out <- .interpret(x_tran, rules = rules) } - names(out) <- names(x) + names(out) <- names(x_tran) class(out) <- c("effectsize_interpret", class(out)) attr(out, "rules") <- rules @@ -156,11 +172,18 @@ interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"), ...) { #' @rdname interpret #' @export -interpret.effectsize_table <- function(x, rules, ...) { +interpret.effectsize_table <- function(x, rules, transform = NULL, ...) { if (missing(rules)) insight::format_error("You {.b must} specify the rules of interpretation!") + # This is meant to circumvent https://github.com/easystats/report/issues/442 + if (is.character(transform)) { + transform <- match.fun(transform) + } else if (!is.function(transform)) { + transform <- identity + } + es_name <- colnames(x)[is_effectsize_name(colnames(x))] - value <- x[[es_name]] + value <- transform(x[[es_name]]) x$Interpretation <- switch(es_name, ## std diff diff --git a/R/interpret_bf.R b/R/interpret_bf.R index 47e146af..f420dd51 100644 --- a/R/interpret_bf.R +++ b/R/interpret_bf.R @@ -30,7 +30,7 @@ #' #' @examples #' interpret_bf(1) -#' interpret_bf(c(5, 2)) +#' interpret_bf(c(5, 2, 0.01)) #' #' @references #' - Jeffreys, H. (1961), Theory of Probability, 3rd ed., Oxford University @@ -50,21 +50,13 @@ interpret_bf <- function(bf, include_value = FALSE, protect_ratio = TRUE, exact = TRUE) { - if (log) bf <- exp(bf) - - if (any(bf < 0, na.rm = TRUE)) { - insight::format_warning("Negative BFs detected. These are not possible, and are {.i ignored}.") - bf[bf < 0] <- NA + if (!log && any(bf < 0, na.rm = TRUE)) { + insight::format_error("Negative BFs detected. These are not possible, and are {.i ignored}.") } - orig_bf <- bf - - dir <- rep("against or in favour of", length.out = length(bf)) - dir <- replace(dir, is.na(bf), NA_character_) - dir <- replace(dir, bf < 1, "against") - dir <- replace(dir, bf > 1, "in favour of") - bf <- exp(abs(log(bf))) + if (!log) bf <- log(bf) + # interpret strength rules <- .match.rules( rules, list( @@ -77,27 +69,23 @@ interpret_bf <- function(bf, ) ) - interpretation <- interpret(bf, rules) + interpretation <- interpret(bf, rules, transform = function(.x) exp(abs(.x))) + interpretation[bf == 0] <- "no" - # Format text - interpretation[] <- paste0(interpretation, " evidence") - interpretation[orig_bf == 1] <- "no evidence" + # interpret direction + dir <- interpret(bf, rules(0, c("against", "in favour of"))) + dir[bf == 0] <- "against or in favour of" - # Add value if asked for + # Format text if (include_value) { - interpretation[] <- - paste0( - interpretation, - " (", - insight::format_bf(orig_bf, protect_ratio = protect_ratio, exact = exact), - ")" - ) + bf_fmt <- insight::format_bf(exp(bf), protect_ratio = protect_ratio, exact = exact) + interpretation[] <- sprintf("%s evidence (%s) %s", interpretation, bf_fmt, dir) + } else { + interpretation[] <- paste0(interpretation, " evidence ", dir) } - # Add direction - interpretation[] <- paste(interpretation[], dir) - - interpretation[is.na(orig_bf)] <- "" + interpretation[is.na(bf)] <- "" + interpretation[] <- trimws(interpretation, "right") interpretation } diff --git a/R/interpret_cohens_d.R b/R/interpret_cohens_d.R index def2aaaf..a87243db 100644 --- a/R/interpret_cohens_d.R +++ b/R/interpret_cohens_d.R @@ -81,7 +81,7 @@ interpret_cohens_d <- function(d, rules = "cohen1988", ...) { ) ) - interpret(abs(d), rules) + interpret(d, rules, transform = abs) } #' @rdname interpret_cohens_d diff --git a/R/interpret_cohens_g.R b/R/interpret_cohens_g.R index fc10230c..3c1418a0 100644 --- a/R/interpret_cohens_g.R +++ b/R/interpret_cohens_g.R @@ -42,5 +42,5 @@ interpret_cohens_g <- function(g, rules = "cohen1988", ...) { ) ) - interpret(abs(g), rules) + interpret(g, rules, transform = abs) } diff --git a/R/interpret_ess_rhat.R b/R/interpret_ess_rhat.R index 003a7c5c..9207b4fe 100644 --- a/R/interpret_ess_rhat.R +++ b/R/interpret_ess_rhat.R @@ -45,11 +45,11 @@ interpret_ess <- function(ess, rules = "burkner2017") { rules <- .match.rules( rules, list( - burkner2017 = rules(c(1000), c("insufficient", "sufficient"), name = "burkner2017", right = FALSE) + burkner2017 = rules(1000, c("insufficient", "sufficient"), name = "burkner2017", right = FALSE) ) ) - interpret(abs(ess), rules) + interpret(ess, rules) } @@ -60,10 +60,10 @@ interpret_rhat <- function(rhat, rules = "vehtari2019") { rules <- .match.rules( rules, list( - vehtari2019 = rules(c(1.01), c("converged", "failed"), name = "vehtari2019"), - gelman1992 = rules(c(1.1), c("converged", "failed"), name = "gelman1992") + vehtari2019 = rules(1.01, c("converged", "failed"), name = "vehtari2019"), + gelman1992 = rules(1.1, c("converged", "failed"), name = "gelman1992") ) ) - interpret(abs(rhat), rules) + interpret(rhat, rules) } diff --git a/R/interpret_oddsratio.R b/R/interpret_oddsratio.R index c3f09b75..0d4851c4 100644 --- a/R/interpret_oddsratio.R +++ b/R/interpret_oddsratio.R @@ -42,15 +42,15 @@ #' @export interpret_oddsratio <- function(OR, rules = "chen2010", log = FALSE, ...) { if (log) { - OR <- exp(abs(OR)) + f_transform <- function(.x) exp(abs(.x)) } else { - OR <- exp(abs(log(OR))) + f_transform <- function(.x) exp(abs(log(.x))) } if (is.character(rules) && rules == "cohen1988") { - d <- oddsratio_to_d(OR, log = FALSE) - return(interpret_cohens_d(abs(d), rules = rules)) + d <- oddsratio_to_d(OR, log = log) + return(interpret_cohens_d(d, rules = rules)) } rules <- .match.rules( @@ -63,5 +63,5 @@ interpret_oddsratio <- function(OR, rules = "chen2010", log = FALSE, ...) { ) ) - interpret(OR, rules) + interpret(OR, rules, transform = f_transform) } diff --git a/R/interpret_p.R b/R/interpret_p.R index 9ea34325..9f1b7c73 100644 --- a/R/interpret_p.R +++ b/R/interpret_p.R @@ -21,6 +21,11 @@ #' interpret_p(c(.5, .02, 0.001)) #' interpret_p(c(.5, .02, 0.001), rules = "rss") #' +#' stars <- rules(c(0.001, 0.01, 0.05, 0.1), c("***", "**", "*", "+", ""), +#' right = FALSE, name = "stars" +#' ) +#' interpret_p(c(.5, .02, 0.001), rules = stars) +#' #' @keywords interpreters #' @export interpret_p <- function(p, rules = "default") { diff --git a/R/interpret_pd.R b/R/interpret_pd.R index 711b9ef6..305a138a 100644 --- a/R/interpret_pd.R +++ b/R/interpret_pd.R @@ -30,7 +30,7 @@ interpret_pd <- function(pd, rules = "default", ...) { rules <- .match.rules( rules, list( - default = rules(c(0.975), c("not significant", "significant"), + default = rules(0.975, c("not significant", "significant"), name = "default", right = TRUE ), makowski2019 = rules(c(0.95, 0.97, 0.99, 0.999), c("uncertain", "possibly existing", "likely existing", "probably existing", "certainly existing"), diff --git a/R/interpret_r.R b/R/interpret_r.R index 158259fd..bc3bbe24 100644 --- a/R/interpret_r.R +++ b/R/interpret_r.R @@ -106,7 +106,7 @@ interpret_r <- function(r, rules = "funder2019", ...) { ) ) - interpret(abs(r), rules) + interpret(r, rules, transform = abs) } #' @export diff --git a/R/interpret_r2.R b/R/interpret_r2.R index c294a0cc..f8cb9ea0 100644 --- a/R/interpret_r2.R +++ b/R/interpret_r2.R @@ -55,7 +55,7 @@ interpret_r2 <- function(r2, rules = "cohen1988") { cohen1988 = rules(c(0.02, 0.13, 0.26), c("very weak", "weak", "moderate", "substantial"), name = "cohen1988", right = FALSE ), - falk1992 = rules(c(0.10), c("negligible", "adequate"), + falk1992 = rules(0.10, c("negligible", "adequate"), name = "falk1992", right = FALSE ), chin1998 = rules(c(0.19, 0.33, 0.67), c("very weak", "weak", "moderate", "substantial"), diff --git a/R/rank_ANOVA.R b/R/rank_ANOVA.R index ff3c431f..3e8e3fa2 100644 --- a/R/rank_ANOVA.R +++ b/R/rank_ANOVA.R @@ -226,7 +226,7 @@ kendalls_w <- function(x, groups, blocks, data = NULL, .reta <- function(data) { model <- suppressWarnings(stats::kruskal.test(data$x, data$groups)) - k <- length(levels(data$groups)) + k <- nlevels(data$groups) n <- nrow(data) E <- model$statistic @@ -244,7 +244,10 @@ kendalls_w <- function(x, groups, blocks, data = NULL, R <- colSums(rankings) no_ties <- apply(rankings, 1, function(x) length(x) == insight::n_unique(x)) - if (!all(no_ties)) { + if (all(no_ties)) { + S <- stats::var(R) * (n - 1) + W <- (12 * S) / (m^2 * (n^3 - n)) + } else { if (verbose) { insight::format_warning( sprintf( @@ -264,10 +267,6 @@ kendalls_w <- function(x, groups, blocks, data = NULL, W <- (12 * sum(R^2) - 3 * (m^2) * n * ((n + 1)^2)) / (m^2 * (n^3 - n) - m * Tj) - } else { - S <- stats::var(R) * (n - 1) - W <- (12 * S) / - (m^2 * (n^3 - n)) } W } diff --git a/R/rank_diff.R b/R/rank_diff.R index 33c12e5e..c165da05 100644 --- a/R/rank_diff.R +++ b/R/rank_diff.R @@ -156,7 +156,7 @@ rank_biserial <- function(x, y = NULL, data = NULL, alpha <- 1 - ci.level - rf <- atanh(r_rbs) + rank_f <- atanh(r_rbs) if (is_paired_or_onesample) { nd <- sum((x - mu) != 0) maxw <- (nd^2 + nd) / 2 @@ -185,9 +185,9 @@ rank_biserial <- function(x, y = NULL, data = NULL, rfSE <- sqrt((n1 + n2 + 1) / (3 * n1 * n2)) } - confint <- tanh(rf + c(-1, 1) * stats::qnorm(1 - alpha / 2) * rfSE) - out$CI_low <- confint[1] - out$CI_high <- confint[2] + conf_int <- tanh(rank_f + c(-1, 1) * stats::qnorm(1 - alpha / 2) * rfSE) + out$CI_low <- conf_int[1] + out$CI_high <- conf_int[2] ci_method <- list(method = "normal") out <- .limit_ci(out, alternative, -1, 1) } else { diff --git a/R/repeated_measures_d.R b/R/repeated_measures_d.R index 6db41967..56e9aebd 100644 --- a/R/repeated_measures_d.R +++ b/R/repeated_measures_d.R @@ -185,9 +185,9 @@ repeated_measures_d <- function(x, y, probs <- c(alpha / 2, 1 - alpha / 2) qs <- stats::qnorm(probs) - confint <- out[["d"]] + qs * values[["se"]] - out$CI_low <- confint[1] - out$CI_high <- confint[2] + conf_int <- out[["d"]] + qs * values[["se"]] + out$CI_low <- conf_int[1] + out$CI_high <- conf_int[2] ci_method <- list(method = "normal") out <- .limit_ci(out, alternative, -Inf, Inf) @@ -231,11 +231,11 @@ rm_d <- repeated_measures_d m <- mean(x - y) n <- length(x) - df <- n - 1 + dof <- n - 1 r <- stats::cor(x, y) f <- 2 * (1 - r) - if (method == "rm") { + if (method == "rm") { # nolint s <- stats::sd(x - y) / sqrt(f) d <- (m - mu) / s @@ -261,7 +261,7 @@ rm_d <- repeated_measures_d se <- sqrt(f / n + (d^2) / (2 * n)) } - .nlist(d, se, df) + .nlist(d, se, df = dof) } #' @keywords internal diff --git a/R/utils.R b/R/utils.R index 4e64489f..b5a2e247 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,5 +1,5 @@ #' @keywords internal -".someattributes<-" <- function(x, value) { +`.someattributes<-` <- function(x, value) { for (a in names(value)) { attr(x, a) <- value[[a]] } diff --git a/R/utils_ci.R b/R/utils_ci.R index 9f36db72..ff36d0d1 100644 --- a/R/utils_ci.R +++ b/R/utils_ci.R @@ -1,7 +1,5 @@ # NCP ------------------------- -# TODO: other packages like lmeInfo, MOTE and others use qt/qf for these. - #' @keywords internal .get_ncp_F <- function(f, df, df_error, conf.level = 0.9) { if (!is.finite(f) || !is.finite(df) || !is.finite(df_error)) { @@ -15,8 +13,8 @@ ncp <- suppressWarnings(stats::optim( par = 1.1 * rep(lambda, 2), fn = function(x) { - q <- stats::qf(p = probs, df, df_error, ncp = x) - sum(abs(q - f)) + quan <- stats::qf(p = probs, df, df_error, ncp = x) + sum(abs(quan - f)) }, control = list(abstol = 1e-09) )) @@ -45,8 +43,8 @@ ncp <- suppressWarnings(stats::optim( par = 1.1 * rep(t, 2), fn = function(x) { - q <- stats::qt(p = probs, df = df_error, ncp = x) - sum(abs(q - t)) + quan <- stats::qt(p = probs, df = df_error, ncp = x) + sum(abs(quan - t)) }, control = list(abstol = 1e-09) )) @@ -68,8 +66,8 @@ ncp <- suppressWarnings(stats::optim( par = 1.1 * rep(chisq, 2), fn = function(x) { - q <- stats::qchisq(p = probs, df, ncp = x) - sum(abs(q - chisq)) + quan <- stats::qchisq(p = probs, df, ncp = x) + sum(abs(quan - chisq)) }, control = list(abstol = 1e-09) )) @@ -100,7 +98,7 @@ ci > 1) { insight::format_error("ci must be a single numeric value between (0, 1)") } - return(TRUE) + TRUE } #' @keywords internal diff --git a/R/utils_interpret.R b/R/utils_interpret.R index 4633b85b..1cb25131 100644 --- a/R/utils_interpret.R +++ b/R/utils_interpret.R @@ -15,5 +15,5 @@ ) } - return(choices[[rule]]) + choices[[rule]] } diff --git a/R/utils_validate_input_data.R b/R/utils_validate_input_data.R index 089d702a..43f37c7b 100644 --- a/R/utils_validate_input_data.R +++ b/R/utils_validate_input_data.R @@ -254,8 +254,7 @@ wide = TRUE, allow_ordered = FALSE, verbose = TRUE, ...) { if (inherits(x, "formula")) { - if (length(x) != 3L || - x[[3L]][[1L]] != as.name("|")) { + if (length(x) != 3L || x[[3L]][[1L]] != as.name("|")) { insight::format_error("Formula must have the 'x ~ groups | blocks'.") } @@ -323,7 +322,7 @@ verbose = TRUE, ...) { if (inherits(x, "formula")) { if (length(x) != 3L || length(x[[3]]) != 1L) { - insight::format_error("Formula must have the form of 'DV1 + ... + DVk ~ group', with exactly one term on the RHS.") + insight::format_error("Formula must have the form of 'DV1 + ... + DVk ~ group', with exactly one term on the RHS.") # nolint } data <- .resolve_formula(stats::reformulate(as.character(x)[3:2]), data, ...) diff --git a/cran-comments.md b/cran-comments.md index 1e4601ce..58f71cf0 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -8,9 +8,9 @@ * local installation: R 4.3.2 on Windows * GitHub Actions - - Windows: release + - Windows: release, oldrel - macOS: release - - ubuntu-18.04: release, oldrel, 4.0, 3.6 + - ubuntu-18.04: release, oldrel, 4.3 * win-builder: release @@ -21,7 +21,7 @@ ## revdepcheck results -We checked 20 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. +We checked 23 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. * We saw 0 new problems * We failed to check 0 packages diff --git a/data-raw/df data.R b/data-raw/df data.R index 56bb5411..3b41e648 100644 --- a/data-raw/df data.R +++ b/data-raw/df data.R @@ -16,7 +16,7 @@ screening_test <- data.frame( Test1 = rep(screening_test[[1]], times = screening_test$Freq), Test2 = rep(screening_test[[2]], times = screening_test$Freq) ) -i <- sample(1600, size = 800) +i <- sample.int(1600, size = 800) screening_test$Diagnosis[i] <- screening_test$Test1[i] screening_test$Diagnosis[-i] <- screening_test$Test2[-i] screening_test$Diagnosis <- factor(screening_test$Diagnosis, labels = c("Neg", "Pos")) diff --git a/man/interpret.Rd b/man/interpret.Rd index 556f943a..c831620e 100644 --- a/man/interpret.Rd +++ b/man/interpret.Rd @@ -8,9 +8,9 @@ \usage{ interpret(x, ...) -\method{interpret}{numeric}(x, rules, name = attr(rules, "rule_name"), ...) +\method{interpret}{numeric}(x, rules, name = attr(rules, "rule_name"), transform = NULL, ...) -\method{interpret}{effectsize_table}(x, rules, ...) +\method{interpret}{effectsize_table}(x, rules, transform = NULL, ...) } \arguments{ \item{x}{Vector of value break points (edges defining categories), or a data @@ -22,6 +22,9 @@ frame of class \code{effectsize_table}.} established set of rules.} \item{name}{Name of the set of rules (will be printed).} + +\item{transform}{a function (or name of a function) to apply to \code{x} before +interpreting. See examples.} } \value{ \itemize{ @@ -42,6 +45,10 @@ interpret(c(0.01, 0.005, 0.08), rules_grid) interpret(c(0.35, 0.15), c("small" = 0.2, "large" = 0.4), name = "Cohen's Rules") interpret(c(0.35, 0.15), rules(c(0.2, 0.4), c("small", "medium", "large"))) +bigness <- rules(c(1, 10), c("small", "medium", "big")) +interpret(abs(-5), bigness) +interpret(-5, bigness, transform = abs) + # ---------- d <- cohens_d(mpg ~ am, data = mtcars) interpret(d, rules = "cohen1988") diff --git a/man/interpret_bf.Rd b/man/interpret_bf.Rd index c547e40c..bd05bcec 100644 --- a/man/interpret_bf.Rd +++ b/man/interpret_bf.Rd @@ -62,7 +62,7 @@ Rules apply to BF as ratios, so BF of 10 is as extreme as a BF of 0.1 (1/10). \examples{ interpret_bf(1) -interpret_bf(c(5, 2)) +interpret_bf(c(5, 2, 0.01)) } \references{ diff --git a/man/interpret_p.Rd b/man/interpret_p.Rd index a8a79354..6810d38c 100644 --- a/man/interpret_p.Rd +++ b/man/interpret_p.Rd @@ -36,6 +36,11 @@ Interpret \emph{p}-Values interpret_p(c(.5, .02, 0.001)) interpret_p(c(.5, .02, 0.001), rules = "rss") +stars <- rules(c(0.001, 0.01, 0.05, 0.1), c("***", "**", "*", "+", ""), + right = FALSE, name = "stars" +) +interpret_p(c(.5, .02, 0.001), rules = stars) + } \references{ \itemize{ diff --git a/tests/testthat/test-interpret.R b/tests/testthat/test-interpret.R index ad947c84..31433fc9 100644 --- a/tests/testthat/test-interpret.R +++ b/tests/testthat/test-interpret.R @@ -92,7 +92,7 @@ test_that("interpret_r2", { test_that("interpret_bf", { - expect_warning(interpret_bf(-2), "Negative") + expect_error(interpret_bf(-2), "Negative") expect_equal(interpret_bf(1)[1], "no evidence against or in favour of") expect_equal( interpret_bf(c(0.8, 3.5), "jeffreys1961")[1:2], @@ -252,4 +252,13 @@ test_that("interpret effectsize_table", { expect_output(print(V_), "Interpretation rule: funder2019") expect_error(interpret(d), "must specify") + + d1 <- cohens_d(mtcars$wt, mu = 4) + d2 <- cohens_d(-mtcars$wt, mu = -4) + d1_ <- interpret(d1, rules = "cohen1988") + d2_ <- interpret(d2, rules = "cohen1988") + + expect_equal(d1_$Interpretation, d2_$Interpretation) + expect_equal(d1_[[1]], d1[[1]]) + expect_equal(d2_[[1]], d2[[1]]) })