1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
# Rules ---------------------------------------------------------------
#' Create an Interpretation Grid
#'
#' Create a container for interpretation rules of thumb. Usually used in conjunction with [interpret].
#'
#' @param values Vector of reference values (edges defining categories or
#' critical values).
#' @param labels Labels associated with each category. If `NULL`, will try to
#' infer it from `values` (if it is a named vector or a list), otherwise, will
#' return the breakpoints.
#' @param name Name of the set of rules (will be printed).
#' @param right logical, for threshold-type rules, indicating if the thresholds
#' themselves should be included in the interval to the right (lower values)
#' or in the interval to the left (higher values).
#'
#'
#'
#' @seealso [interpret()]
#'
#' @examples
#' rules(c(0.05), c("significant", "not significant"), right = FALSE)
#' rules(c(0.2, 0.5, 0.8), c("small", "medium", "large"))
#' rules(c("small" = 0.2, "medium" = 0.5), name = "Cohen's Rules")
#' @export
rules <- function(values, labels = NULL, name = NULL, right = TRUE) {
if (is.null(labels)) {
if (is.list(values)) {
values <- unlist(values)
}
if (is.null(names(values))) {
labels <- values
} else {
labels <- names(values)
}
}
# Sanity checks
if (length(labels) < length(values)) {
insight::format_error("There cannot be less labels than reference values!")
} else if (length(labels) > length(values) + 1) {
insight::format_error("Too many labels for the number of reference values!")
}
if (length(values) == length(labels) - 1) {
if (is.unsorted(values)) {
insight::format_error("Reference values must be sorted.")
}
} else {
right <- NULL
}
# Store and return
out <- list(
values = values,
labels = labels
)
if (is.null(name)) {
attr(out, "rule_name") <- "Custom rules"
} else {
attr(out, "rule_name") <- name
}
attr(out, "right") <- right
class(out) <- c("rules", "list")
out
}
#' @rdname rules
#' @param x An arbitrary R object.
#' @export
is.rules <- function(x) inherits(x, "rules")
# Interpret ---------------------------------------------------------------
#' Generic Function for Interpretation
#'
#' Interpret a value based on a set of rules. See [rules()].
#'
#' @param x Vector of value break points (edges defining categories), or a data
#' 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 ... Currently not used.
#' @inheritParams rules
#'
#' @return
#' - For numeric input: A character vector of interpretations.
#' - For data frames: the `x` input with an additional `Interpretation` column.
#'
#' @seealso [rules()]
#' @examples
#' rules_grid <- rules(c(0.01, 0.05), c("very significant", "significant", "not significant"))
#' interpret(0.001, rules_grid)
#' interpret(0.021, rules_grid)
#' interpret(0.08, rules_grid)
#' 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")))
#'
#' # ----------
#' d <- cohens_d(mpg ~ am, data = mtcars)
#' interpret(d, rules = "cohen1988")
#'
#' d <- glass_delta(mpg ~ am, data = mtcars)
#' interpret(d, rules = "gignac2016")
#'
#' interpret(d, rules = rules(1, c("tiny", "yeah okay")))
#'
#' m <- lm(formula = wt ~ am * cyl, data = mtcars)
#' eta2 <- eta_squared(m)
#' interpret(eta2, rules = "field2013")
#'
#' X <- chisq.test(mtcars$am, mtcars$cyl == 8)
#' interpret(oddsratio(X), rules = "chen2010")
#' interpret(cramers_v(X), "lovakov2021")
#' @export
interpret <- function(x, ...) {
UseMethod("interpret")
}
#' @rdname interpret
#' @export
interpret.numeric <- function(x, rules, name = attr(rules, "rule_name"), ...) {
if (!inherits(rules, "rules")) {
rules <- rules(rules)
}
if (is.null(name)) name <- "Custom rules"
attr(rules, "rule_name") <- name
if (length(x) > 1) {
out <- sapply(x, .interpret, rules)
} else {
out <- .interpret(x, rules)
}
names(out) <- names(x)
class(out) <- c("effectsize_interpret", class(out))
attr(out, "rules") <- rules
out
}
#' @rdname interpret
#' @export
interpret.effectsize_table <- function(x, rules, ...) {
if (missing(rules)) insight::format_error("You {.b must} specify the rules of interpretation!")
es_name <- colnames(x)[is_effectsize_name(colnames(x))]
value <- x[[es_name]]
x$Interpretation <- switch(es_name,
## std diff
Cohens_d = ,
Hedges_g = ,
Glass_delta = ,
Mahalanobis_D = interpret_cohens_d(value, rules = rules),
## xtab cor
Cramers_v = ,
Cramers_v_adjusted = ,
phi = ,
phi_adjusted = ,
Pearsons_c = ,
Cohens_w = ,
Tschuprows_t = ,
fei = interpret_cramers_v(value, rules = rules),
## xtab 2x2
Cohens_h = interpret_cohens_d(value, rules = rules),
Odds_ratio = interpret_oddsratio(value, rules = rules, log = FALSE),
log_Odds_ratio = interpret_oddsratio(value, rules = rules, log = TRUE),
# TODO:
# Risk_ratio = ,
# log_Risk_ratio = ,
## xtab dep
Cohens_g = interpret_cohens_g(value, rules = rules),
## anova
Eta2 = ,
Eta2_partial = ,
Eta2_generalized = ,
Epsilon2 = ,
Epsilon2_partial = ,
Omega2 = ,
Omega2_partial = interpret_omega_squared(value, rules = rules),
Cohens_f = ,
Cohens_f_partial = interpret_omega_squared(f_to_eta2(value), rules = rules),
Cohens_f2 = ,
Cohens_f2_partial = interpret_omega_squared(f2_to_eta2(value), rules = rules),
## Rank
r_rank_biserial = interpret_r(value, rules = rules),
VDs_A = interpret_r(value * 2 - 1, rules = rules),
Kendalls_W = interpret_kendalls_w(value, rules = rules),
rank_epsilon_squared = ,
rank_eta_squared = interpret_omega_squared(value, rules = rules),
# TODO: add cles as a transformation of d?
## other
r = interpret_r(value, rules = rules),
d = interpret_cohens_d(value, rules = rules)
)
attr(x, "rules") <- attr(x$Interpretation, "rules")
x
}
#' @keywords internal
.interpret <- function(x, rules) {
if (is.na(x)) {
return(NA)
}
if (length(rules$values) == length(rules$labels)) {
index <- which.min(abs(x - rules$values))
} else {
if (isTRUE(attr(rules, "right"))) {
check <- x <= rules$values
} else {
check <- x < rules$values
}
if (any(check)) {
index <- min(which(check))
} else {
index <- length(rules$labels)
}
}
rules$labels[index]
}
|