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

Update definition of BreslowDayFunction #20

Merged
merged 3 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ Imports:
magrittr,
checkmate,
cli,
usethis
usethis,
DescTools
Remotes:
hta-pharma/chef,
matthew-phelps/testr
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export(sd_value)
export(use_chefStats)
import(data.table)
importFrom(Barnard,barnard.test)
importFrom(magrittr,"%>%")
89 changes: 2 additions & 87 deletions R/BreslowDayFunction.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,91 +9,6 @@
#' \eqn{\chi^2(K-1)} distribution
breslowdaytest_ <- function(x, odds_ratio = NA, correct = FALSE) {

# Function to perform the Breslow and Day (1980) test including the
# corrected test by Tarone Uses the equations in Lachin (2000),
# Biostatistical Methods, Wiley, p. 124-125.
#
# Programmed by Michael Hoehle <http://www.math.su.se/~hoehle>
# Code taken originally from a Biostatistical Methods lecture
# held at the Technical University of Munich in 2008.
#
# Params:
# x - a 2x2xK contingency table
# correct - if TRUE Tarones correction is returned
#
# Returns:
# a vector with three values
# statistic - Breslow and Day test statistic
# pval - p value evtl. based on the Tarone test statistic
# using a \chi^2(K-1) distribution
#

if (is.na(odds_ratio)) {
#Find the common odds_ratio based on Mantel-Haenszel
oddsratio_hat_mh <- stats::mantelhaen.test(x)$estimate
} else {
oddsratio_hat_mh <- odds_ratio
}

#Number of strata
k <- dim(x)[3]
#Value of the Statistic
x2_hbd <- 0
#Value of aj, tildeaj and variance_aj
a <- tildea <- variance_a <- numeric(k)

for (j in 1:k) {
#Find marginals of table j
mj <- apply(x[, , j], MARGIN = 1, sum)
nj <- apply(x[, , j], MARGIN = 2, sum)

#Solve for tilde(a)_j
coef <- c(-mj[1] * nj[1] * oddsratio_hat_mh, nj[2] - mj[1]
+ (oddsratio_hat_mh * (nj[1] + mj[1])),
1 - oddsratio_hat_mh)
sols <- Re(polyroot(coef))
#Take the root, which fulfills 0 < tilde(a)_j <= min(n1_j, m1_j)
tildeaj <- sols[(0 < sols) & (sols <= min(nj[1], mj[1]))]
#Observed value
aj <- x[1, 1, j]

#Determine other expected cell entries
tildebj <- mj[1] - tildeaj
tildecj <- nj[1] - tildeaj
tildedj <- mj[2] - tildecj

#Compute \hat{\variance}(a_j | \widehat{\odds_ratio}_MH)
variance_aj <- (1 / tildeaj + 1 / tildebj + 1 / tildecj + 1 / tildedj)^(-1)

#Compute contribution
x2_hbd <- x2_hbd + as.numeric((aj - tildeaj)^2 / variance_aj)

#Assign found value for later computations
a[j] <- aj
tildea[j] <- tildeaj
variance_a[j] <- variance_aj
}

# Compute Tarone corrected test
# Add on 2015: The original equation from the 2008 lecture is incorrect
# as pointed out by Jean-Francois Bouzereau.
x2_hbdt <- as.numeric(x2_hbd - (sum(a) - sum(tildea))^2 / sum(variance_a))

dname <- deparse(substitute(x))

statistic <- if (correct) x2_hbdt else x2_hbd
parameter <- k - 1
# Compute p-value based on the Tarone corrected test
pval <- 1 - stats::pchisq(statistic, parameter)
method <-
if (correct)
"Breslow-Day Test on Homogeneity of Odds Ratios (with Tarone correction)"
else
"Breslow-Day Test on Homogeneity of Odds Ratios"
names(statistic) <- "X-squared"
names(parameter) <- "df"
structure(list(statistic = statistic, parameter = parameter,
p.value = pval, method = method, data.name = dname),
class = "htest")

# Call the BreslowDayTest from the DescTools package
DescTools::BreslowDayTest(x, odds_ratio, correct)
}
6 changes: 3 additions & 3 deletions R/by_strata_by_trt.R
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ demographics_continuous <- function(dat,
stat <- dat_cell[,
.(
mean = mean(get(var), na.rm = TRUE),
median = median(get(var), na.rm = TRUE),
sd = sd(get(var), na.rm = TRUE),
median = stats::median(get(var), na.rm = TRUE),
sd = stats::sd(get(var), na.rm = TRUE),
min = min(get(var), na.rm = TRUE),
max = max(get(var), na.rm = TRUE),
n_non_missing = sum(!is.na(get(var))),
Expand Down Expand Up @@ -580,7 +580,7 @@ sd_value <- function(dat,
unique(by = c(subjectid_var))

stat <- dat_cell[[var]] |>
sd()
stats::sd()

return(
data.table(
Expand Down
6 changes: 5 additions & 1 deletion R/two_by_two_x.R
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
#' @param treatment_var character. The name of the treatment variable in `dat`.
#' @param treatment_refval character. The reference value of the treatment variable in `dat`.
#' @param subjectid_var character. Name of the subject identifier variable in `dat` (default is "USUBJID").
#'@return A matrix
#' @return A matrix
#' @export
#' @importFrom magrittr %>%
#'
make_two_by_two_ <-
function(dat,
Expand All @@ -33,6 +34,8 @@ make_two_by_two_ <-
treatment_var,
treatment_refval,
subjectid_var) {
N <- is_cell <- is_event <- INDEX_ <- treatment <- NULL

dat_ <- copy(dat)
n_trt_levels <-
dat[, unique(dat, by = treatment_var)][[treatment_var]] |>
Expand Down Expand Up @@ -103,6 +106,7 @@ make_two_by_two_ <-
#' @return data.table of 2x2 table in long format
#' @noRd
ensure_complete_two_by_two <- function(two_by_two_long, treatment_var) {
is_cell <- N <- NULL
n_rows_two_by_two_long <-
two_by_two_long[(is_cell), .N, by = c("is_event", treatment_var)] |> NROW()

Expand Down
3 changes: 3 additions & 0 deletions tests/testthat/test-two_by_twos.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ expected <- as.matrix(cbind(yes_counts[,.(N)], no_counts[,.(N)]))
rownames(expected) <- no_counts$TRT01A
colnames(expected) <- c("outcome_YES", "outcome_NO")

# With data.table 1.16, attributes are preserved in a different way, so strip
# these for testing.
attr(dimnames(expected)[[1]], "label") <- NULL

expect_identical(actual, expected)
})