Skip to content

Commit

Permalink
bulk commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bailliem committed Dec 3, 2024
0 parents commit 4592819
Show file tree
Hide file tree
Showing 67 changed files with 107,599 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
^rbmi\.helpers\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
^README\.Rmd$
^data-raw$
^doc$
^Meta$
^.gitlab-ci.yml$
^docs$
^.*\.Rproj$
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.Rproj.user
.Rhistory
.Rdata
.httr-oauth
.DS_Store
.quarto
inst/doc
/doc/
/Meta/
scratch.R
.gitlab-ci.yml
37 changes: 37 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Package: rbmiUtils
Title: Utility functions to work with and extend the rbmi package
Version: 0.0.1
Authors@R: c(
person("Mark", "Baillie", email = "mark.baillie@novartis.com", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-5618-0667")),
person("Tobias", "Mütze", email = "tobias.muetze@novartis.com", role = c("aut"),
comment = c(ORCID = "0000-0002-4111-1941")),
person("Jack", "Talboys", email = "jack.talboys@novartis.com", role = c("ctb")),
person("Lukas A.", "Widmer", role = "ctb", comment = c(ORCID = "0000-0003-1471-3493"))
)
Description: This package provides additional functionality for rbmi to enable trial analysis and reporting aligned with CDISC ADaM.
License: GPL (>= 3)
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Suggests:
knitr,
rmarkdown,
spelling,
testthat (>= 3.0.0),
tidyr,
readr,
ggplot2,
beeca
Config/testthat/edition: 3
Language: en-US
Imports:
assertthat,
dplyr,
purrr,
rbmi,
rlang
VignetteBuilder: knitr
Depends:
R (>= 2.10)
LazyData: true
595 changes: 595 additions & 0 deletions LICENSE.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Generated by roxygen2: do not edit by hand

export(analyse_mi_data)
export(get_imputed_data)
export(tidy_pool_obj)
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# rbmiUtils (development version)

* Initial CRAN submission.

# rbmiUtils 0.0.1

* tbc
20 changes: 20 additions & 0 deletions R/ADEFF.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#' Example efficacy trial dataset
#'
#' A simplified example of a simulated trial dataset, with missing data.
#'
#' @format `ADEFF`
#' A data frame with 1,000 rows and 10 columns:
#' \describe{
#' \item{USUBJID}{Unique subject identifier}
#' \item{AVAL}{Primary outcome variable}
#' \item{TRT01P}{Planned treatment}
#' \item{STRATA}{Stratification at randomisation}
#' \item{REGION}{Stratification by region}
#' \item{REGIONC}{Stratification by region, numeric code}
#' \item{BASE}{Baseline value of primary outcome variable}
#' \item{CHG}{Change from baseline}
#' \item{AVISIT}{Visit number}
#' \item{PARAM}{Analysis parameter name}
#' }
#'
"ADEFF"
22 changes: 22 additions & 0 deletions R/ADMI.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#' Example multiple imputation trial dataset
#'
#' A simplified example of a simulated trial ADMI dataset
#'
#' @format `ADMI`
#' A data frame with 100,000 rows and 12 columns:
#' \describe{
#' \item{USUBJID}{Unique patient identifier}
#' \item{STRATA}{Stratification at randomisation}
#' \item{REGION}{Stratification by region}
#' \item{REGIONC}{Stratification by region, numeric code}
#' \item{TRT}{Planned treatment}
#' \item{BASE}{Baseline value of primary outcome variable}
#' \item{CHG}{Change from baseline}
#' \item{AVISIT}{Visit number}
#' \item{IMPID}{Imputation number identifier}
#' \item{CRIT1FLN}{Responder criteria (binary)}
#' \item{CRIT1FL}{Responder criteria (categorical)}
#' \item{CRIT}{Responder criteria (definition)}
#' }
#'
"ADMI"
179 changes: 179 additions & 0 deletions R/analyse_mi_data.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#' Apply Analysis Function to Multiple Imputed Datasets
#'
#' This function applies an analysis function (e.g., ANCOVA) to imputed datasets and stores the results for later pooling. It is designed to work with multiple imputed datasets and apply a given analysis function to each imputation iteration.
#'
#' @param data A data frame containing the imputed datasets. The data frame should include a variable (e.g., `IMPID`) that identifies distinct imputation iterations.
#' @param vars A list specifying key variables used in the analysis (e.g., `subjid`, `visit`, `group`, `outcome`). Required.
#' @param method A character string or object specifying the method used for analysis (e.g., Bayesian imputation). Defaults to `NULL`.
#' @param fun A function that will be applied to each imputed dataset. Defaults to `rbmi::ancova`. Must be a valid analysis function.
#' @param delta A `data.frame` used for delta adjustments, or `NULL` if no delta adjustments are needed. Defaults to `NULL`.
#' @param ... Additional arguments passed to the analysis function `fun`.
#'
#' @details
#' The function loops through distinct imputation datasets (identified by `IMPID`), applies the provided analysis function `fun`, and stores the results for later pooling. If a `delta` dataset is provided, it will be merged with the imputed data to apply the specified delta adjustment before analysis.
#'
#' @return An object of class `analysis` containing the results from applying the analysis function to each imputed dataset.
#'
#' @examples
#' # Example usage with an ANCOVA function
#' library(dplyr)
#' library(rbmi)
#'
#' data("ADMI")
#' N_IMPUTATIONS <- 100
#' BURN_IN <- 200
#' BURN_BETWEEN <- 5
#'
#' # Convert key columns to factors
#' ADMI$TRT <- factor(ADMI$TRT, levels = c("Placebo", "Drug A"))
#' ADMI$USUBJID <- factor(ADMI$USUBJID)
#' ADMI$AVISIT <- factor(ADMI$AVISIT)
#'
#' # Define key variables for ANCOVA analysis
#' vars <- set_vars(
#' subjid = "USUBJID",
#' visit = "AVISIT",
#' group = "TRT",
#' outcome = "CHG",
#' covariates = c("BASE", "STRATA", "REGION") # Covariates for adjustment
#' )
#'
#' # Specify the imputation method (Bayesian) - need for pool step
#' method <- rbmi::method_bayes(
#' n_samples = N_IMPUTATIONS,
#' burn_in = BURN_IN,
#' burn_between = BURN_BETWEEN
#' )
#'
#' # Perform ANCOVA Analysis on Each Imputed Dataset
#' ana_obj_ancova <- analyse_mi_data(
#' data = ADMI,
#' vars = vars,
#' method = method,
#' fun = ancova, # Apply ANCOVA
#' delta = NULL # No sensitivity analysis adjustment
#' )
#'
#' @export
analyse_mi_data <- function(data = NULL, vars = NULL, method = NULL, fun = rbmi::ancova, delta = NULL, ...){

# Check for missing inputs
if (is.null(data))
stop("`data` cannot be NULL.")

# check IMPID is in data
if (!"IMPID" %in% names(data))
stop("`data` must contain a variable `IMPID` to identify distinct imputation iterations.")

if (is.null(vars))
stop("`vars` cannot be NULL. Specify key variables.")

## asset function
assertthat::assert_that(
is.function(fun),
msg = "`fun` must be a function"
)

## check on delta
assertthat::assert_that(
is.null(delta) | is.data.frame(delta),
msg = "`delta` must be NULL or a data.frame"
)

## check delta has correct variables and then apply
if (!is.null(delta)) {
expected_vars <- c(
vars$subjid,
vars$visit,
"delta"
)
assertthat::assert_that(
all(expected_vars %in% names(delta)),
msg = sprintf(
"The following variables must exist witin `delta`: `%s`",
paste0(expected_vars, collapse = "`, `")
)
)

## apply delta to data set adding to outcome
data <- data |>
dplyr::left_join(delta, by = c(vars$subjid, vars$visit, vars$group)) |>
dplyr::mutate(!!rlang::sym(vars$outcome) := .data[[vars$outcome]] + .data$delta)
}

# Loop through distinct imputation data sets based on IMPID in a single data frame
results <- data |>
dplyr::group_split(IMPID) |>
lapply(function(dat_subset, ...) {
# Perform analysis on the subset of data corresponding to each imputation
fun(dat_subset, vars, ...)
}, ...)


fun_name <- deparse(substitute(fun))

if (length(fun_name) > 1) {
fun_name <- "<Anonymous Function>"
} else if (is.null(fun_name)) {
fun_name <- "<NULL>"
}

ret <- as_analysis2(
results = results,
fun_name = fun_name,
delta = delta,
fun = fun,
method = method
)

return(ret)
}


#' Construct an rbmi `analysis` object
#'
#' @description
#' This is a helper function to create an analysis object that stores the
#' results from multiple imputation analyses. It validates the results and
#' ensures proper class assignment.
#'
#' This is a modification of the rbmi::as_analysis function.
#'
#' @param results A list containing the analysis results for each imputation.
#' @param method The method object used for the imputation.
#' @param delta Optional. A delta dataset used for adjustment.
#' @param fun The analysis function that was used.
#' @param fun_name The name of the analysis function (used for printing).
#'
#' @return An object of class `analysis` with the results and associated metadata.
as_analysis2 <- function(results, method, delta = NULL, fun = NULL, fun_name = NULL) {

next_class <- switch(class(method)[[2]],
bayes = "rubin",
approxbayes = "rubin",
condmean = ifelse(
method$type == "jackknife",
"jackknife",
"bootstrap"
),
bmlmi = "bmlmi"
)

assertthat::assert_that(
is.list(results),
length(next_class) == 1,
is.character(next_class),
next_class %in% c("jackknife", "bootstrap", "rubin", "bmlmi")
)

x <- list(
results = rbmi::as_class(results, c(next_class, "list")),
delta = delta,
fun = fun,
fun_name = fun_name,
method = method
)
class(x) <- c("analysis", "list")

return(x)
}
25 changes: 25 additions & 0 deletions R/rbmiUtils-package.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
utils::globalVariables(
c(
".data",
":=",
"IMPID",
"description",
"est",
"lci",
"lsm_type",
"original_id",
"parameter",
"parameter_type",
"pval",
"se",
"uci",
"visit"
)
)

#' @keywords internal
"_PACKAGE"

## usethis namespace: start
## usethis namespace: end
NULL
Loading

0 comments on commit 4592819

Please sign in to comment.