Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename normalized_chi() to fei() #475

Merged
merged 14 commits into from
Sep 12, 2022
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export(F_to_omega2)
export(F_to_r)
export(chisq_to_cohens_w)
export(chisq_to_cramers_v)
export(chisq_to_fei)
export(chisq_to_normalized)
export(chisq_to_pearsons_c)
export(chisq_to_phi)
Expand Down Expand Up @@ -93,6 +94,7 @@ export(eta_squared)
export(eta_squared_posterior)
export(f2_to_eta2)
export(f_to_eta2)
export(fei)
export(format_standardize)
export(get_effectsize_label)
export(get_effectsize_name)
Expand Down
5 changes: 4 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

# effectsize 0.7.0.9999

## Breaking Changes

- `normalized_chi()` has been renamed `fei()`.

## Bug fixes

- Effect sizes for goodness-of-fit now work when passing a `p` that is a table.
Expand Down
23 changes: 12 additions & 11 deletions R/convert_stat_chisq.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#' Conversion Chi-Squared to Phi or Cramer's V
#'
#' Convert between Chi square (\eqn{\chi^2}), Cramer's V, phi (\eqn{\phi}),
#' Cohen's *w*, normalized Chi (\eqn{\chi}) and Pearson's *C* for contingency
#' tables or goodness of fit.
#' Convert between Chi square (\eqn{\chi^2}), phi (\eqn{\phi}), Cramer's V,
#' Cohen's *w*, Fei (\u05e4) and Pearson's *C* for contingency tables or
#' goodness of fit.
#'
#'
#' @param chisq The Chi-squared statistic.
#' @param n Total sample size.
Expand All @@ -21,14 +22,14 @@
#'
#' @details These functions use the following formulae:
#' \cr
#' \deqn{\phi = \sqrt{\chi^2 / n}}{phi = sqrt(\chi^2 / n)}
#' \deqn{\phi = w = \sqrt{\chi^2 / n}}{phi = w = sqrt(\chi^2 / n)}
#' \cr
#' \deqn{Cramer's V = \phi / \sqrt{min(nrow,ncol)-1}}{Cramer's V = \phi / sqrt(min(nrow,ncol)-1)}
#' \deqn{\text{Cramer's }V = \phi / \sqrt{min(nrow,ncol)-1}}{Cramer's V = \phi / sqrt(min(nrow,ncol)-1)}
#' \cr
#' \deqn{Pearson's C = \sqrt{\chi^2 / (\chi^2 + n)}}{Pearson's C = sqrt(\chi^2 / (\chi^2 + n))}
#' \deqn{Fei = w / \sqrt{\frac{1}{min(p_E)}-1}}{Fei = w / sqrt(1/min(p_E) - 1))}
#' Where `p_E` are the expected probabilities.
#' \cr
#' \deqn{\chi_{Normalized} = w \times \sqrt{\frac{q}{1-q}}}{Chi (Normalized) = w * sqrt(q/(1-q))}
#' Where `q` is the smallest of the expected probabilities.
#' \deqn{\text{Pearson's }C = \sqrt{\chi^2 / (\chi^2 + n)}}{Pearson's C = sqrt(\chi^2 / (\chi^2 + n))}
#' \cr\cr
#' For adjusted versions of *phi* and *V*, see Bergsma, 2013.
#'
Expand Down Expand Up @@ -65,7 +66,7 @@
#' #> data: Smoking_ASD
#' #> X-squared = 7.8521, df = 2, p-value = 0.01972
#'
#' chisq_to_normalized(
#' chisq_to_fei(
#' 7.8521,
#' n = sum(Smoking_ASD),
#' nrow = 1,
Expand Down Expand Up @@ -229,7 +230,7 @@ chisq_to_cramers_v <- function(chisq, n, nrow, ncol, ci = 0.95, alternative = "g
#' @rdname chisq_to_phi
#' @export
#' @param p Vector of expected values. See [stats::chisq.test()].
chisq_to_normalized <- function(chisq, n, nrow, ncol, p,
chisq_to_fei <- function(chisq, n, nrow, ncol, p,
ci = 0.95, alternative = "greater", ...) {
if (is.numeric(ci) || (!missing(nrow) && !missing(ncol))) {
# This means that the user passed ncol/nrow
Expand All @@ -255,7 +256,7 @@ chisq_to_normalized <- function(chisq, n, nrow, ncol, p,
N <- n * (1 - q) / q

res <- chisq_to_phi(chisq, N, nrow, ncol, ci = ci, alternative = alternative, adjust = FALSE, dont_stop = TRUE)
colnames(res)[1] <- "normalized_chi"
colnames(res)[1] <- "Fei"

if ("CI" %in% colnames(res)) {
if ((alternative <- attr(res, "alternative")) == "less") {
Expand Down
2 changes: 1 addition & 1 deletion R/effectsize.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#' - For an object of class `htest`, data is extracted via [insight::get_data()], and passed to the relevant function according to:
#' - A **t-test** depending on `type`: `"cohens_d"` (default), `"hedges_g"`, or `"cles"`.
#' - A **Chi-squared tests of independence**, depending on `type`: `"cramers_v"` (default), `"phi"`, `"cohens_w"`, `"pearsons_c"`, `"cohens_h"`, `"oddsratio"`, or `"riskratio"`.
#' - A **Chi-squared tests of goodness-of-fit**, depending on `type`: `"normalized_chi"` (default) `"cohens_w"`, `"pearsons_c"`
#' - A **Chi-squared tests of goodness-of-fit**, depending on `type`: `"fei"` (default) `"cohens_w"`, `"pearsons_c"`
#' - A **One-way ANOVA test**, depending on `type`: `"eta"` (default), `"omega"` or `"epsilon"` -squared, `"f"`, or `"f2"`.
#' - A **McNemar test** returns *Cohen's g*.
#' - A **Wilcoxon test** depending on `type`: returns "`rank_biserial`" correlation (default) or `"cles"`.
Expand Down
9 changes: 5 additions & 4 deletions R/effectsize.htest.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ effectsize.htest <- function(model, type = NULL, verbose = TRUE, ...) {

if (is.null(type)) {
if (nr == 1 || nc == 1) {
type <- "normalized_chi"
type <- "fei"
} else {
type <- "cramers_v"
}
}

if (grepl("(c|v|w|phi)$", tolower(type)) || tolower(type) %in% c("normalized_chi", "chi")) {
if (tolower(type) %in% c("normalized_chi", "chi")) {
if (grepl("(c|v|w|phi|fei)$", tolower(type))) {
if (tolower(type) == "fei") {
p <- Exp
} else {
p <- NULL
Expand All @@ -136,7 +136,8 @@ effectsize.htest <- function(model, type = NULL, verbose = TRUE, ...) {
c = ,
pearsons_c = chisq_to_pearsons_c,
chi = ,
normalized_chi = chisq_to_normalized
normalized_chi = ,
fei = chisq_to_fei
)

out <- f(
Expand Down
1 change: 1 addition & 0 deletions R/interpret.R
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ interpret.effectsize_table <- function(x, rules, ...) {
Cramers_v = ,
Cramers_v_adjusted = ,
normalized_chi = ,
fei = ,
Cohens_w = ,
phi = ,
phi_adjusted = interpret_cramers_v(value, rules = rules),
Expand Down
2 changes: 1 addition & 1 deletion R/is_effectsize_name.R
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ es_info <- matrix(
"phi_adjusted", "Phi (adj.)", "onetail", 0, 1, 0,
"Pearsons_c", "Pearson's C", "onetail", 0, 1, 0,
"Cohens_w", "Cohen's w", "onetail", 0, Inf, 0,
"normalized_chi", "Norm. Chi", "onetail", 0, 1, 0,
"Fei", "Fei", "onetail", 0, 1, 0,
"Cohens_g", "Cohen's g", "onetail", -0.5, 0.5, 0,
"Cohens_h", "Cohen's h", "twotail", -pi, pi, 0,
"Odds_ratio", "Odds ratio", "twotail", 0, Inf, 1,
Expand Down
81 changes: 42 additions & 39 deletions R/xtab.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#' Effect size for contingency tables
#'
#' Compute Cramer's *V*, phi (\eqn{\phi}), Cohen's *w*, normalized Chi
#' (\eqn{\chi}), Pearson's contingency coefficient, Odds ratios, Risk ratios,
#' Cohen's *h* and Cohen's *g* for contingency tables or goodness-of-fit. See
#' details.
#' Compute Cramer's *V*, phi (\eqn{\phi}), Cohen's *w*, Fei (\eqn{XXX}), Pearson's
#' contingency coefficient, Odds ratios, Risk ratios, Cohen's *h* and Cohen's
#' *g* for contingency tables or goodness-of-fit. See details.
#'
#' @inheritParams stats::chisq.test
#' @param ci Confidence Interval (CI) level
Expand All @@ -14,8 +13,8 @@
#' Partial matching is allowed (e.g., `"g"`, `"l"`, `"two"`...). See
#' *One-Sided CIs* in [effectsize_CIs].
#' @param adjust Should the effect size be bias-corrected? Defaults to `FALSE`.
#' @param ... Arguments passed to [stats::chisq.test()], such as `p` for
#' goodness-of-fit. Ignored for `cohens_g()`.
#' @param ... For goodness-of-fit effect sizes, can pass `rescale.p` (see
#' [stats::chisq.test()]). Else, ignored.
#'
#' @details
#'
Expand All @@ -30,17 +29,17 @@
#' can also be used, but since it is not bounded at 1 (can be larger) its
#' interpretation is more difficult.
#' \cr \cr
#' For goodness-of-fit in 1D tables Cohen's *W*, normalized Chi (\eqn{\chi}) or
#' Pearson's *C* can be used. Cohen's *w* has no upper bound (can be arbitrarily
#' large, depending on the expected distribution). Normalized Chi is an adjusted
#' Cohen's *w*, accounting for the expected distribution, making it bounded
#' between 0-1. Pearson's *C* is also bounded between 0-1.
#' For goodness-of-fit in 1D tables Cohen's *W*, Fei (\eqn{XXX}) or Pearson's *C*
#' can be used. Cohen's *w* has no upper bound (can be arbitrarily large,
#' depending on the expected distribution). Fei is an adjusted Cohen's *w*,
#' accounting for the expected distribution, making it bounded between 0-1.
#' Pearson's *C* is also bounded between 0-1.
#' \cr \cr
#' To summarize, for correlation-like effect sizes, we recommend:
#'
#' - For a 2x2 table, use `phi()`
#' - For larger tables, use `cramers_v()`
#' - For goodness-of-fit, use `normalized_chi()`
#' - For goodness-of-fit, use `fei()`
#'
#' ## Other Effect Sizes for 2-by-2 xtabs
#'
Expand Down Expand Up @@ -69,15 +68,15 @@
#' \cr \cr
#' See *Confidence (Compatibility) Intervals (CIs)*, *CIs and Significance Tests*,
#' and *One-Sided CIs* sections for *phi*, Cohen's *w*, Cramer's *V*,
#' Pearson's *C*, and normalized Chi.
#' Pearson's *C*, and *Fei*.
#'
#' @inheritSection effectsize_CIs Confidence (Compatibility) Intervals (CIs)
#' @inheritSection effectsize_CIs CIs and Significance Tests
#'
#' @return A data frame with the effect size (`Cramers_v`, `phi` (possibly with
#' the suffix `_adjusted`), `Cohens_w`, `normalized_chi`, `Odds_ratio`,
#' `Risk_ratio` (possibly with the prefix `log_`), `Cohens_h`, or `Cohens_g`)
#' and its CIs (`CI_low` and `CI_high`).
#' the suffix `_adjusted`), `Cohens_w`, `Fei`, `Odds_ratio`, `Risk_ratio`
#' (possibly with the prefix `log_`), `Cohens_h`, or `Cohens_g`) and its CIs
#' (`CI_low` and `CI_high`).
#'
#' @seealso [chisq_to_phi()] for details regarding estimation and CIs.
#' @family effect size indices
Expand Down Expand Up @@ -141,14 +140,14 @@
#'
#' Smoking_ASD <- as.table(c(ASD = 17, ASP = 11, TD = 640))
#'
#' normalized_chi(Smoking_ASD)
#' fei(Smoking_ASD)
#'
#' cohens_w(Smoking_ASD)
#'
#' pearsons_c(Smoking_ASD)
#'
#' # Use custom expected values:
#' normalized_chi(Smoking_ASD, p = c(0.015, 0.010, 0.975))
#' fei(Smoking_ASD, p = c(0.015, 0.010, 0.975))
#'
#' cohens_w(Smoking_ASD, p = c(0.015, 0.010, 0.975))
#'
Expand Down Expand Up @@ -205,50 +204,52 @@ phi <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust = FALSE,
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
} else {
x <- suppressWarnings(stats::chisq.test(x, y, ...))
x <- suppressWarnings(stats::chisq.test(x, y))
x$data.name <- NULL
}

effectsize(x, type = "phi", adjust = adjust, ci = ci, alternative = alternative)
}

#' @rdname phi
#' @importFrom stats chisq.test
#' @export
cohens_w <- function(x, y = NULL, ci = 0.95, alternative = "greater", ...) {
cramers_v <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust = FALSE, ...) {
alternative <- match.arg(alternative, c("greater", "two.sided", "less"))

if (inherits(x, "BFBayesFactor")) {
if (!inherits(x@numerator[[1]], "BFcontingencyTable")) {
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
return(effectsize(x, type = "phi", ci = ci, ...))
return(effectsize(x, type = "cramers_v", adjust = adjust, ci = ci, ...))
}


if (inherits(x, "htest")) {
if (!(grepl("Pearson's Chi-squared", x$method) ||
grepl("Chi-squared test for given probabilities", x$method))) {
grepl("Chi-squared test for given probabilities", x$method))) {
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
} else {
x <- suppressWarnings(stats::chisq.test(x, y, ...))
x <- suppressWarnings(stats::chisq.test(x, y))
x$data.name <- NULL
}

effectsize(x, type = "cohens_w", ci = ci, alternative = alternative)
effectsize(x, type = "cramers_v", adjust = adjust, ci = ci, alternative = alternative)
}

#' @rdname phi
#' @importFrom stats chisq.test
#' @export
cramers_v <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust = FALSE, ...) {
cohens_w <- function(x, y = NULL, p = rep(1/length(x), length(x)),
ci = 0.95, alternative = "greater", ...) {
alternative <- match.arg(alternative, c("greater", "two.sided", "less"))

if (inherits(x, "BFBayesFactor")) {
if (!inherits(x@numerator[[1]], "BFcontingencyTable")) {
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
return(effectsize(x, type = "cramers_v", adjust = adjust, ci = ci, ...))
return(effectsize(x, type = "phi", ci = ci, ...))
}


Expand All @@ -258,21 +259,22 @@ cramers_v <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust =
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
} else {
x <- suppressWarnings(stats::chisq.test(x, y, ...))
x <- suppressWarnings(stats::chisq.test(x, y, p = p, ...))
x$data.name <- NULL
}

effectsize(x, type = "cramers_v", adjust = adjust, ci = ci, alternative = alternative)
effectsize(x, type = "cohens_w", ci = ci, alternative = alternative)
}


#' @rdname phi
#' @importFrom stats chisq.test
#' @export
normalized_chi <- function(x, y = NULL, ci = 0.95, alternative = "greater", ...) {
fei <- function(x, p = rep(1/length(x), length(x)), ci = 0.95, alternative = "greater", ...) {
alternative <- match.arg(alternative, c("greater", "two.sided", "less"))

if (inherits(x, "BFBayesFactor")) {
stop("Normalized Chi is only applicable to goodness of fit tests.", call. = FALSE)
stop("Fei is only applicable to goodness of fit tests.", call. = FALSE)
}


Expand All @@ -282,24 +284,25 @@ normalized_chi <- function(x, y = NULL, ci = 0.95, alternative = "greater", ...)
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
} else {
x <- suppressWarnings(stats::chisq.test(x, y, ...))
x <- suppressWarnings(stats::chisq.test(x, y = NULL, p = p, ...))
x$data.name <- NULL
}

effectsize(x, type = "normalized_chi", ci = ci, alternative = alternative)
effectsize(x, type = "fei", ci = ci, alternative = alternative)
}

#' @rdname phi
#' @importFrom stats chisq.test
#' @export
pearsons_c <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust = FALSE, ...) {
pearsons_c <- function(x, y = NULL, p = rep(1/length(x), length(x)),
ci = 0.95, alternative = "greater", ...) {
alternative <- match.arg(alternative, c("greater", "two.sided", "less"))

if (inherits(x, "BFBayesFactor")) {
if (!inherits(x@numerator[[1]], "BFcontingencyTable")) {
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
return(effectsize(x, type = "pearsons_c", adjust = adjust, ci = ci, ...))
return(effectsize(x, type = "pearsons_c", ci = ci, ...))
}


Expand All @@ -309,11 +312,11 @@ pearsons_c <- function(x, y = NULL, ci = 0.95, alternative = "greater", adjust =
stop("'x' is not a Chi-squared test!", call. = FALSE)
}
} else {
x <- suppressWarnings(stats::chisq.test(x, y, ...))
x <- suppressWarnings(stats::chisq.test(x, y, p = p, ...))
x$data.name <- NULL
}

effectsize(x, type = "pearsons_c", adjust = adjust, ci = ci, alternative = alternative)
effectsize(x, type = "pearsons_c", ci = ci, alternative = alternative)
}


Expand All @@ -340,7 +343,7 @@ oddsratio <- function(x, y = NULL, ci = 0.95, alternative = "two.sided", log = F
return(effectsize(x, type = "or", log = log, ci = ci, ...))
}

res <- suppressWarnings(stats::chisq.test(x, y, ...))
res <- suppressWarnings(stats::chisq.test(x, y))
Obs <- res$observed

if (any(c(colSums(Obs), rowSums(Obs)) == 0L)) {
Expand Down Expand Up @@ -416,7 +419,7 @@ riskratio <- function(x, y = NULL, ci = 0.95, alternative = "two.sided", log = F
return(effectsize(x, type = "rr", log = log, ci = ci, ...))
}

res <- suppressWarnings(stats::chisq.test(x, y, ...))
res <- suppressWarnings(stats::chisq.test(x, y))
Obs <- res$observed

if (any(c(colSums(Obs), rowSums(Obs)) == 0L)) {
Expand Down Expand Up @@ -494,7 +497,7 @@ cohens_h <- function(x, y = NULL, ci = 0.95, alternative = "two.sided", ...) {
return(effectsize(x, type = "cohens_h", ci = ci, ...))
}

res <- suppressWarnings(stats::chisq.test(x, y, ...))
res <- suppressWarnings(stats::chisq.test(x, y))
Obs <- res$observed

if (any(c(colSums(Obs), rowSums(Obs)) == 0L)) {
Expand Down
Loading