Skip to content

Commit

Permalink
metacont(): bug fix for exact SMD method if total sample size is abov…
Browse files Browse the repository at this point in the history
…e 343 (#42)
  • Loading branch information
guido-s committed Dec 2, 2021
1 parent ff9adca commit e18d6c7
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 153 deletions.
29 changes: 27 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
## meta, version 5.1-1 (2021-mm-dd)
## meta, version 5.1-1 (2021-12-03)

### Major changes

* For meta-analysis of single proportions,
- export p-value of exact binomial test for individual studies if
Clopper-Pearson method (method.ci = "CP") is used to calculate
confidence intervals for individual studies
- do not export p-value for individual studies if argument
'method.ci' is not equal to "CP" or "NAsm" (normal approximation
based on summary measure)

### Bug fixes

* Meta-analysis of continuous outcomes using Hedges' g or Cohen's d as
summary measure resulted in [inestimable SMDs in individual
studies](https://github.com/guido-s/meta/issues/42) if the total
sample size was larger than 343 and argument 'exact.smd' was TRUE
(default)

* Forest plot creation for meta-analysis of single means with
subgroups resulted in an error
subgroups resulted in an
[error](https://github.com/guido-s/meta/issues/41)

### Internal changes

* New internal function ciClopperPearson() to calculate confidence
limits and p-value for exact binomial method

* Exported list elements changed for internal functions
ciAgrestiCoull(), ciSimpleAsymptotic() and ciWilsonScore()


## meta, version 5.1-0 (2021-11-17)
Expand Down
7 changes: 3 additions & 4 deletions R/ci.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@


ci <- function(TE, seTE, level = 0.95, df = NULL, null.effect = 0) {

if (level <= 0 | level >= 1)
stop("no valid level for confidence interval")


chklevel(level)

alpha <- 1 - level

if (is.null(df)) {
Expand Down
183 changes: 136 additions & 47 deletions R/meta-ci.R
Original file line number Diff line number Diff line change
@@ -1,79 +1,168 @@
ciAgrestiCoull <- function(event, n, level = 0.95) {

if (level <= 0 | level >= 1)
stop("no valid level for confidence interval")

ciAgrestiCoull <- function(event, n, level) {
chknumeric(event, 0)
chknumeric(n, 0, zero = TRUE)
chklevel(level)
##
if (length(event) == 1 & length(n) > 1)
event <- rep(event, length(n))
else if (length(event) > 1 & length(n) == 1)
n <- rep(n, length(event))
else
if (length(event) != length(n))
stop("Arguments 'event' and 'n' must be of same length.", call. = FALSE)
##
if (any(event > n, na.rm = TRUE))
stop("Number of events must be smaller equal sample size.", call. = FALSE)
##
z <- qnorm(1 - (1 - level) / 2)
##
n <- n + z^2
p <- 1 / n * (event + 0.5 * z^2)

lower <- p - z * sqrt(1 / n * p * (1 - p))
upper <- p + z * sqrt(1 / n * p * (1 - p))
prop <- 1 / n * (event + 0.5 * z^2)
##
lower <- prop - z * sqrt(1 / n * prop * (1 - prop))
upper <- prop + z * sqrt(1 / n * prop * (1 - prop))
##
lower[lower < 0] <- 0
upper[upper > 1] <- 1

list(n = n, p = p, lower = lower, upper = upper, level = level)
##
list(event = event, n = n,
prop = prop, lower = lower, upper = upper,
statistic = NA, p = NA, level = level,
df = NA, null.effect = NA)
}


ciClopperPearson <- function(event, n, level, null.effect) {
chknumeric(event, 0)
chknumeric(n, 0, zero = TRUE)
chklevel(level)
chknumeric(null.effect, min = 0, max = 1, length = 1)
##
if (length(event) == 1 & length(n) > 1)
event <- rep(event, length(n))
else if (length(event) > 1 & length(n) == 1)
n <- rep(n, length(event))
else
if (length(event) != length(n))
stop("Arguments 'event' and 'n' must be of same length.", call. = FALSE)
##
if (any(event > n, na.rm = TRUE))
stop("Number of events must be smaller equal sample size.", call. = FALSE)
##
k <- length(event)
lower <- upper <- statistic <- pval <- rep(NA, k)
##
for (i in seq_len(k)) {
if (!is.na(event[i] & !is.na(n[i]))) {
cint <- binom.test(event[i], n[i], conf.level = level,
p = if (!is.na(null.effect)) null.effect else 0.5)
##
lower[i] <- cint$conf.int[[1]]
upper[i] <- cint$conf.int[[2]]
if (!is.na(null.effect))
pval[i] <- cint$p.value
}
else {
lower[i] <- NA
upper[i] <- NA
pval[i] <- NA
}
}
##
list(event = event, n = n,
prop = event / n, lower = lower, upper = upper,
statistic = statistic, p = pval, level = level,
df = NA, null.effect = null.effect)
}
ciSimpleAsymptotic <- function(event, n, level = 0.95, correct = FALSE) {

## Reference:


ciSimpleAsymptotic <- function(event, n, level, correct = FALSE) {
##
## Newcombe RG. Two-sided confidence intervals for the single
## proportion: Comparison of seven methods.
## Stat Med 1998, Apr 30;17(8): 857-72

if (level <= 0 | level >= 1)
stop("no valid level for confidence interval")

p <- event / n
q <- 1 - p
##
chknumeric(event, 0)
chknumeric(n, 0, zero = TRUE)
chklevel(level)
chklogical(correct)
##
if (length(event) == 1 & length(n) > 1)
event <- rep(event, length(n))
else if (length(event) > 1 & length(n) == 1)
n <- rep(n, length(event))
else
if (length(event) != length(n))
stop("Arguments 'event' and 'n' must be of same length.", call. = FALSE)
##
if (any(event > n, na.rm = TRUE))
stop("Number of events must be smaller equal sample size.", call. = FALSE)
##
prop <- event / n
z <- qnorm(1 - (1 - level) / 2)

##
if (!correct) {
lower <- p - z * sqrt(p * q / n)
upper <- p + z * sqrt(p * q / n)
lower <- prop - z * sqrt(prop * (1 - prop) / n)
upper <- prop + z * sqrt(prop * (1 - prop) / n)
}
else {
lower <- p - (z * sqrt(p * q / n) + 1 / (2 * n))
upper <- p + (z * sqrt(p * q / n) + 1 / (2 * n))
lower <- prop - (z * sqrt(prop * (1 - prop) / n) + 1 / (2 * n))
upper <- prop + (z * sqrt(prop * (1 - prop) / n) + 1 / (2 * n))
}
##
lower[lower < 0] <- 0
upper[upper > 1] <- 1

list(n = n, p = p, lower = lower, upper = upper, level = level)
##
list(event = event, n = n,
prop = prop, lower = lower, upper = upper,
statistic = NA, p = NA, level = level,
df = NA, null.effect = NA)
}
ciWilsonScore <- function(event, n, level = 0.95, correct = FALSE) {

## Reference:


ciWilsonScore <- function(event, n, level, correct = FALSE) {
##
## Newcombe RG. Two-sided confidence intervals for the single
## proportion: Comparison of seven methods.
## Stat Med 1998, Apr 30;17(8): 857-72

if (level <= 0 | level >= 1)
stop("no valid level for confidence interval")

p <- event / n
q <- 1 - p
##
chknumeric(event, 0)
chknumeric(n, 0, zero = TRUE)
chklevel(level)
##
if (length(event) == 1 & length(n) > 1)
event <- rep(event, length(n))
else if (length(event) > 1 & length(n) == 1)
n <- rep(n, length(event))
else
if (length(event) != length(n))
stop("Arguments 'event' and 'n' must be of same length.", call. = FALSE)
##
if (any(event > n, na.rm = TRUE))
stop("Number of events must be smaller equal sample size.", call. = FALSE)
##
prop <- event / n
z <- qnorm(1 - (1 - level) / 2)

##
if (!correct) {
lower <- (2 * n * p + z^2 -
z * sqrt(z^2 + 4 * n * p * q)) / (2 * (n + z^2))
upper <- (2 * n * p + z^2 +
z * sqrt(z^2 + 4 * n * p * q)) / (2 * (n + z^2))
lower <- (2 * n * prop + z^2 -
z * sqrt(z^2 + 4 * n * prop * (1 - prop))) / (2 * (n + z^2))
upper <- (2 * n * prop + z^2 +
z * sqrt(z^2 + 4 * n * prop * (1 - prop))) / (2 * (n + z^2))
}
else {
lower <- (2 * n * p + z^2 - 1 -
z * sqrt(z^2 - 2 - 1/n + 4 * p * (n * q + 1))) /
lower <- (2 * n * prop + z^2 - 1 -
z * sqrt(z^2 - 2 - 1/n + 4 * prop * (n * (1 - prop) + 1))) /
(2 * (n + z^2))
lower[lower < 0] <- 0
upper <- (2 * n * p + z^2 + 1 +
z * sqrt(z^2 + 2 - 1/n + 4 * p * (n * q - 1))) /
upper <- (2 * n * prop + z^2 + 1 +
z * sqrt(z^2 + 2 - 1/n + 4 * prop * (n * (1 - prop) - 1))) /
(2 * (n + z^2))
upper[upper > 1] <- 1
}

list(n = n, p = p, lower = lower, upper = upper, level = level)
##
list(event = event, n = n,
prop = prop, lower = lower, upper = upper,
statistic = NA, p = NA, level = level,
df = NA, null.effect = NA)
}
49 changes: 49 additions & 0 deletions R/meta-internal.R
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,55 @@ catmeth <- function(method,
}


catobsev <- function(var1, var2 = NULL, type = "n", addrow = FALSE,
big.mark = gs("big.mark")) {
if (type == "n") {
txt <- "observations"
idx <- "o"
}
else if (type == "e") {
txt <- "events"
idx <- "e"
}
##
if (!is.null(var1) & !is.null(var2)) {
if (!(all(is.na(var1)) | all(is.na(var2)))) {
sum1 <- sum(var1, na.rm = TRUE)
sum2 <- sum(var2, na.rm = TRUE)
##
cat(paste0("Number of ", txt, ": ", idx, " = ",
format(sum1 + sum2, big.mark = big.mark),
##" (", idx, ".e = ",
##format(sum1, big.mark = big.mark),
##", ", idx, ".c = ",
##format(sum2, big.mark = big.mark),
##")",
"\n"))
}
}
else if (!is.null(var1)) {
if (!all(is.na(var1))) {
cat(paste0("Number of ", txt, ": ", idx, " = ",
format(sum(var1, na.rm = TRUE),
big.mark = big.mark),
"\n"))
}
}
else if (!is.null(var2)) {
if (!all(is.na(var2))) {
cat(paste0("Number of ", txt, ": ", idx, " = ",
format(sum(var2, na.rm = TRUE), big.mark = big.mark),
"\n"))
}
}
##
if (addrow)
cat("\n")
##
invisible(NULL)
}


## The following R code is based on the file snowfall-internal.R from
## R package snowfall (Maintainer: Jochen Knaus <jo@imbi.uni-freiburg.de>)
##
Expand Down
Loading

0 comments on commit e18d6c7

Please sign in to comment.