R/SE_from_p.R

Defines functions se.from.p

Documented in se.from.p

#' Calculate the standard error from the effect size and p-value
#'
#' This function calculates the standard error of an effect size provided the exact
#' \eqn{p}-value and (continuous) effect size according to the formula
#' by \href{https://www.ncbi.nlm.nih.gov/pubmed/21824904}{Altman and Bland (2011)}.
#'
#' @usage se.from.p(effect.size, p, N, effect.size.type = 'difference',
#'     calculate.g = FALSE)
#'
#' @param effect.size Numeric vector or single number. The effect size, such as the
#' standardized mean difference, Hedges' \eqn{g} or other continuous effect size.
#' @param p Numeric vector or single number. The exact \eqn{p}-value corresponding to the
#' effect size.
#' @param N Numeric vector or single number. The total number of samples used to
#' calculate the effect size/\eqn{p}-value.
#' @param effect.size.type The type of effect sizes provided in \code{effect.size}. For
#' effect sizes based on differences (e.g., mean differences), this parameter has to be
#' set to \code{"difference"}. For effect sizes based on ratios (e.g., risk ratio, odds ratio),
#' this parameter has to be set to \code{"ratio"}.
#' @param calculate.g Logical. Calculates the standardized mean difference
#' corrected for small sample bias (Hedges' \eqn{g}). \code{FALSE} by default.
#'
#' @details This function calculates the standard error, standard deviation and 95\% confidence
#' interval of an effect size given the effect size and exact \eqn{p}-value. The function can be used for:
#' \itemize{
#' \item effect sizes based on \strong{differences} (e.g., mean differences) by setting \code{effect.size.type}
#' to \code{"difference"}, or
#' \item effect sizes based on \strong{ratios} (e.g. risk ratios, odds ratios or
#' hazard ratios) by setting \code{effect.size.type} to \code{"ratio"}. When ratios are used, the
#' function returns the log-transformed effect sizes, standard error, standard deviation and confidence interval,
#' which can be used for meta-analytic pooling using the \code{\link[meta]{metagen}} function,
#' along with the original effect size and confidence interval.
#' }
#'
#' @references Altman D.G. & Bland J.M. (2011) How to obtain the confidence interval
#' of a \emph{p} value. \emph{BMJ 343}:d2090.
#'
#' @author Mathias Harrer & David Daniel Ebert
#'
#' @importFrom stats qnorm
#'
#' @return A dataframe containing the following columns:
#' \itemize{
#' \item \code{(log)EffectSize}: The input effect size. Log-transformed if \code{effect.size.type} is \code{"ratio"}.
#' \item \code{Hedges.g}: The calculated Hedges' g values (only if \code{calculate.g=TRUE}).
#' \item \code{(log)StandardError}: The standard error (SE) for the effect size. Log-transformed if \code{effect.size.type} is \code{"ratio"}.
#' \item \code{(log)LLCI} and \code{(log)ULCI}: The lower and upper 95\% confidence interval of the effect size. Log-transformed if \code{effect.size.type="ratio"}.}
#'
#' @export se.from.p
#'
#' @examples
#' # Example 1: one single effect size
#' se.from.p(effect.size = 0.71, p = 0.013, N = 75,
#'     effect.size.type= "difference", calculate.g = TRUE)
#'
#' # Example 2: vector of effect sizes (Odds Ratio)
#' effect.size = c(0.91, 1.01, 0.72, 0.43)
#' p = c(0.05, 0.031, 0.001, 0.09)
#' N = c(120, 86, 450, 123)
#' se.from.p(effect.size = effect.size, p = p, N = N,
#'     effect.size.type = "ratio")


se.from.p = function(effect.size, p, N, effect.size.type = "difference", calculate.g = FALSE) {

    # Define helper funcs
    sssbc = function(totaln){return(1 - (3/(4 * totaln - 9)))}
    hedges_g = function(d, totaln){mapply(function(.x, .y) .x * sssbc(.y), d, totaln)}

    # Set params
    ES = effect.size
    p = p
    N = N
    ES.type = effect.size.type
    calculate.g = calculate.g

    if (is.numeric(ES) == FALSE) {
        stop("'effect.size' is not of type numeric().")
    }

    if (is.numeric(p) == FALSE) {
        stop("'p' is not of type numeric().")
    }

    if (sum(p < 0 | p > 1) > 0){
        stop("values of 'p' must range between 0 and 1.")
    }

    if (is.numeric(N) == FALSE) {
        stop("'N' is not of type numeric().")
    }

    if (ES.type %in% c("difference", "ratio") == FALSE) {
        stop("'effect.size.type' must be either 'difference' or 'ratio'.")
    }

    if (ES.type == "ratio" & sum(ES < 0) > 0) {
        stop("when 'effect.size.type' is 'ratio', values of 'effect.size' must be equal to or greater than 0.")
    }

    # Difference vs. Ratio

    # Difference
    if (ES.type == "difference") {

        if (calculate.g == TRUE) {
            ES = hedges_g(d = ES, totaln = N)
            z = -0.862 + sqrt(0.743 - 2.404 * log(p))
            SE = ES/z
            SD = SE * sqrt(N)
            LLCI = ES - qnorm(0.975) * SE
            ULCI = ES + qnorm(0.975) * SE
            data = data.frame(ES, abs(SE), abs(SD), LLCI, ULCI)
            colnames(data) = c("Hedges.g", "StandardError", "StandardDeviation", "LLCI", "ULCI")

        } else {

            z = -0.862 + sqrt(0.743 - 2.404 * log(p))
            SE = ES/z
            SD = SE * sqrt(N)
            LLCI = ES - qnorm(0.975) * SE
            ULCI = ES + qnorm(0.975) * SE
            data = data.frame(ES, abs(SE), abs(SD), LLCI, ULCI)
            colnames(data) = c("EffectSize", "StandardError", "StandardDeviation", "LLCI", "ULCI")
        }

    }

    if (ES.type == "ratio") {

        if (calculate.g == TRUE) {

            stop("Hedges' g cannot be calculated for ratios using this function; set 'calculate.g=FALSE'.")

        } else {

            z = -0.862 + sqrt(0.743 - 2.404 * log(p))
            ES = log(ES)
            SE = abs(ES/z)
            SD = SE * sqrt(N)
            LLCI = ES - qnorm(0.975) * SE
            ULCI = ES + qnorm(0.975) * SE

            # Exponentiate to get original scale
            expES = exp(ES)
            expLLCI = exp(LLCI)
            expULCI = exp(ULCI)

            data = data.frame(ES, abs(SE), abs(SD), LLCI, ULCI, expES, expLLCI, expULCI)
            colnames(data) = c("logEffectSize", "logStandardError", "logStandardDeviation", "logLLCI", "logULCI", "EffectSize",
                "LLCI", "ULCI")
        }
    }
    return(data)
}
MathiasHarrer/dmetar documentation built on April 4, 2024, 6:57 p.m.