Skip to content

Commit

Permalink
Usability improvements for pd() and pd_to_p() (#668)
Browse files Browse the repository at this point in the history
* Usability improvements for pd() and pd_to_p()
Fixes #665

* docs

* add as_p

* Work on #664

* add tests

* add tests

* tests for as..vector

* news

* include #666

* news

* news

* lintr
  • Loading branch information
strengejacke authored Aug 31, 2024
1 parent 73d77e3 commit 1d81f55
Show file tree
Hide file tree
Showing 11 changed files with 467 additions and 130 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Type: Package
Package: bayestestR
Title: Understand and Describe Bayesian Models and Posterior Distributions
Version: 0.14.0.2
Version: 0.14.0.3
Authors@R:
c(person(given = "Dominique",
family = "Makowski",
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ S3method(as.numeric,map_estimate)
S3method(as.numeric,p_direction)
S3method(as.numeric,p_map)
S3method(as.numeric,p_significance)
S3method(as.vector,p_direction)
S3method(bayesfactor_inclusion,BFBayesFactor)
S3method(bayesfactor_inclusion,bayesfactor_models)
S3method(bayesfactor_models,BFBayesFactor)
Expand Down Expand Up @@ -368,6 +369,8 @@ S3method(p_significance,stanfit)
S3method(p_significance,stanreg)
S3method(p_to_bf,default)
S3method(p_to_bf,numeric)
S3method(pd_to_p,data.frame)
S3method(pd_to_p,numeric)
S3method(plot,bayesfactor_models)
S3method(plot,bayesfactor_parameters)
S3method(plot,bayestestR_eti)
Expand Down
25 changes: 25 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# bayestestR (development version)

## Changes

* Usability improvements for `p_direction()`:

- Results from `p_direction()` can directly be used in `pd_to_p()`.

- `p_direction()` gets an `as_p` argument, to directly convert pd-values into
frequentist p-values.

- `p_direction()` gets a `remove_na` argument, which defaults to `TRUE`, to
remove `NA` values from the input before calculating the pd-values.

- The `data.frame` method for `p_direction()` gets an `rvar_col` argument, to
specify the column that contains the `rvar` objects.

- Besides the existing `as.numeric()` method, `p_direction()` now also has an
`as.vector()` method.

* `p_to_pd()` now also works with data frames returned by `p_direction()`. If
a data frame contains a `pd`, `p_direction` or `PD` column name, this is assumed
to be the pd-values, which are then converted to p-values.

* `p_to_pd()` for data frame inputs gets a `as.numeric()` and `as.vector()`
method.

## Bug fixes

* Fixed warning in CRAN check results.
Expand Down
5 changes: 2 additions & 3 deletions R/bayesfactor_inclusion.R
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ bayesfactor_inclusion.bayesfactor_models <- function(models,
attr(df.effect, "matched") <- match_models
attr(df.effect, "priorOdds") <- prior_odds

return(df.effect)
df.effect
}


Expand All @@ -185,8 +185,7 @@ bayesfactor_inclusion.BFBayesFactor <- function(models,
eff_b <- strsplit(eff, ":", fixed = TRUE)
effnames_b <- strsplit(effnames, ":", fixed = TRUE)

is_int <- vapply(effnames_b, function(x) length(x) > 1, TRUE)

is_int <- lengths(effnames_b) > 1
temp <- logical(length(effnames))

for (rr in seq_along(effnames)) {
Expand Down
10 changes: 5 additions & 5 deletions R/bayesfactor_models.R
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ bayesfactor_models.default <- function(..., denominator = 1, verbose = TRUE) {
cl$...$estimator <- cl$...$check_response <- NULL


names(mods) <- sapply(cl$`...`, insight::safe_deparse)
names(mods) <- sapply(cl[["..."]], insight::safe_deparse)
names(denominator) <- insight::safe_deparse(cl$denominator)

mods <- .cleanup_BF_models(mods, denominator, cl)
Expand Down Expand Up @@ -346,7 +346,7 @@ bayesfactor_models.stanreg <- function(..., denominator = 1, verbose = TRUE) {
denominator <- list(denominator)

cl <- match.call(expand.dots = FALSE)
names(mods) <- sapply(cl$`...`, insight::safe_deparse)
names(mods) <- sapply(cl[["..."]], insight::safe_deparse)
names(denominator) <- insight::safe_deparse(cl$denominator)

mods <- .cleanup_BF_models(mods, denominator, cl)
Expand Down Expand Up @@ -446,7 +446,7 @@ as.matrix.bayesfactor_models <- function(x, ...) {
.cleanup_BF_models <- function(mods, denominator, cl) {
if (length(mods) == 1 && inherits(mods[[1]], "list")) {
mods <- mods[[1]]
mod_names <- .safe(sapply(cl$`...`[[1]][-1], insight::safe_deparse))
mod_names <- .safe(sapply(cl[["..."]][[1]][-1], insight::safe_deparse))

if (!is.null(mod_names) && length(mod_names) == length(mods)) {
names(mods) <- mod_names
Expand Down Expand Up @@ -562,10 +562,10 @@ as.matrix.bayesfactor_models <- function(x, ...) {
is_wrapped <- grepl("(", m_txt, fixed = TRUE)
m_txt[!is_wrapped] <- paste0("(", m_txt[!is_wrapped], ")")

return(m_txt)
m_txt
},
error = function(e) {
return(m_names)
m_names
}
)
}
Expand Down
57 changes: 43 additions & 14 deletions R/convert_pd_to_p.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,33 @@
#'
#' Enables a conversion between Probability of Direction (pd) and p-value.
#'
#' @param pd A Probability of Direction (pd) value (between 0 and 1).
#' @param pd A Probability of Direction (pd) value (between 0 and 1). Can also
#' be a data frame with a column named `pd`, `p_direction`, or `PD`, as returned
#' by [`p_direction()`]. In this case, the column is converted to p-values and
#' the new data frame is returned.
#' @param p A p-value.
#' @param direction What type of p-value is requested or provided. Can be
#' `"two-sided"` (default, two tailed) or `"one-sided"` (one tailed).
#' @param verbose Toggle off warnings.
#' @param ... Arguments passed to or from other methods.
#'
#' @return A p-value or a data frame with a p-value column.
#'
#' @details
#' Conversion is done using the following equation (see Makowski et al., 2019):
#' \cr\cr
#' When `direction = "two-sided"` -
#' \cr\cr
#' Conversion is done using the following equation (see _Makowski et al., 2019_):
#'
#' When `direction = "two-sided"`
#'
#' \deqn{p = 2 \times (1 - p_d)}{p = 2 * (1 - pd)}
#' When `direction = "one-sided"` -
#' \cr\cr
#'
#' When `direction = "one-sided"`
#'
#' \deqn{p = 1 - p_d}{p = 1 - pd}
#' \cr\cr
#'
#' Note that this conversion is only valid when the lowest possible values of pd
#' is 0.5 - i.e., when the posterior represents continuous parameter space (see
#' [p_direction]). If any pd < 0.5 are detected, they are converted to a p of 1,
#' and a warning is given.
#' [`p_direction()`]). If any pd < 0.5 are detected, they are converted to a p
#' of 1, and a warning is given.
#'
#' @references
#' Makowski, D., Ben-Shachar, M. S., Chen, S. H. A., and Lüdecke, D. (2019).
Expand All @@ -34,7 +40,14 @@
#' pd_to_p(pd = 0.95, direction = "one-sided")
#'
#' @export
pd_to_p <- function(pd, direction = "two-sided", verbose = TRUE, ...) {
pd_to_p <- function(pd, ...) {
UseMethod("pd_to_p")
}


#' @export
#' @rdname pd_to_p
pd_to_p.numeric <- function(pd, direction = "two-sided", verbose = TRUE, ...) {
p <- 1 - pd
if (.get_direction(direction) == 0) {
p <- 2 * p
Expand All @@ -44,9 +57,9 @@ pd_to_p <- function(pd, direction = "two-sided", verbose = TRUE, ...) {
if (any(less_than_0.5)) {
if (verbose) {
insight::format_warning(paste(
"pd values smaller than 0.5 detected.",
"pd-to-p conversion assumes a continious parameter space;",
"see help('p_direction') for more info."
"pd-values smaller than 0.5 detected, indicating inconsistent direction of the probability mass.",
"This usually happens when the parameters space is not continuous. Affected values are set to 1.",
"See help('p_direction') for more info."
))
}
p[less_than_0.5] <- 1
Expand All @@ -56,6 +69,22 @@ pd_to_p <- function(pd, direction = "two-sided", verbose = TRUE, ...) {
}


#' @export
pd_to_p.data.frame <- function(pd, direction = "two-sided", verbose = TRUE, ...) {
# check if data frame has an appropriate column
pd_column <- intersect(c("pd", "p_direction", "PD"), colnames(pd))[1]
if (is.na(pd_column) || length(pd_column) == 0) {
insight::format_error("No column named `pd`, `p_direction`, or `PD` found.")
}

# add p-value column
pd$p <- pd_to_p(as.numeric(pd[[pd_column]]))
# remove pd-column
pd[[pd_column]] <- NULL
pd
}


#' @rdname pd_to_p
#' @export
p_to_pd <- function(p, direction = "two-sided", ...) {
Expand Down
Loading

0 comments on commit 1d81f55

Please sign in to comment.