From dbb624a1bd910909d00c72d30cb5695dfa377198 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Tue, 22 Feb 2022 22:32:27 +0000 Subject: [PATCH 01/60] first pass at AE_Visualize + AE_Poisson_PredictBounds --- DESCRIPTION | 4 ++- NAMESPACE | 4 +++ R/AE_Poisson_PredictBounds.R | 41 ++++++++++++++++++++++ R/AE_Visualize.R | 55 ++++++++++++++++++++++++++++++ man/AE_Poisson_PredictBounds.Rd | 17 +++++++++ man/AE_Visualize.Rd | 21 ++++++++++++ tests/testthat/test-AE_Visualize.R | 3 ++ 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 R/AE_Poisson_PredictBounds.R create mode 100644 R/AE_Visualize.R create mode 100644 man/AE_Poisson_PredictBounds.Rd create mode 100644 man/AE_Visualize.Rd create mode 100644 tests/testthat/test-AE_Visualize.R diff --git a/DESCRIPTION b/DESCRIPTION index d3cbef175..015708477 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -12,7 +12,9 @@ Imports: dplyr, lubridate, magrittr, - purrr + purrr, + ggplot2, + lamW Suggests: testthat (>= 3.0.0), safetyData, diff --git a/NAMESPACE b/NAMESPACE index 65e8f3fb3..d9326ea02 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,8 @@ export("%>%") export(AE_Assess) export(AE_Map_Adam) export(AE_Map_Raw) +export(AE_Poisson_PredictBounds) +export(AE_Visualize) export(Analyze_Poisson) export(Analyze_Wilcoxon) export(Consent_Analyze) @@ -19,6 +21,8 @@ export(PD_Map_Raw) export(Summarize) export(Transform_EventCount) import(dplyr) +import(ggplot2) +import(lamW) import(lubridate) importFrom(broom,augment) importFrom(broom,glance) diff --git a/R/AE_Poisson_PredictBounds.R b/R/AE_Poisson_PredictBounds.R new file mode 100644 index 000000000..bd901f331 --- /dev/null +++ b/R/AE_Poisson_PredictBounds.R @@ -0,0 +1,41 @@ +#' Safety Assessment - Calculate prediction bounds +#' +#' @param dfOutput data frame in format produced by \code{\link{AE_Poisson_Analyze}} +#' +#' @return dataframe with prediction boundary curves +#' +#' @import lamW +#' +#' @export +AE_Poisson_PredictBounds <- function( dfOutput ){ + + cModel <- glm( + TotalCount ~ stats::offset(LogExposure), + family=poisson(link="log"), + data=dfOutput + ) + + vNewX <- seq( + min(dfOutput$LogExposure)-0.05, + max(dfOutput$LogExposure)+0.05, + by=0.05 + ) + + vMu <- as.numeric( exp( vNewX * cModel$coefficients[2] + cModel$coefficients[1] ) ) + vWHi <- ( dfOutput$ThresholdHigh[1] ^2 - 2 * vMu ) / ( 2 * exp(1) * vMu ) + vWLo <- ( dfOutput$ThresholdLow[1] ^2 - 2 * vMu ) / ( 2 * exp(1) * vMu ) + + vPredictYHi <- ( dfOutput$ThresholdHigh[1]^2-2* vMu) / (2*lambertW0( vWHi )) + vPredictYLo <- ( dfOutput$ThresholdLow[1]^2-2* vMu) / (2*lambertWm1( vWLo )) + vPredictY <- exp( vNewX * cModel$coefficients[2] + cModel$coefficients[1]) + vPredictYLo[ is.nan( vPredictYLo ) ] <- 0 + vPredictYHi[ is.nan( vPredictYHi ) ] <- 0 + + dfBounds <- data.frame( + LogExposure = vNewX, + MeanCount = vPredictY, + LowerCount = vPredictYLo, + UpperCount = vPredictYHi) + + return( dfBounds ) +} diff --git a/R/AE_Visualize.R b/R/AE_Visualize.R new file mode 100644 index 000000000..0ab761cc3 --- /dev/null +++ b/R/AE_Visualize.R @@ -0,0 +1,55 @@ +#' Safety Assessment - Site-level plot +#' +#' @param dfFlagged Flagged data frame generated by \code{\link{AE_Poisson_Flag}} +#' @param title Title for the plot +#' @param unit exposure time unit. Defaults to "weeks". +#' +#' @return site level plot object +#' +#' @import ggplot2 +#' +#' @export +AE_Visualize <- function( dfFlagged ,title = "", unit="weeks"){ + + ### Calculate upper and lower boundaries + dfBounds <- gsm::AE_Poisson_PredictBounds( dfFlagged ) + + ### Plot of data + p <- ggplot( + dfFlagged, + aes(x=LogExposure, y=TotalCount) + ) + + theme_bw(base_size=16) + + geom_point(size=2.5, shape=19) + + scale_x_continuous( + breaks=log(c(5,10,50, 100, 500, 1000, 5000, 10000)), + labels=c(5,10,50, 100, 500, 1000, 5000, 10000) + ) + + ggtitle( title ) + + xlab(paste0("Site Total Exposure (",unit," - log scale)")) + + ylab("Site Total Events") + + geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + + geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + + geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") + + # Make flagged points red and annotate site number + + vFlagDex <- which( dfFlagged$Flag != 0 ) + if( length( vFlagDex ) > 0 ){ + p<-p + geom_point( + data = dfFlagged[ vFlagDex ,] , + aes( x = LogExposure, y = TotalCount ), + col="red", + size=2.5, + shape=19) + + geom_text( + data = dfFlagged[ vFlagDex, ], + aes( x = LogExposure, y = TotalCount, label = SiteID), + vjust = 1.2, + col="red", + size=3.5 + ) + } + return(p) +} + diff --git a/man/AE_Poisson_PredictBounds.Rd b/man/AE_Poisson_PredictBounds.Rd new file mode 100644 index 000000000..61509f72d --- /dev/null +++ b/man/AE_Poisson_PredictBounds.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/AE_Poisson_PredictBounds.R +\name{AE_Poisson_PredictBounds} +\alias{AE_Poisson_PredictBounds} +\title{Safety Assessment - Calculate prediction bounds} +\usage{ +AE_Poisson_PredictBounds(dfOutput) +} +\arguments{ +\item{dfOutput}{data frame in format produced by \code{\link{AE_Poisson_Analyze}}} +} +\value{ +dataframe with prediction boundary curves +} +\description{ +Safety Assessment - Calculate prediction bounds +} diff --git a/man/AE_Visualize.Rd b/man/AE_Visualize.Rd new file mode 100644 index 000000000..6eee3942b --- /dev/null +++ b/man/AE_Visualize.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/AE_Visualize.R +\name{AE_Visualize} +\alias{AE_Visualize} +\title{Safety Assessment - Site-level plot} +\usage{ +AE_Visualize(dfFlagged, title = "", unit = "weeks") +} +\arguments{ +\item{dfFlagged}{Flagged data frame generated by \code{\link{AE_Poisson_Flag}}} + +\item{title}{Title for the plot} + +\item{unit}{exposure time unit. Defaults to "weeks".} +} +\value{ +site level plot object +} +\description{ +Safety Assessment - Site-level plot +} diff --git a/tests/testthat/test-AE_Visualize.R b/tests/testthat/test-AE_Visualize.R new file mode 100644 index 000000000..2afe30d56 --- /dev/null +++ b/tests/testthat/test-AE_Visualize.R @@ -0,0 +1,3 @@ +test_that("placeholder", { + expect_equal(2 * 2, 4) +}) From f3d019bf8d6d2aacfe255eebf6a0d4e225b8bc9f Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Wed, 23 Feb 2022 14:37:47 +0000 Subject: [PATCH 02/60] update documentation to pass checks --- R/AE_Poisson_PredictBounds.R | 2 +- R/AE_Visualize.R | 2 +- man/AE_Poisson_PredictBounds.Rd | 2 +- man/AE_Visualize.Rd | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/AE_Poisson_PredictBounds.R b/R/AE_Poisson_PredictBounds.R index bd901f331..9801cc1a2 100644 --- a/R/AE_Poisson_PredictBounds.R +++ b/R/AE_Poisson_PredictBounds.R @@ -1,6 +1,6 @@ #' Safety Assessment - Calculate prediction bounds #' -#' @param dfOutput data frame in format produced by \code{\link{AE_Poisson_Analyze}} +#' @param dfOutput data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}. #' #' @return dataframe with prediction boundary curves #' diff --git a/R/AE_Visualize.R b/R/AE_Visualize.R index 0ab761cc3..76201bb17 100644 --- a/R/AE_Visualize.R +++ b/R/AE_Visualize.R @@ -1,6 +1,6 @@ #' Safety Assessment - Site-level plot #' -#' @param dfFlagged Flagged data frame generated by \code{\link{AE_Poisson_Flag}} +#' @param dfFlagged Flagged data frame generated by \code{\link{AE_Assess}} when `bDataList` is FALSE. #' @param title Title for the plot #' @param unit exposure time unit. Defaults to "weeks". #' diff --git a/man/AE_Poisson_PredictBounds.Rd b/man/AE_Poisson_PredictBounds.Rd index 61509f72d..a96001e39 100644 --- a/man/AE_Poisson_PredictBounds.Rd +++ b/man/AE_Poisson_PredictBounds.Rd @@ -7,7 +7,7 @@ AE_Poisson_PredictBounds(dfOutput) } \arguments{ -\item{dfOutput}{data frame in format produced by \code{\link{AE_Poisson_Analyze}}} +\item{dfOutput}{data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}.} } \value{ dataframe with prediction boundary curves diff --git a/man/AE_Visualize.Rd b/man/AE_Visualize.Rd index 6eee3942b..12048d5f1 100644 --- a/man/AE_Visualize.Rd +++ b/man/AE_Visualize.Rd @@ -7,7 +7,7 @@ AE_Visualize(dfFlagged, title = "", unit = "weeks") } \arguments{ -\item{dfFlagged}{Flagged data frame generated by \code{\link{AE_Poisson_Flag}}} +\item{dfFlagged}{Flagged data frame generated by \code{\link{AE_Assess}} when \code{bDataList} is FALSE.} \item{title}{Title for the plot} From cbca516c1ba3b2284b2013674eaf5703e3fe0e4e Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Fri, 25 Feb 2022 15:53:21 -0800 Subject: [PATCH 03/60] made changes for IE_Map_Raw to handle column mapping arguments, also updated tests and test data --- R/IE_Assess.R | 6 +++ R/IE_Map_Raw.R | 33 ++++++++------ man/IE_Assess.Rd | 6 +++ man/IE_Map_Raw.Rd | 26 ++++++++--- tests/testthat/test_IE_Assess.R | 4 +- tests/testthat/test_IE_Map_Raw.R | 77 ++++++++++++++++++++------------ 6 files changed, 101 insertions(+), 51 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index cfce41c39..5d46f9256 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -34,6 +34,12 @@ #' ) #' #' ie_summary <- IE_Assess(dfInput) +#' +#' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +#' ie_input <- ie_input %>% filter(!is.na(.data$Count)) +#' +#' ie_summary2 <- IE_Assess(ie_input) +#' #' #' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. #' diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index dd10c87f7..ae4267d1a 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -12,22 +12,24 @@ #' The following columns are required: #' - `dfIE` #' - `SUBJID` - Unique subject ID -#' - `IECAT` - IE Category -#' - `IETEST` - Criterion Description (truncated) -#' - `IEORRES` - Incl criteria not met Excl criteria met. +#' - Value specified in strCategoryCol - IE Category; "IECAT" by default +#' - Value specified in strResultCol - Incl criteria not met Excl criteria met; "IEORRES_STD" by default #' - `dfRDSL` #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID #' -#' @param dfIE ie dataset with columns SUBJID IVID IECAT IETESTCD IEORRES +#' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID -#' @param vExpected Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". +#' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' +#' @param vCategoryValuess Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion"). +#' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". +#' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". #' #' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count #' #' @examples #' -#' dfInput <- IE_Map_Raw(clindata::raw_ie_a2, clindata::rawplus_rdsl) +#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') #' #' @import dplyr #' @@ -35,23 +37,26 @@ IE_Map_Raw <- function( dfIE = NULL, dfRDSL = NULL, - vExpected = c(0,1) + strCategoryCol = 'IECAT', + vCategoryValues = c("Inclusion","Exclusion"), + strResultCol = 'IEORRES_STD', + vExpectedResultValues = c(0,1) ){ ### Requires raw ie dataset if(is.null(dfIE)) stop("IE dataset not found") - if( ! all(c("SUBJID", "IECAT", "IETESTCD","IETEST", "IEORRES") %in% names(dfIE)) ) stop("SUBJID, IECAT, IETEST, IETESTCD, IEORRES columns are required in ie dataset" ) + if( ! all(c("SUBJID", strCategoryCol, strResultCol) %in% names(dfIE)) ) stop(paste0("SUBJID, ",strCategoryCol,", and " , strResultCol, " columns are required in ie dataset") ) if(is.null(dfRDSL)) stop("RDSL dataset not found") if( !(all(c("SubjectID","SiteID") %in% names(dfRDSL)))) stop("SubjectID and SiteID column are required in RDSL dataset" ) # filter records where SUBJID is missing and create basic flags dfIE_long <- dfIE %>% filter(.data$SUBJID !="")%>% - select(.data$SUBJID, .data$IECAT, .data$IETESTCD, .data$IETEST, .data$IEORRES) %>% - mutate(expected=ifelse(.data$IECAT=="Exclusion",vExpected[1],vExpected[2])) %>% - mutate(valid=.data$IEORRES==.data$expected)%>% - mutate(invalid=.data$IEORRES!=.data$expected)%>% - mutate(missing=!(.data$IEORRES %in% vExpected)) + select(.data$SUBJID, .data[[strCategoryCol]], .data[[strResultCol]]) %>% + mutate(expected=ifelse(.data[[strCategoryCol]] ==vCategoryValues[2],vExpectedResultValues[1],vExpectedResultValues[2])) %>% + mutate(valid=.data[[strResultCol]]==.data$expected)%>% + mutate(invalid=.data[[strResultCol]]!=.data$expected)%>% + mutate(missing=!(.data[[strResultCol]] %in% vExpectedResultValues)) # collapse long data to one record per participant dfIE_Subj <- dfIE_long %>% @@ -78,4 +83,4 @@ IE_Map_Raw <- function( if( nrow(missIE) > 0 ) warning("Not all SubjectID in IE found in RDSL") return(dfInput) -} \ No newline at end of file +} diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 08eec9b92..69f36b579 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -52,5 +52,11 @@ The Assessment ) ie_summary <- IE_Assess(dfInput) + + ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') + ie_input <- ie_input \%>\% filter(!is.na(.data$Count)) + + ie_summary2 <- IE_Assess(ie_input) + } diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index c4ea00b5a..58b775ae6 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -4,14 +4,27 @@ \alias{IE_Map_Raw} \title{Inclusion/Exclusion Assessment Mapping from Raw Data- Make Input Data} \usage{ -IE_Map_Raw(dfIE = NULL, dfRDSL = NULL, vExpected = c(0, 1)) +IE_Map_Raw( + dfIE = NULL, + dfRDSL = NULL, + strCategoryCol = "IECAT", + vCategoryValues = c("Inclusion", "Exclusion"), + strResultCol = "IEORRES_STD", + vExpectedResultValues = c(0, 1) +) } \arguments{ -\item{dfIE}{ie dataset with columns SUBJID IVID IECAT IETESTCD IEORRES} +\item{dfIE}{ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol.} \item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID SiteID} -\item{vExpected}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion".} +\item{strCategoryCol}{Name ofcCriteria category column. default = 'IECAT'} + +\item{strResultCol}{Name of criteria Result column. Default = "IEORRES_STD".} + +\item{vExpectedResultValues}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion".} + +\item{vCategoryValuess}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion").} } \value{ Data frame with one record per person data frame with columns: SubjectID, SiteID, Count @@ -30,9 +43,8 @@ The following columns are required: \item \code{dfIE} \itemize{ \item \code{SUBJID} - Unique subject ID -\item \code{IECAT} - IE Category -\item \code{IETEST} - Criterion Description (truncated) -\item \code{IEORRES} - Incl criteria not met Excl criteria met. +\item Value specified in strCategoryCol - IE Category; "IECAT" by default +\item Value specified in strResultCol - Incl criteria not met Excl criteria met; "IEORRES_STD" by default } \item \code{dfRDSL} \itemize{ @@ -44,6 +56,6 @@ The following columns are required: \examples{ -dfInput <- IE_Map_Raw(clindata::raw_ie_a2, clindata::rawplus_rdsl) +dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') } diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index c16b07afa..f579bffd1 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -1,8 +1,8 @@ -ie_input <- IE_Map_Raw(clindata::raw_ie_a2 , clindata::rawplus_rdsl ) %>% filter(!is.na(Count)) - +ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +ie_input <- ie_input %>% filter(!is.na(.data$Count)) test_that("summary df created as expected and has correct structure",{ ie_list <- IE_Assess(ie_input) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 1f6c8abdd..1ca3ecb9a 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -1,7 +1,7 @@ test_that("output created as expected and has correct structure",{ - ie_input <- IE_Map_Raw(clindata::raw_ie_a2 , clindata::rawplus_rdsl) + ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') expect_true(is.data.frame(ie_input)) expect_equal( @@ -18,7 +18,7 @@ test_that("incorrect inputs throw errors",{ test_that("incorrect inputs throw errors",{ expect_error(IE_Map_Raw(list(), list())) - expect_error(IE_Map_Raw( clindata::raw_ie_a2, list())) + expect_error(IE_Map_Raw( clindata::raw_ie_all, list(), strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_error(IE_Map_Raw(list())) expect_error(IE_Map_Raw("Hi","Mom")) }) @@ -27,48 +27,62 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( - clindata::raw_ie_a2 %>% rename(ID = SUBJID), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% rename(ID = SUBJID), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) #"INVID", "IECAT", "IETESTCD","IETEST", "IEORRES" expect_error( IE_Map_Raw( - clindata::raw_ie_a2 , - clindata::rawplus_rdsl%>% select(-SiteID) + clindata::raw_ie_all , + clindata::rawplus_rdsl_s%>% select(-SiteID), + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) expect_error( IE_Map_Raw( - clindata::raw_ie_a2 %>% select(-IECAT), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% select(-IECAT), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) expect_error( IE_Map_Raw( - clindata::raw_ie_a2 %>% select(-IETESTCD), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% select(-IETESTCD), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) expect_error( IE_Map_Raw( - clindata::raw_ie_a2 %>% select(-IETEST), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% select(-IETEST), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) expect_error( IE_Map_Raw( - clindata::raw_ie_a2 %>% select(-IEORRES), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% select(-IEORRES), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) expect_silent( IE_Map_Raw( - clindata::raw_ie_a2 %>% select(-PROJECT), - clindata::rawplus_rdsl + clindata::raw_ie_all %>% select(-PROJECT), + clindata::rawplus_rdsl_s, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' ) ) }) @@ -76,22 +90,29 @@ test_that("error given if required column not found",{ test_that("output is correct given clindata example input",{ -dfIE <- clindata::raw_ie_a2 +dfIE <- clindata::raw_ie_all dfIE$SUBJID <- as.character(dfIE$SUBJID) dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, - "0142", "X194X", - "0308", "X159X", - "0776", "X194X", - "1032", "X033X" ) + "0496", "X055X", + "0539", "X128X", + "1314", "X169X", + "1218", "X126X" ) + + -dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, - "0142", "X194X", 9, - "0308", "X159X", 9, - "0776", "X194X", 8, - "1032", "X033X", 9 ) +dfInput <- tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + "0496", "X055X", 15L, + "0539", "X128X", 15L, + "1314", "X169X", 14L, + "1218", "X126X", 14L +) + +expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) + + -expect_equal(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL), dfInput ) dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, @@ -112,7 +133,7 @@ dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, 2, 1, 2L, 4, 3, 1L ) -expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2), ignore_attr = TRUE) +expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) }) From cc825e327e72a1861a5287b71991b1d5df5aba05 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Fri, 25 Feb 2022 16:04:23 -0800 Subject: [PATCH 04/60] made change to IE_Assess example so that it could run without dependencies --- R/IE_Assess.R | 4 +++- man/IE_Assess.Rd | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index 5d46f9256..1fd549e66 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -36,7 +36,9 @@ #' ie_summary <- IE_Assess(dfInput) #' #' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -#' ie_input <- ie_input %>% filter(!is.na(.data$Count)) +#' +#' +#' ie_input <- na.omit(ie_input) #' #' ie_summary2 <- IE_Assess(ie_input) #' diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 69f36b579..235ca036d 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -54,7 +54,9 @@ The Assessment ie_summary <- IE_Assess(dfInput) ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') - ie_input <- ie_input \%>\% filter(!is.na(.data$Count)) + + + ie_input <- na.omit(ie_input) ie_summary2 <- IE_Assess(ie_input) From 89a2cadd475eda0f356818e293eb7f97b66b1011 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Mon, 28 Feb 2022 15:59:59 -0500 Subject: [PATCH 05/60] refactor ggplot code --- R/AE_Visualize.R | 55 --------------------------------------- R/Visualize_Poisson.R | 60 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 55 deletions(-) delete mode 100644 R/AE_Visualize.R create mode 100644 R/Visualize_Poisson.R diff --git a/R/AE_Visualize.R b/R/AE_Visualize.R deleted file mode 100644 index 76201bb17..000000000 --- a/R/AE_Visualize.R +++ /dev/null @@ -1,55 +0,0 @@ -#' Safety Assessment - Site-level plot -#' -#' @param dfFlagged Flagged data frame generated by \code{\link{AE_Assess}} when `bDataList` is FALSE. -#' @param title Title for the plot -#' @param unit exposure time unit. Defaults to "weeks". -#' -#' @return site level plot object -#' -#' @import ggplot2 -#' -#' @export -AE_Visualize <- function( dfFlagged ,title = "", unit="weeks"){ - - ### Calculate upper and lower boundaries - dfBounds <- gsm::AE_Poisson_PredictBounds( dfFlagged ) - - ### Plot of data - p <- ggplot( - dfFlagged, - aes(x=LogExposure, y=TotalCount) - ) + - theme_bw(base_size=16) + - geom_point(size=2.5, shape=19) + - scale_x_continuous( - breaks=log(c(5,10,50, 100, 500, 1000, 5000, 10000)), - labels=c(5,10,50, 100, 500, 1000, 5000, 10000) - ) + - ggtitle( title ) + - xlab(paste0("Site Total Exposure (",unit," - log scale)")) + - ylab("Site Total Events") + - geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + - geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + - geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") - - # Make flagged points red and annotate site number - - vFlagDex <- which( dfFlagged$Flag != 0 ) - if( length( vFlagDex ) > 0 ){ - p<-p + geom_point( - data = dfFlagged[ vFlagDex ,] , - aes( x = LogExposure, y = TotalCount ), - col="red", - size=2.5, - shape=19) + - geom_text( - data = dfFlagged[ vFlagDex, ], - aes( x = LogExposure, y = TotalCount, label = SiteID), - vjust = 1.2, - col="red", - size=3.5 - ) - } - return(p) -} - diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R new file mode 100644 index 000000000..29986aabb --- /dev/null +++ b/R/Visualize_Poisson.R @@ -0,0 +1,60 @@ +#' Site-level visualization of site-level Poisson Model results +#' +#' @param dfFlagged analyze_poisson results with flags added. +#' @param unit exposure time unit. Defaults to "days". +#' +#' @return site level plot object +#' +#' @examples +#' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfAnalyzed <- Analyze_Poisson( dfTransformed) +#' dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) +#' + +#' @import ggplot2 +#' +#' @export +AE_Visualize <- function( dfFlagged, unit="days"){ + + ### Calculate upper and lower boundaries + dfBounds <- gsm::AE_Poisson_PredictBounds( dfFlagged ) + + ### Plot of data + p <- ggplot( + dfFlagged, + aes( + x=LogExposure, + y=TotalCount, + color=as.factor(Flag)) + ) + + # Formatting + theme_bw() + + scale_x_continuous( + breaks=log(c(5,10,50, 100, 500, 1000, 5000, 10000)), + labels=c(5,10,50, 100, 500, 1000, 5000, 10000) + ) + + theme(legend.position = "none") + + scale_color_manual( + breaks = c("0", "-1", "1"), + values=c("#999999", "red", "red") + ) + + # Add chart elements + geom_point() + + xlab(paste0("Site Total Exposure (",unit," - log scale)")) + + ylab("Site Total Events") + + geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + + geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + + geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") + + geom_text( + data = dfFlagged%>%filter(Flag !=0), + aes( x = LogExposure, y = TotalCount, label = SiteID), + vjust = 1.5, + col="red", + size=3.5 + ) + + + return(p) +} + From 9fc4f6f9dba191242521c421deb2cc501be234df Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 11:18:12 -0500 Subject: [PATCH 06/60] refactor prediction bounds -> tidyverse --- NAMESPACE | 4 +-- R/AE_Poisson_PredictBounds.R | 41 ---------------------------- R/Analyze_Poisson_PredictBounds.R | 37 +++++++++++++++++++++++++ R/Visualize_Poisson.R | 17 ++++++------ man/AE_Poisson_PredictBounds.Rd | 17 ------------ man/AE_Visualize.Rd | 21 -------------- man/Analyze_Poisson_PredictBounds.Rd | 17 ++++++++++++ man/Visualize_Poisson.Rd | 28 +++++++++++++++++++ 8 files changed, 93 insertions(+), 89 deletions(-) delete mode 100644 R/AE_Poisson_PredictBounds.R create mode 100644 R/Analyze_Poisson_PredictBounds.R delete mode 100644 man/AE_Poisson_PredictBounds.Rd delete mode 100644 man/AE_Visualize.Rd create mode 100644 man/Analyze_Poisson_PredictBounds.Rd create mode 100644 man/Visualize_Poisson.Rd diff --git a/NAMESPACE b/NAMESPACE index 5bfde8e96..135e6917e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,11 +4,10 @@ export("%>%") export(AE_Assess) export(AE_Map_Adam) export(AE_Map_Raw) -export(AE_Poisson_PredictBounds) -export(AE_Visualize) export(Analyze_Chisq) export(Analyze_Fisher) export(Analyze_Poisson) +export(Analyze_Poisson_PredictBounds) export(Analyze_Wilcoxon) export(Consent_Assess) export(Consent_Map_Raw) @@ -20,6 +19,7 @@ export(PD_Assess) export(PD_Map_Raw) export(Summarize) export(Transform_EventCount) +export(Visualize_Poisson) import(dplyr) import(ggplot2) import(lamW) diff --git a/R/AE_Poisson_PredictBounds.R b/R/AE_Poisson_PredictBounds.R deleted file mode 100644 index 9801cc1a2..000000000 --- a/R/AE_Poisson_PredictBounds.R +++ /dev/null @@ -1,41 +0,0 @@ -#' Safety Assessment - Calculate prediction bounds -#' -#' @param dfOutput data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}. -#' -#' @return dataframe with prediction boundary curves -#' -#' @import lamW -#' -#' @export -AE_Poisson_PredictBounds <- function( dfOutput ){ - - cModel <- glm( - TotalCount ~ stats::offset(LogExposure), - family=poisson(link="log"), - data=dfOutput - ) - - vNewX <- seq( - min(dfOutput$LogExposure)-0.05, - max(dfOutput$LogExposure)+0.05, - by=0.05 - ) - - vMu <- as.numeric( exp( vNewX * cModel$coefficients[2] + cModel$coefficients[1] ) ) - vWHi <- ( dfOutput$ThresholdHigh[1] ^2 - 2 * vMu ) / ( 2 * exp(1) * vMu ) - vWLo <- ( dfOutput$ThresholdLow[1] ^2 - 2 * vMu ) / ( 2 * exp(1) * vMu ) - - vPredictYHi <- ( dfOutput$ThresholdHigh[1]^2-2* vMu) / (2*lambertW0( vWHi )) - vPredictYLo <- ( dfOutput$ThresholdLow[1]^2-2* vMu) / (2*lambertWm1( vWLo )) - vPredictY <- exp( vNewX * cModel$coefficients[2] + cModel$coefficients[1]) - vPredictYLo[ is.nan( vPredictYLo ) ] <- 0 - vPredictYHi[ is.nan( vPredictYHi ) ] <- 0 - - dfBounds <- data.frame( - LogExposure = vNewX, - MeanCount = vPredictY, - LowerCount = vPredictYLo, - UpperCount = vPredictYHi) - - return( dfBounds ) -} diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R new file mode 100644 index 000000000..b0a560369 --- /dev/null +++ b/R/Analyze_Poisson_PredictBounds.R @@ -0,0 +1,37 @@ +#' Safety Assessment - Calculate prediction bounds +#' +#' @param dfTransformed data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}. +#' +#' @return dataframe with prediction boundary curves +#' +#' @import lamW +#' +#' @export + +Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold ){ + dfTransformed$LogExposure <- log(dfTransformed$TotalExposure) + cModel <- glm( + TotalCount ~ stats::offset(LogExposure), + family=poisson(link="log"), + data=dfTransformed + ) + + dfBounds <- data.frame( + LogExposure = seq( + min(dfFlagged$LogExposure)-0.05, + max(dfFlagged$LogExposure)+0.05, + by=0.05 + )) %>% + mutate( vMu = as.numeric( exp( LogExposure * cModel$coefficients[2] + cModel$coefficients[1] ))) %>% + mutate( vWHi = (vThreshold[2]^2 - 2 * vMu) / ( 2 * exp(1) * vMu )) %>% + mutate( vWLo = (vThreshold[1]^2 - 2 * vMu) / ( 2 * exp(1) * vMu )) %>% + mutate( PredictYHigh = ( vThreshold[2]^2-2* vMu) / (2*lamW::lambertW0( vWHi ))) %>% + mutate( PredictYLo = ( vThreshold[1]^2-2* vMu) / (2*lamW::lambertWm1( vWLo ))) %>% + mutate( MeanCount = exp( LogExposure * cModel$coefficients[2] + cModel$coefficients[1])) %>% + mutate( LowerCount = if_else(is.nan( PredictYLo ), 0, PredictYLo )) %>% + mutate( UpperCount = if_else(is.nan( PredictYHigh ), 0, PredictYHigh )) %>% + select( LogExposure, MeanCount, LowerCount, UpperCount ) + + + return( dfBounds ) +} diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R index 29986aabb..da6e17b3e 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Poisson.R @@ -1,6 +1,7 @@ #' Site-level visualization of site-level Poisson Model results #' #' @param dfFlagged analyze_poisson results with flags added. +#' @param dfBounds data.frame giving prediction bounds for range of dfFlagged #' @param unit exposure time unit. Defaults to "days". #' #' @return site level plot object @@ -15,10 +16,7 @@ #' @import ggplot2 #' #' @export -AE_Visualize <- function( dfFlagged, unit="days"){ - - ### Calculate upper and lower boundaries - dfBounds <- gsm::AE_Poisson_PredictBounds( dfFlagged ) +Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ ### Plot of data p <- ggplot( @@ -43,9 +41,6 @@ AE_Visualize <- function( dfFlagged, unit="days"){ geom_point() + xlab(paste0("Site Total Exposure (",unit," - log scale)")) + ylab("Site Total Events") + - geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + - geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + - geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") + geom_text( data = dfFlagged%>%filter(Flag !=0), aes( x = LogExposure, y = TotalCount, label = SiteID), @@ -53,8 +48,14 @@ AE_Visualize <- function( dfFlagged, unit="days"){ col="red", size=3.5 ) - + if(!is.null(dfBounds)){ + p<-p+ + geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + + geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + + geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") + } + return(p) } diff --git a/man/AE_Poisson_PredictBounds.Rd b/man/AE_Poisson_PredictBounds.Rd deleted file mode 100644 index a96001e39..000000000 --- a/man/AE_Poisson_PredictBounds.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/AE_Poisson_PredictBounds.R -\name{AE_Poisson_PredictBounds} -\alias{AE_Poisson_PredictBounds} -\title{Safety Assessment - Calculate prediction bounds} -\usage{ -AE_Poisson_PredictBounds(dfOutput) -} -\arguments{ -\item{dfOutput}{data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}.} -} -\value{ -dataframe with prediction boundary curves -} -\description{ -Safety Assessment - Calculate prediction bounds -} diff --git a/man/AE_Visualize.Rd b/man/AE_Visualize.Rd deleted file mode 100644 index 12048d5f1..000000000 --- a/man/AE_Visualize.Rd +++ /dev/null @@ -1,21 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/AE_Visualize.R -\name{AE_Visualize} -\alias{AE_Visualize} -\title{Safety Assessment - Site-level plot} -\usage{ -AE_Visualize(dfFlagged, title = "", unit = "weeks") -} -\arguments{ -\item{dfFlagged}{Flagged data frame generated by \code{\link{AE_Assess}} when \code{bDataList} is FALSE.} - -\item{title}{Title for the plot} - -\item{unit}{exposure time unit. Defaults to "weeks".} -} -\value{ -site level plot object -} -\description{ -Safety Assessment - Site-level plot -} diff --git a/man/Analyze_Poisson_PredictBounds.Rd b/man/Analyze_Poisson_PredictBounds.Rd new file mode 100644 index 000000000..131ded7d5 --- /dev/null +++ b/man/Analyze_Poisson_PredictBounds.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Analyze_Poisson_PredictBounds.R +\name{Analyze_Poisson_PredictBounds} +\alias{Analyze_Poisson_PredictBounds} +\title{Safety Assessment - Calculate prediction bounds} +\usage{ +Analyze_Poisson_PredictBounds(dfTransformed, vThreshold) +} +\arguments{ +\item{dfTransformed}{data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}.} +} +\value{ +dataframe with prediction boundary curves +} +\description{ +Safety Assessment - Calculate prediction bounds +} diff --git a/man/Visualize_Poisson.Rd b/man/Visualize_Poisson.Rd new file mode 100644 index 000000000..681c4d3bb --- /dev/null +++ b/man/Visualize_Poisson.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualize_Poisson.R +\name{Visualize_Poisson} +\alias{Visualize_Poisson} +\title{Site-level visualization of site-level Poisson Model results} +\usage{ +Visualize_Poisson(dfFlagged, dfBounds = NULL, unit = "days") +} +\arguments{ +\item{dfFlagged}{analyze_poisson results with flags added.} + +\item{dfBounds}{data.frame giving prediction bounds for range of dfFlagged} + +\item{unit}{exposure time unit. Defaults to "days".} +} +\value{ +site level plot object +} +\description{ +Site-level visualization of site-level Poisson Model results +} +\examples{ +dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfAnalyzed <- Analyze_Poisson( dfTransformed) +dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) + +} From d428ff5152093c1ba3dc2882d9796d9d71b8a527 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 11:51:38 -0500 Subject: [PATCH 07/60] clear checks --- R/Analyze_Poisson_PredictBounds.R | 27 ++++++++++++++------------- R/Visualize_Poisson.R | 16 ++++++++-------- man/Analyze_Poisson_PredictBounds.Rd | 4 +++- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R index b0a560369..b962c2226 100644 --- a/R/Analyze_Poisson_PredictBounds.R +++ b/R/Analyze_Poisson_PredictBounds.R @@ -1,7 +1,8 @@ #' Safety Assessment - Calculate prediction bounds #' -#' @param dfTransformed data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}. -#' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. +#' @param vThreshold Residual thresholds used to calculating upper and lower bounds. + #' @return dataframe with prediction boundary curves #' #' @import lamW @@ -18,19 +19,19 @@ Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold ){ dfBounds <- data.frame( LogExposure = seq( - min(dfFlagged$LogExposure)-0.05, - max(dfFlagged$LogExposure)+0.05, + min(dfTransformed$LogExposure)-0.05, + max(dfTransformed$LogExposure)+0.05, by=0.05 )) %>% - mutate( vMu = as.numeric( exp( LogExposure * cModel$coefficients[2] + cModel$coefficients[1] ))) %>% - mutate( vWHi = (vThreshold[2]^2 - 2 * vMu) / ( 2 * exp(1) * vMu )) %>% - mutate( vWLo = (vThreshold[1]^2 - 2 * vMu) / ( 2 * exp(1) * vMu )) %>% - mutate( PredictYHigh = ( vThreshold[2]^2-2* vMu) / (2*lamW::lambertW0( vWHi ))) %>% - mutate( PredictYLo = ( vThreshold[1]^2-2* vMu) / (2*lamW::lambertWm1( vWLo ))) %>% - mutate( MeanCount = exp( LogExposure * cModel$coefficients[2] + cModel$coefficients[1])) %>% - mutate( LowerCount = if_else(is.nan( PredictYLo ), 0, PredictYLo )) %>% - mutate( UpperCount = if_else(is.nan( PredictYHigh ), 0, PredictYHigh )) %>% - select( LogExposure, MeanCount, LowerCount, UpperCount ) + mutate( vMu = as.numeric( exp( .data$LogExposure * cModel$coefficients[2] + cModel$coefficients[1] ))) %>% + mutate( vWHi = (vThreshold[2]^2 - 2 * .data$vMu) / ( 2 * exp(1) * .data$vMu )) %>% + mutate( vWLo = (vThreshold[1]^2 - 2 * .data$vMu) / ( 2 * exp(1) * .data$vMu )) %>% + mutate( PredictYHigh = ( vThreshold[2]^2-2* .data$vMu) / (2*lamW::lambertW0( .data$vWHi ))) %>% + mutate( PredictYLo = ( vThreshold[1]^2-2* .data$vMu) / (2*lamW::lambertWm1( .data$vWLo ))) %>% + mutate( MeanCount = exp( .data$LogExposure * cModel$coefficients[2] + cModel$coefficients[1])) %>% + mutate( LowerCount = if_else(is.nan( .data$PredictYLo ), 0, .data$PredictYLo )) %>% + mutate( UpperCount = if_else(is.nan( .data$PredictYHigh ), 0, .data$PredictYHigh )) %>% + select( .data$LogExposure, .data$MeanCount, .data$LowerCount, .data$UpperCount ) return( dfBounds ) diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R index da6e17b3e..cb228e8a5 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Poisson.R @@ -22,9 +22,9 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ p <- ggplot( dfFlagged, aes( - x=LogExposure, - y=TotalCount, - color=as.factor(Flag)) + x=.data$LogExposure, + y=.data$TotalCount, + color=as.factor(.data$Flag)) ) + # Formatting theme_bw() + @@ -42,8 +42,8 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ xlab(paste0("Site Total Exposure (",unit," - log scale)")) + ylab("Site Total Events") + geom_text( - data = dfFlagged%>%filter(Flag !=0), - aes( x = LogExposure, y = TotalCount, label = SiteID), + data = dfFlagged%>%filter(.data$Flag !=0), + aes( x = .data$LogExposure, y = .data$TotalCount, label = .data$SiteID), vjust = 1.5, col="red", size=3.5 @@ -51,9 +51,9 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ if(!is.null(dfBounds)){ p<-p+ - geom_line( data = dfBounds, aes( x = LogExposure, y = MeanCount), color="red") + - geom_line( data = dfBounds, aes( x = LogExposure, y = LowerCount), color="red", linetype="dashed") + - geom_line( data = dfBounds, aes( x = LogExposure, y = UpperCount), color="red", linetype="dashed") + geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$MeanCount), color="red") + + geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$LowerCount), color="red", linetype="dashed") + + geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$UpperCount), color="red", linetype="dashed") } return(p) diff --git a/man/Analyze_Poisson_PredictBounds.Rd b/man/Analyze_Poisson_PredictBounds.Rd index 131ded7d5..99fcc402a 100644 --- a/man/Analyze_Poisson_PredictBounds.Rd +++ b/man/Analyze_Poisson_PredictBounds.Rd @@ -7,7 +7,9 @@ Analyze_Poisson_PredictBounds(dfTransformed, vThreshold) } \arguments{ -\item{dfTransformed}{data frame in format produced by \code{\link{AE_Map_Adam}} or \code{\link{AE_Map_Raw}}.} +\item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}.} + +\item{vThreshold}{Residual thresholds used to calculating upper and lower bounds.} } \value{ dataframe with prediction boundary curves From 375a39a0d10647deafa27cf863eb089fe0dae96f Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 1 Mar 2022 12:09:30 -0800 Subject: [PATCH 08/60] switched join in IE_Map_Raw from left to inner so that it will only create complete records --- R/IE_Assess.R | 6 ++---- R/IE_Map_Raw.R | 12 +++++++----- man/IE_Assess.Rd | 6 ++---- man/IE_Map_Raw.Rd | 7 ++++--- tests/testthat/test_IE_Assess.R | 4 ++-- tests/testthat/test_IE_Map_Raw.R | 2 +- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index 1fd549e66..20739dbfb 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -35,10 +35,8 @@ #' #' ie_summary <- IE_Assess(dfInput) #' -#' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -#' -#' -#' ie_input <- na.omit(ie_input) +#' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, +#' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') #' #' ie_summary2 <- IE_Assess(ie_input) #' diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index ae4267d1a..2fe0f6a55 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -21,7 +21,7 @@ #' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID #' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' -#' @param vCategoryValuess Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion"). +#' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion"). #' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". #' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". #' @@ -29,7 +29,8 @@ #' #' @examples #' -#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, +#' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') #' #' @import dplyr #' @@ -72,15 +73,16 @@ IE_Map_Raw <- function( select(.data$SubjectID, .data$Count) %>% ungroup() + missIE <- anti_join( dfIE_Subj, dfRDSL, by="SubjectID") + if( nrow(missIE) > 0 ) warning("Not all SubjectID in IE found in RDSL") + # merge IE and RDSL dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID)%>% - left_join(dfIE_Subj, by="SubjectID") %>% + inner_join(dfIE_Subj, by="SubjectID") %>% select(.data$SubjectID, .data$SiteID, .data$Count) #Throw warning if a an ID in IE isn't found in RDSL - missIE <- anti_join( dfIE_Subj, dfRDSL, by="SubjectID") - if( nrow(missIE) > 0 ) warning("Not all SubjectID in IE found in RDSL") return(dfInput) } diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 235ca036d..0548e79ed 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -53,10 +53,8 @@ The Assessment ie_summary <- IE_Assess(dfInput) - ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') - - - ie_input <- na.omit(ie_input) + ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') ie_summary2 <- IE_Assess(ie_input) diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 58b775ae6..0eed3e0ec 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -20,11 +20,11 @@ IE_Map_Raw( \item{strCategoryCol}{Name ofcCriteria category column. default = 'IECAT'} +\item{vCategoryValues}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion").} + \item{strResultCol}{Name of criteria Result column. Default = "IEORRES_STD".} \item{vExpectedResultValues}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion".} - -\item{vCategoryValuess}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion").} } \value{ Data frame with one record per person data frame with columns: SubjectID, SiteID, Count @@ -56,6 +56,7 @@ The following columns are required: \examples{ -dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') } diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index f579bffd1..06e54089b 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -1,8 +1,8 @@ -ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -ie_input <- ie_input %>% filter(!is.na(.data$Count)) +ie_input <- suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) + test_that("summary df created as expected and has correct structure",{ ie_list <- IE_Assess(ie_input) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 1ca3ecb9a..2e60bc9cc 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -1,7 +1,7 @@ test_that("output created as expected and has correct structure",{ - ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl_s, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') + ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_true(is.data.frame(ie_input)) expect_equal( From b53168ca5a2ba227302388a3f2b2753a1e8c82b0 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 16:50:37 -0500 Subject: [PATCH 09/60] add flexible mapping for Score col. fix #212 --- R/Summarize.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/R/Summarize.R b/R/Summarize.R index 3d5601466..265f35d04 100644 --- a/R/Summarize.R +++ b/R/Summarize.R @@ -3,6 +3,7 @@ #' Create a concise summary of assessment results that is easy to aggregate across assessments #' #' @param dfFlagged data frame in format produced by \code{\link{Flag}} +#' @param strScoreCol column from analysis results to be copied to `dfSummary$Score` #' @param cAssessment brief description of current assessment #' @param cLabel brief description of line item in current assessment #' @@ -19,17 +20,18 @@ #' #' @export -Summarize <- function( dfFlagged , cAssessment="", cLabel=""){ +Summarize <- function( dfFlagged , strScoreCol="PValue", cAssessment="", cLabel=""){ stopifnot( is.data.frame(dfFlagged), is.character(cAssessment), is.character(cLabel), - all(c("SiteID", "N", "PValue", "Flag") %in% names(dfFlagged)) + all(c("SiteID", "N", "Flag",strScoreCol) %in% names(dfFlagged)) ) dfSummary <- dfFlagged %>% mutate(Assessment = cAssessment) %>% mutate(Label = cLabel) %>% - select(.data$Assessment,.data$Label, .data$SiteID,.data$N, .data$PValue, .data$Flag) %>% + rename(Score = strScoreCol) + select(.data$Assessment,.data$Label, .data$SiteID,.data$N, .data$Flag) %>% arrange(.data$PValue) return(dfSummary) From 9f84983352e2894684a254866c9d2bd9294f9db1 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 16:51:10 -0500 Subject: [PATCH 10/60] Update Poisson analyze docs. #108 --- R/Analyze_Poisson.R | 20 +++++++--------- R/Analyze_Poisson_PredictBounds.R | 39 ++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/R/Analyze_Poisson.R b/R/Analyze_Poisson.R index 9b347698e..a3da6c2ae 100644 --- a/R/Analyze_Poisson.R +++ b/R/Analyze_Poisson.R @@ -1,14 +1,12 @@ -#' AE Poisson Assessment - Analysis -#' -#' Adds columns for site-level statistical assessment of distribution of reported safety outcomes +#' Poisson Analysis - Site Residuals #' #' @details #' -#' Fits a Poisson Model to site-level data. +#' Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. #' #' @section Statistical Methods: #' -#' TODO Coming soon ... +#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Site-level residuals are calculated `stats::predict.glm` via `broom::augment`. #' #' @section Data Specification: #' @@ -18,12 +16,12 @@ #' - `TotalCount` - Number of Events #' - `TotalExposure` - Number of days of exposure #' -#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include -#' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. +#' #' @importFrom stats glm offset poisson pnorm #' @importFrom broom augment #' -#' @return input data frame with columns added for "Residuals", "PredictedCount" and "PValue" +#' @return input data frame with columns added for "Residuals" and "PredictedCount" #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) @@ -36,7 +34,7 @@ Analyze_Poisson <- function( dfTransformed ){ stopifnot( is.data.frame(dfTransformed), - all(c("SiteID", "N", "TotalExposure", "TotalCount", "Rate") %in% names(dfTransformed)) + all(c("SiteID", "N", "TotalExposure", "TotalCount") %in% names(dfTransformed)) ) dfModel <- dfTransformed %>% mutate(LogExposure = log( .data$TotalExposure) ) @@ -51,10 +49,8 @@ Analyze_Poisson <- function( dfTransformed ){ Residuals=.data$.resid, PredictedCount=.data$.fitted, ) %>% - mutate(PValue = stats::pnorm( abs(.data$Residuals) , lower.tail=F ) * 2) %>% + select(.data$SiteID, .data$N, .data$TotalExposure, .data$TotalCount, .data$Rate, .data$Residuals, .data$PredictedCount) %>% arrange(.data$Residuals) - # Note that the PValue calculation is a non-standard approximation and might be more accurately labeled a "standardized estimate" rather than a formal p-value. - return(dfAnalyzed) } diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R index b962c2226..b4233a0da 100644 --- a/R/Analyze_Poisson_PredictBounds.R +++ b/R/Analyze_Poisson_PredictBounds.R @@ -1,15 +1,38 @@ -#' Safety Assessment - Calculate prediction bounds +#' Poisson Analysis - Predicted Boundaries +#' +#' @details #' -#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. -#' @param vThreshold Residual thresholds used to calculating upper and lower bounds. - -#' @return dataframe with prediction boundary curves -#' -#' @import lamW +#' Fits a Poisson model to site level data and then calculates predicted count values and upper- and lower- bounds for across the full range of exposure values. +#' +#' @section Statistical Methods: +#' +#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Upper and lower boundary values are then calculated using the method described here TODO: Add link. In short, +#' +#' @section Data Specification: +#' +#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +#' - `SubjectID` - Unique subject ID +#' - `SiteID` - Site ID +#' - `TotalCount` - Number of Events +#' - `TotalExposure` - Number of days of exposure #' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. +#' @param vThreshold upper and lower boundaries in residual space. Should be identical to the threhsolds used AE_Assess(). +#' +#' @importFrom stats glm offset poisson pnorm +#' @importFrom broom augment +#' @importFrom lamW lambertW0 lambertWm1 +#' +#' @return data frame containing predicted boundary values with upper and lower bounds across the range of observed values +#' +#' @examples +#' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) +#' #' @export -Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold ){ +Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold=c(-5,5)){ dfTransformed$LogExposure <- log(dfTransformed$TotalExposure) cModel <- glm( TotalCount ~ stats::offset(LogExposure), From 9c686b1b956bc70ac0ebcc65df6336704472e1e5 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 17:12:58 -0500 Subject: [PATCH 11/60] start clearing checks --- NAMESPACE | 3 ++- R/AE_Assess.R | 5 ++-- R/Analyze_Poisson_PredictBounds.R | 2 +- R/Consent_Assess.R | 4 +-- R/IE_Assess.R | 4 +-- R/PD_Assess.R | 5 ++-- R/Summarize.R | 6 ++--- man/Analyze_Poisson.Rd | 12 ++++----- man/Analyze_Poisson_PredictBounds.Rd | 39 +++++++++++++++++++++++----- man/Summarize.Rd | 4 ++- 10 files changed, 58 insertions(+), 26 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 135e6917e..cc47257d6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -22,10 +22,11 @@ export(Transform_EventCount) export(Visualize_Poisson) import(dplyr) import(ggplot2) -import(lamW) import(lubridate) importFrom(broom,augment) importFrom(broom,glance) +importFrom(lamW,lambertW0) +importFrom(lamW,lambertWm1) importFrom(magrittr,"%>%") importFrom(purrr,map) importFrom(purrr,map_df) diff --git a/R/AE_Assess.R b/R/AE_Assess.R index 11c22d94e..ce578ea5a 100644 --- a/R/AE_Assess.R +++ b/R/AE_Assess.R @@ -64,6 +64,8 @@ AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bD } lAssess$dfAnalyzed <- gsm::Analyze_Poisson( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'Residuals', vThreshold =vThreshold) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol = 'Residuals', cAssessment="Safety", cLabel= cLabel) + } else if(cMethod=="wilcoxon"){ if(is.null(vThreshold)){ vThreshold = c(0.0001,NA) @@ -77,10 +79,9 @@ AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bD } lAssess$dfAnalyzed <- gsm::Analyze_Wilcoxon( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'PValue', vThreshold =vThreshold, strValueColumn = 'Estimate') + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) } - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) - if(bDataList){ return(lAssess) } else { diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R index b4233a0da..3221f3fec 100644 --- a/R/Analyze_Poisson_PredictBounds.R +++ b/R/Analyze_Poisson_PredictBounds.R @@ -28,7 +28,7 @@ #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) #' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) -#' dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) +#' dfBounds <- Analyze_Poisson_PredictBounds(dfTransformed, c(-5,5)) #' #' @export diff --git a/R/Consent_Assess.R b/R/Consent_Assess.R index 8f4c637b8..f8b053716 100644 --- a/R/Consent_Assess.R +++ b/R/Consent_Assess.R @@ -52,9 +52,9 @@ Consent_Assess <- function( dfInput, nThreshold=0.5, cLabel="", bDataList=FALSE lAssess <- list() lAssess$dfInput <- dfInput lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = 'Count' ) - lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(PValue = NA) %>% mutate(Estimate = .data$TotalCount) + lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(Estimate = .data$TotalCount) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed ,vThreshold = c(NA,nThreshold), strColumn = "TotalCount" ) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Main Consent", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", cAssessment="Main Consent", cLabel= cLabel) if(bDataList){ return(lAssess) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index cfce41c39..40c3fd7a3 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -52,9 +52,9 @@ IE_Assess <- function( dfInput, nThreshold=0.5, cLabel="", bDataList=FALSE){ lAssess <- list() lAssess$dfInput <- dfInput lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = "Count") - lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(PValue = NA) %>% mutate(Estimate = .data$TotalCount) + lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(Estimate = .data$TotalCount) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , vThreshold = c(NA,nThreshold), strColumn = "Estimate" ) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Inclusion/Exclusion", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", cAssessment="Inclusion/Exclusion", cLabel= cLabel) if(bDataList){ return(lAssess) diff --git a/R/PD_Assess.R b/R/PD_Assess.R index 732e1bea2..d50f21a38 100644 --- a/R/PD_Assess.R +++ b/R/PD_Assess.R @@ -65,6 +65,8 @@ PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="p lAssess$dfAnalyzed <- gsm::Analyze_Poisson( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'Residuals', vThreshold =vThreshold) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="Residuals", cAssessment="Safety", cLabel= cLabel) + } else if(cMethod=="wilcoxon"){ if(is.null(vThreshold)){ vThreshold = c(0.0001,NA) @@ -78,10 +80,9 @@ PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="p } lAssess$dfAnalyzed <- gsm::Analyze_Wilcoxon( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'PValue', vThreshold =vThreshold) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) } - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) - if(bDataList){ return(lAssess) } else { diff --git a/R/Summarize.R b/R/Summarize.R index 265f35d04..6da11f241 100644 --- a/R/Summarize.R +++ b/R/Summarize.R @@ -30,9 +30,9 @@ Summarize <- function( dfFlagged , strScoreCol="PValue", cAssessment="", cLabel= dfSummary <- dfFlagged %>% mutate(Assessment = cAssessment) %>% mutate(Label = cLabel) %>% - rename(Score = strScoreCol) - select(.data$Assessment,.data$Label, .data$SiteID,.data$N, .data$Flag) %>% - arrange(.data$PValue) + rename(Score = strScoreCol)%>% + select(.data$Assessment,.data$Label, .data$SiteID,.data$N, .data$Score, .data$Flag) %>% + arrange(.data$Score) return(dfSummary) } diff --git a/man/Analyze_Poisson.Rd b/man/Analyze_Poisson.Rd index 2c99b9066..b7ac646df 100644 --- a/man/Analyze_Poisson.Rd +++ b/man/Analyze_Poisson.Rd @@ -2,26 +2,26 @@ % Please edit documentation in R/Analyze_Poisson.R \name{Analyze_Poisson} \alias{Analyze_Poisson} -\title{AE Poisson Assessment - Analysis} +\title{Poisson Analysis - Site Residuals} \usage{ Analyze_Poisson(dfTransformed) } \arguments{ -\item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}. Must include} +\item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure.} } \value{ -input data frame with columns added for "Residuals", "PredictedCount" and "PValue" +input data frame with columns added for "Residuals" and "PredictedCount" } \description{ -Adds columns for site-level statistical assessment of distribution of reported safety outcomes +Poisson Analysis - Site Residuals } \details{ -Fits a Poisson Model to site-level data. +Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. } \section{Statistical Methods}{ -TODO Coming soon ... +This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the \code{stats} package by fitting a \code{glm} model with family set to \code{poisson} using a "log" link. Site-level residuals are calculated \code{stats::predict.glm} via \code{broom::augment}. } \section{Data Specification}{ diff --git a/man/Analyze_Poisson_PredictBounds.Rd b/man/Analyze_Poisson_PredictBounds.Rd index 99fcc402a..cc5def38c 100644 --- a/man/Analyze_Poisson_PredictBounds.Rd +++ b/man/Analyze_Poisson_PredictBounds.Rd @@ -2,18 +2,45 @@ % Please edit documentation in R/Analyze_Poisson_PredictBounds.R \name{Analyze_Poisson_PredictBounds} \alias{Analyze_Poisson_PredictBounds} -\title{Safety Assessment - Calculate prediction bounds} +\title{Poisson Analysis - Predicted Boundaries} \usage{ -Analyze_Poisson_PredictBounds(dfTransformed, vThreshold) +Analyze_Poisson_PredictBounds(dfTransformed, vThreshold = c(-5, 5)) } \arguments{ -\item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}.} +\item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure.} -\item{vThreshold}{Residual thresholds used to calculating upper and lower bounds.} +\item{vThreshold}{upper and lower boundaries in residual space. Should be identical to the threhsolds used AE_Assess().} } \value{ -dataframe with prediction boundary curves +data frame containing predicted boundary values with upper and lower bounds across the range of observed values } \description{ -Safety Assessment - Calculate prediction bounds +Poisson Analysis - Predicted Boundaries +} +\details{ +Fits a Poisson model to site level data and then calculates predicted count values and upper- and lower- bounds for across the full range of exposure values. +} +\section{Statistical Methods}{ + + +This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the \code{stats} package by fitting a \code{glm} model with family set to \code{poisson} using a "log" link. Upper and lower boundary values are then calculated using the method described here TODO: Add link. In short, +} + +\section{Data Specification}{ + + +The input data (\code{ dfTransformed}) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +\itemize{ +\item \code{SubjectID} - Unique subject ID +\item \code{SiteID} - Site ID +\item \code{TotalCount} - Number of Events +\item \code{TotalExposure} - Number of days of exposure +} +} + +\examples{ +dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfBounds <- Analyze_Poisson_PredictBounds(dfTransformed, c(-5,5)) + } diff --git a/man/Summarize.Rd b/man/Summarize.Rd index 6dc07649b..47aa9f4c0 100644 --- a/man/Summarize.Rd +++ b/man/Summarize.Rd @@ -4,11 +4,13 @@ \alias{Summarize} \title{Make Summary Data Frame} \usage{ -Summarize(dfFlagged, cAssessment = "", cLabel = "") +Summarize(dfFlagged, strScoreCol = "PValue", cAssessment = "", cLabel = "") } \arguments{ \item{dfFlagged}{data frame in format produced by \code{\link{Flag}}} +\item{strScoreCol}{column from analysis results to be copied to \code{dfSummary$Score}} + \item{cAssessment}{brief description of current assessment} \item{cLabel}{brief description of line item in current assessment} From 6cc7a0439400f0919ba3c4ebdb6882e523dcd23e Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 1 Mar 2022 15:09:03 -0800 Subject: [PATCH 12/60] forgot to update all clindata::rawplus_rdsl_s to clindata::rawplus_rdsl --- tests/testthat/test_IE_Map_Raw.R | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 2e60bc9cc..13198fbfd 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -28,7 +28,7 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all %>% rename(ID = SUBJID), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) @@ -37,7 +37,7 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all , - clindata::rawplus_rdsl_s%>% select(-SiteID), + clindata::rawplus_rdsl%>% select(-SiteID), strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) @@ -46,7 +46,7 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IECAT), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) @@ -55,7 +55,7 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IETESTCD), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) @@ -63,7 +63,7 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IETEST), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) @@ -72,18 +72,21 @@ test_that("error given if required column not found",{ expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IEORRES), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) + expect_silent( + suppressWarnings( IE_Map_Raw( clindata::raw_ie_all %>% select(-PROJECT), - clindata::rawplus_rdsl_s, + clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) + ) ) }) From 288d9aa4c47de8f037f9ac1ee485e308763dc010 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 1 Mar 2022 15:37:52 -0800 Subject: [PATCH 13/60] added some error handling + tests for vCategoryValues and vExpectedResultValues in IE_Map_Raw --- R/IE_Map_Raw.R | 6 ++++ tests/testthat/test_IE_Map_Raw.R | 47 +++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 2fe0f6a55..1026a827d 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -50,6 +50,12 @@ IE_Map_Raw <- function( if(is.null(dfRDSL)) stop("RDSL dataset not found") if( !(all(c("SubjectID","SiteID") %in% names(dfRDSL)))) stop("SubjectID and SiteID column are required in RDSL dataset" ) + stopifnot( + "length of vExpectedResultValues is not equal to 2"= (length( vExpectedResultValues) ==2), + "length of vCategoryValues is not equal to 2"= (length( vCategoryValues) ==2) + + ) + # filter records where SUBJID is missing and create basic flags dfIE_long <- dfIE %>% filter(.data$SUBJID !="")%>% diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 13198fbfd..7bb2b4072 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -77,7 +77,7 @@ test_that("error given if required column not found",{ strResultCol = 'IEORRES' ) ) - + expect_silent( suppressWarnings( IE_Map_Raw( @@ -90,6 +90,51 @@ test_that("error given if required column not found",{ ) }) +test_that("icorrect strCategoryCol or strResultCol throw errors",{ + # test these as incorrect inputs + # strCategoryCol = 'IECAT', + # vCategoryValues = c("Inclusion","Exclusion"), + # strResultCol = 'IEORRES_STD', + # vExpectedResultValues = c(0,1) + + expect_error( + suppressWarnings(IE_Map_Raw( + clindata::raw_ie_all, + clindata::rawplus_rdsl, + strCategoryCol = 'Not_A_Name', + strResultCol = 'IEORRES' + )) + ) + + expect_error( + suppressWarnings(IE_Map_Raw( + clindata::raw_ie_all, + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + strResultCol = 'Not_A_Name' + )) + ) + + expect_error( + suppressWarnings(IE_Map_Raw( + clindata::raw_ie_all, + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES', + vExpectedResultValues = c("A",1,3) + )) + ) + + expect_error( + suppressWarnings(IE_Map_Raw( + clindata::raw_ie_all, + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES', + vCategoryValues = c("Inclusion","Exclusion", "Illusion") + )) + ) +}) test_that("output is correct given clindata example input",{ From 896f4423eb1c6c29a8dbb7972b0488f6975636b5 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 19:18:38 -0500 Subject: [PATCH 14/60] update tests --- tests/testthat/test_AE_Assess.R | 2 +- tests/testthat/test_Consent_Assess.R | 6 ++---- tests/testthat/test_Flag.R | 6 +++--- tests/testthat/test_IE_Assess.R | 4 ++-- tests/testthat/test_PD_Assess.R | 2 +- tests/testthat/test_Summarize.R | 4 ++-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/testthat/test_AE_Assess.R b/tests/testthat/test_AE_Assess.R index 06e27c6ae..097372a30 100644 --- a/tests/testthat/test_AE_Assess.R +++ b/tests/testthat/test_AE_Assess.R @@ -7,7 +7,7 @@ ae_input <- AE_Map_Adam( test_that("summary df created as expected and has correct structure",{ ae_assessment <- AE_Assess(ae_input) expect_true(is.data.frame(ae_assessment)) - expect_equal(names(ae_assessment),c("Assessment","Label", "SiteID", "N", "PValue", "Flag")) + expect_equal(names(ae_assessment),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) test_that("list of df created when bDataList=TRUE",{ diff --git a/tests/testthat/test_Consent_Assess.R b/tests/testthat/test_Consent_Assess.R index 8133c466a..c0e87faf4 100644 --- a/tests/testthat/test_Consent_Assess.R +++ b/tests/testthat/test_Consent_Assess.R @@ -15,12 +15,10 @@ dfRDSL_test <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, consent_input <- Consent_Map_Raw(dfConsent = dfConsent, dfRDSL= dfRDSL_test) - - test_that("summary df created as expected and has correct structure",{ consent_list <- Consent_Assess(consent_input) expect_true(is.data.frame(consent_list)) - expect_equal(names(consent_list),c("Assessment","Label", "SiteID", "N", "PValue", "Flag")) + expect_equal(names(consent_list),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) test_that("list of df created when bDataList=TRUE",{ @@ -50,7 +48,7 @@ consent_summary <- Consent_Assess(consent_input, bDataList=FALSE) target_output <- tibble::tribble( - ~Assessment, ~Label, ~SiteID, ~N, ~PValue, ~Flag, + ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, "Main Consent", "", 1, 1L, NA, 1, "Main Consent", "", 2, 2L, NA, 1, "Main Consent", "", 3, 1L, NA, 1 diff --git a/tests/testthat/test_Flag.R b/tests/testthat/test_Flag.R index 63a92081d..64e33d1f2 100644 --- a/tests/testthat/test_Flag.R +++ b/tests/testthat/test_Flag.R @@ -9,10 +9,10 @@ ae_anly_wilcoxon <- Analyze_Wilcoxon(ae_prep, strOutcome="Rate") test_that("output created as expected and has correct structure",{ - flag <- Flag(ae_anly) + flag <- Flag(ae_anly_wilcoxon) expect_true(is.data.frame(flag)) expect_equal(sort(unique(ae_input$SiteID)), sort(flag$SiteID)) - expect_true(all(names(ae_anly) %in% names(flag))) + expect_true(all(names(ae_anly_wilcoxon) %in% names(flag))) }) test_that("strFlagValueColumn paramter works as intended",{ @@ -35,7 +35,7 @@ test_that("incorrect inputs throw errors",{ }) test_that("Expected Columns are added to dfFlagged",{ - flag <- Flag(ae_anly) + flag <- Flag(ae_anly_wilcoxon) expect_true(all(c("ThresholdLow" , "ThresholdHigh" ,"ThresholdCol" , "Flag") %in% names(flag))) }) diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index c16b07afa..69c7dd6d1 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -7,7 +7,7 @@ ie_input <- IE_Map_Raw(clindata::raw_ie_a2 , clindata::rawplus_rdsl ) %>% filter test_that("summary df created as expected and has correct structure",{ ie_list <- IE_Assess(ie_input) expect_true(is.data.frame(ie_list)) - expect_equal(names(ie_list),c("Assessment","Label", "SiteID", "N", "PValue", "Flag")) + expect_equal(names(ie_list),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) test_that("list of df created when bDataList=TRUE",{ @@ -43,7 +43,7 @@ ie_input1 <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, ie_summary <- IE_Assess(ie_input1, bDataList=FALSE) -target_ie_summary <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~PValue, ~Flag, +target_ie_summary <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, "Inclusion/Exclusion", "", "X033X", 1L, NA, 1, "Inclusion/Exclusion", "", "X159X", 1L, NA, 1, "Inclusion/Exclusion", "", "X194X", 2L, NA, 1 diff --git a/tests/testthat/test_PD_Assess.R b/tests/testthat/test_PD_Assess.R index 0834f1eef..0789ea419 100644 --- a/tests/testthat/test_PD_Assess.R +++ b/tests/testthat/test_PD_Assess.R @@ -4,7 +4,7 @@ pd_input <- PD_Map_Raw(dfPD = clindata::raw_protdev,dfRDSL = rdsl) test_that("summary df created as expected and has correct structure",{ pd_assessment <- PD_Assess(pd_input) expect_true(is.data.frame(pd_assessment)) - expect_equal(names(pd_assessment),c("Assessment","Label", "SiteID", "N", "PValue", "Flag")) + expect_equal(names(pd_assessment),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) test_that("list of df created when bDataList=TRUE",{ diff --git a/tests/testthat/test_Summarize.R b/tests/testthat/test_Summarize.R index 119b01886..f8c7b9469 100644 --- a/tests/testthat/test_Summarize.R +++ b/tests/testthat/test_Summarize.R @@ -8,9 +8,9 @@ dfAnalyzed <- gsm::Analyze_Poisson( dfTransformed) dfFlagged <- gsm::Flag(dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) test_that("output created as expected and has correct structure",{ - ae_finding <- Summarize(dfFlagged, "Safety", "Test Assessment") + ae_finding <- Summarize(dfFlagged,"Residuals" ,"Safety", "Test Assessment") expect_true(is.data.frame(ae_finding)) - expect_equal(names(ae_finding), c("Assessment","Label", "SiteID", "N", "PValue", "Flag")) + expect_equal(names(ae_finding), c("Assessment","Label", "SiteID", "N", "Score", "Flag")) expect_equal(sort(unique(ae_input$SiteID)), sort(ae_finding$SiteID)) }) From fd083dd403b20d797d980236ce355423c326d8fc Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 1 Mar 2022 19:20:29 -0500 Subject: [PATCH 15/60] update tests --- tests/testthat/test_Consent_Assess.R | 6 +++--- tests/testthat/test_IE_Assess.R | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test_Consent_Assess.R b/tests/testthat/test_Consent_Assess.R index c0e87faf4..150d91e7f 100644 --- a/tests/testthat/test_Consent_Assess.R +++ b/tests/testthat/test_Consent_Assess.R @@ -49,9 +49,9 @@ consent_summary <- Consent_Assess(consent_input, bDataList=FALSE) target_output <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, - "Main Consent", "", 1, 1L, NA, 1, - "Main Consent", "", 2, 2L, NA, 1, - "Main Consent", "", 3, 1L, NA, 1 + "Main Consent", "", 1, 1L, 1L, 1, + "Main Consent", "", 2, 2L, 1L, 1, + "Main Consent", "", 3, 1L, 1L, 1 ) test_that("output is correct given example input",{ diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index 69c7dd6d1..e3ae12884 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -44,9 +44,9 @@ ie_summary <- IE_Assess(ie_input1, bDataList=FALSE) target_ie_summary <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, - "Inclusion/Exclusion", "", "X033X", 1L, NA, 1, - "Inclusion/Exclusion", "", "X159X", 1L, NA, 1, - "Inclusion/Exclusion", "", "X194X", 2L, NA, 1 + "Inclusion/Exclusion", "", "X033X", 1L, 9L, 1, + "Inclusion/Exclusion", "", "X159X", 1L, 9L, 1, + "Inclusion/Exclusion", "", "X194X", 2L, 17L, 1 ) From 56fe7c184a24879d352330443c0087b3b1e0ca93 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 1 Mar 2022 17:14:06 -0800 Subject: [PATCH 16/60] made QC additions, corrections and changes per issues #199 and #201 --- R/AE_Assess.R | 4 +++- R/AE_Map_Raw.R | 7 ++++--- man/AE_Map_Raw.Rd | 4 ++-- tests/testthat/test_AE_Assess.R | 24 +++++++++++------------ tests/testthat/test_AE_Map_Raw.R | 33 +++++++++++++++++++++++--------- tests/testthat/test_IE_Map_Raw.R | 1 - 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/R/AE_Assess.R b/R/AE_Assess.R index 11c22d94e..74d9040f9 100644 --- a/R/AE_Assess.R +++ b/R/AE_Assess.R @@ -13,6 +13,7 @@ #' - `SiteID` - Site ID #' - `Count` - Number of Adverse Events #' - `Exposure` - Number of days of exposure +#' - `Rate` - Rate of Exposure (Count / Exposure) #' #' The Assessment #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. @@ -47,7 +48,8 @@ AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bD "cLabel is not character" = is.character(cLabel), "cMethod is not 'poisson' or 'wilcoxon'" = cMethod %in% c("poisson","wilcoxon"), "bDataList is not logical" = is.logical(bDataList), - "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count","Exposure", "Rate") %in% names(dfInput)) + "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count","Exposure", "Rate") %in% names(dfInput)), + "cMethod must be length 1" = length(cMethod) == 1 ) lAssess <- list() lAssess$dfInput <- dfInput diff --git a/R/AE_Map_Raw.R b/R/AE_Map_Raw.R index bacd1ce7a..23fbbf696 100644 --- a/R/AE_Map_Raw.R +++ b/R/AE_Map_Raw.R @@ -20,8 +20,8 @@ #' #' Note that the function can generate data summaries for specific types of AEs, but passing filtered ADAE data to dfADAE. #' -#' @param dfAE AE dataset with columns SUBJID and rows for each AE record -#' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol +#' @param dfAE AE dataset with required column SUBJID and rows for each AE record +#' @param dfRDSL Subject-level Raw Data (RDSL) with required columns: SubjectID, SiteID, value specified in strExposureCol #' @param strExposureCol Name of exposure column. 'TimeOnTreatment' by default #' #' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count (number of AEs), Exposure (Time on Treatment in Days), Rate (AE/Day) @@ -40,7 +40,8 @@ AE_Map_Raw <- function( dfAE, dfRDSL, strExposureCol="TimeOnTreatment"){ "SUBJID column not found in dfAE"="SUBJID" %in% names(dfAE), "strExposureCol is not character"=is.character(strExposureCol), "SubjectID, SiteID and strExposureCol columns not found in dfRDSL"=all(c("SubjectID","SiteID",strExposureCol) %in% names(dfRDSL)), - "NAs found in Subject ID column of dfAE" = all(!is.na(dfAE$SUBJID)) + "NAs found in SUBJID column of dfAE" = all(!is.na(dfAE$SUBJID)), + "NAs found in Subject ID column of dfRDSL" = all(!is.na(dfRDSL$SubjectID)) ) dfInput <- dfRDSL %>% diff --git a/man/AE_Map_Raw.Rd b/man/AE_Map_Raw.Rd index 27f1858d4..e2a4b41b5 100644 --- a/man/AE_Map_Raw.Rd +++ b/man/AE_Map_Raw.Rd @@ -7,9 +7,9 @@ AE_Map_Raw(dfAE, dfRDSL, strExposureCol = "TimeOnTreatment") } \arguments{ -\item{dfAE}{AE dataset with columns SUBJID and rows for each AE record} +\item{dfAE}{AE dataset with required column SUBJID and rows for each AE record} -\item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol} +\item{dfRDSL}{Subject-level Raw Data (RDSL) with required columns: SubjectID, SiteID, value specified in strExposureCol} \item{strExposureCol}{Name of exposure column. 'TimeOnTreatment' by default} } diff --git a/tests/testthat/test_AE_Assess.R b/tests/testthat/test_AE_Assess.R index 06e27c6ae..2b866a05c 100644 --- a/tests/testthat/test_AE_Assess.R +++ b/tests/testthat/test_AE_Assess.R @@ -22,19 +22,17 @@ test_that("incorrect inputs throw errors",{ expect_error(AE_Assess(ae_input, cLabel=123)) expect_error(AE_Assess(ae_input, cMethod="abacus")) expect_error(AE_Assess(ae_input, bDataList="Yes")) + expect_error(AE_Assess(ae_input %>% select(-SubjectID))) + expect_error(AE_Assess(ae_input %>% select(-SiteID))) + expect_error(AE_Assess(ae_input %>% select(-Count))) + expect_error(AE_Assess(ae_input %>% select(-Exposure))) + expect_error(AE_Assess(ae_input %>% select(-Rate))) + expect_error(AE_Assess(ae_input, cMethod=c("wilcoxon", "poisson"))) }) -test_that("incorrect inputs throw errors",{ - expect_error(AE_Assess(ae_input %>% select(-SubjectID))) - expect_error(AE_Assess(ae_input %>% select(-SiteID))) - expect_error(AE_Assess(ae_input %>% select(-Count))) - expect_error(AE_Assess(ae_input %>% select(-Exposure))) - expect_error(AE_Assess(ae_input %>% select(-Rate))) -}) - -ae_list <- AE_Assess(ae_input, bDataList=TRUE) -expect_true(is.list(ae_list)) -expect_equal(names(ae_list),c('dfInput','dfTransformed','dfAnalyzed','dfFlagged','dfSummary')) - - +test_that("Summary created when bDataList = FALSE has correct structure",{ + ae_summary <- AE_Assess(ae_input, bDataList=FALSE) + expect_equal(length(unique(ae_summary$SiteID)) , length(ae_summary$SiteID)) + expect_equal(names(ae_summary),c( "Assessment", "Label" , "SiteID" , "N" , "PValue" , "Flag")) +}) \ No newline at end of file diff --git a/tests/testthat/test_AE_Map_Raw.R b/tests/testthat/test_AE_Map_Raw.R index c2a02c2dd..a23f0c30c 100644 --- a/tests/testthat/test_AE_Map_Raw.R +++ b/tests/testthat/test_AE_Map_Raw.R @@ -13,6 +13,10 @@ test_that("incorrect inputs throw errors",{ expect_error(AE_Map_Raw("Hi","Mom")) }) +test_that("invalid strExposureCol throws error",{ + expect_error( AE_Map_Raw(dfAE = clindata::raw_ae, dfRDSL = clindata::rawplus_rdsl, strExposureCol= "Bad_Name" )) +}) + test_that("error given if required column not found",{ expect_error( @@ -119,7 +123,7 @@ test_that("NA values in input data are handled",{ dfExposure3<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, - NA, 1, 10, + 1, 1, 10, 2, 1, NA, 3, NA, 30, 4, 2, 50 @@ -128,7 +132,7 @@ test_that("NA values in input data are handled",{ dfInput3 <-tibble::tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, - NA, 1, 0, 10, 0, + 1, 1, 4, 10, 0.4, 2, 1, 2, NA, NA, 3, NA, 0, 30, 0 , 4, 2, 2, 50, .04 @@ -136,22 +140,33 @@ test_that("NA values in input data are handled",{ expect_equal(dfInput3, AE_Map_Raw(dfAE = dfAE3, dfRDSL = dfExposure3)) - - - - }) -test_that("dfAE Subject NA value throws error",{ +test_that("dfAE$SUBJID NA value throws error",{ dfAE4 <- tibble::tribble(~SUBJID, 1,NA,1,1,2,2,4,4) + dfExposure4<-tibble::tribble( + ~SubjectID, ~SiteID, ~TimeOnTreatment, + 1, 1, 10, + 2, 1, 20, + 3, 3, 30, + 4, 2, 50 + ) + + + expect_error(AE_Map_Raw(dfAE = dfAE4, dfRDSL = dfExposure4)) +}) + +test_that("dfRDSL$SubjectID NA value throws error",{ + dfAE4 <- tibble::tribble(~SUBJID, 1,1,1,1,2,2,4,4) + dfExposure4<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, NA, 1, 10, - 2, 1, NA, - 3, NA, 30, + 2, 1, 20, + 3, 2, 30, 4, 2, 50 ) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 1f6c8abdd..b7bd7ee9a 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -31,7 +31,6 @@ test_that("error given if required column not found",{ clindata::rawplus_rdsl ) ) - #"INVID", "IECAT", "IETESTCD","IETEST", "IEORRES" expect_error( IE_Map_Raw( clindata::raw_ie_a2 , From ee3a8ffdb30f4bcb24ebac429afdbfbe9f8cadf1 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 1 Mar 2022 17:14:56 -0800 Subject: [PATCH 17/60] regenerated docs --- man/AE_Assess.Rd | 1 + 1 file changed, 1 insertion(+) diff --git a/man/AE_Assess.Rd b/man/AE_Assess.Rd index e8376f526..0e920a063 100644 --- a/man/AE_Assess.Rd +++ b/man/AE_Assess.Rd @@ -41,6 +41,7 @@ The input data (\code{dfInput}) for the AE Assessment is typically created using \item \code{SiteID} - Site ID \item \code{Count} - Number of Adverse Events \item \code{Exposure} - Number of days of exposure +\item \code{Rate} - Rate of Exposure (Count / Exposure) } The Assessment From cd7e13d502981775b00f2b53b2421211d5101b20 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Wed, 2 Mar 2022 16:20:18 -0800 Subject: [PATCH 18/60] addressed 206 Consent_Map_Raw QC items --- NAMESPACE | 1 - R/Consent_Map_Raw.R | 31 ++++++-- man/Consent_Map_Raw.Rd | 4 +- tests/testthat/test_Consent_Map_Raw.R | 100 ++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 9 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 135e6917e..f15684d20 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,7 +23,6 @@ export(Visualize_Poisson) import(dplyr) import(ggplot2) import(lamW) -import(lubridate) importFrom(broom,augment) importFrom(broom,glance) importFrom(magrittr,"%>%") diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index 44a0631f4..efc2bce82 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -18,7 +18,7 @@ #' - `dfRDSL` #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `RandData` - Randomization Date +#' - `RandDate` - Randomization Date #' #' @param dfConsent consent data frame with columns: SUBJID, CONSCAT_STD , CONSYN , CONSDAT. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID RandDate. @@ -27,14 +27,13 @@ #' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count. #' #' @import dplyr -#' @import lubridate #' #' @examples #' #' input <- Consent_Map_Raw( #' dfConsent = clindata::raw_consent, #' dfRDSL = clindata::rawplus_rdsl, -#' strConsentReason = NULL +#' strConsentReason = "mainconsent" #' ) #' #' @export @@ -44,19 +43,39 @@ Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent") "dfConsent dataset not found"=is.data.frame(dfConsent), "dfRDSL dataset is not found"=is.data.frame(dfRDSL), "SUBJID, CONSCAT_STD , CONSYN , CONSDAT column not found in dfConsent"=c("SUBJID", "CONSCAT_STD" , "CONSYN" , "CONSDAT" ) %in% names(dfConsent), - "SubjectID, SiteID and RandData column not found in dfIxrsrand"= c("SubjectID", "SiteID" , "RandDate") %in% names(dfRDSL) + "SubjectID, SiteID and RandDate column not found in dfRDSL"= c("SubjectID", "SiteID" , "RandDate") %in% names(dfRDSL), + "NAs found in SUBJID column of dfConsent" = all(!is.na(dfConsent$SUBJID)), + "NAs found in SubjectID column of dfRDSL" = all(!is.na(dfRDSL$SubjectID)) ) + if(!is.null(strConsentReason)){ + stopifnot( + "strConsentReason is not character"=is.character(strConsentReason), + "strConsentReason has multiple values, specify only one"= length(strConsentReason)==1 + ) + } + + + dfRDSLSiteIDNACount <- sum(is.na(dfRDSL[['SiteID']])) + if(dfRDSLSiteIDNACount>0){ + warning(paste0("Dropped ",dfRDSLSiteIDNACount," record(s) from dfRDSL where SiteID is NA.")) + dfRDSL <- dfRDSL %>% filter(!is.na(.data[['SiteID']])) + } + dfConsent<- dfConsent %>% select(.data$SUBJID, .data$CONSCAT_STD , .data$CONSYN , .data$CONSDAT)%>% rename(SubjectID = .data$SUBJID) + missIE <- anti_join( dfConsent, dfRDSL, by="SubjectID") + if( nrow(missIE) > 0 ) warning("Not all SubjectID in dfConsent found in dfRDSL") + dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID, .data$RandDate)%>% - left_join(dfConsent, by='SubjectID') + inner_join(dfConsent, by='SubjectID') if(!is.null(strConsentReason)){ dfInput <- dfInput %>% filter(tolower(.data$CONSCAT_STD) == tolower(strConsentReason)) + stopifnot("supplied strConsentReason not found in data" = nrow(dfInput) != 0 ) } dfInput <- dfInput %>% @@ -65,7 +84,7 @@ Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent") mutate(flag_missing_rand = is.na(.data$RandDate))%>% mutate(flag_date_compare = .data$CONSDAT >= .data$RandDate ) %>% mutate(any_flag=.data$flag_noconsent | .data$flag_missing_consent | .data$flag_missing_rand | .data$flag_date_compare) %>% - mutate(Count = as.numeric(.data$any_flag)) %>% + mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) %>% select(.data$SubjectID, .data$SiteID, .data$Count) return(dfInput) diff --git a/man/Consent_Map_Raw.Rd b/man/Consent_Map_Raw.Rd index 95a8eed0f..b73c44b22 100644 --- a/man/Consent_Map_Raw.Rd +++ b/man/Consent_Map_Raw.Rd @@ -38,7 +38,7 @@ The following columns are required: \itemize{ \item \code{SubjectID} - Unique subject ID \item \code{SiteID} - Site ID -\item \code{RandData} - Randomization Date +\item \code{RandDate} - Randomization Date } } } @@ -48,7 +48,7 @@ The following columns are required: input <- Consent_Map_Raw( dfConsent = clindata::raw_consent, dfRDSL = clindata::rawplus_rdsl, - strConsentReason = NULL + strConsentReason = "mainconsent" ) } diff --git a/tests/testthat/test_Consent_Map_Raw.R b/tests/testthat/test_Consent_Map_Raw.R index 19383dd40..97d2066c8 100644 --- a/tests/testthat/test_Consent_Map_Raw.R +++ b/tests/testthat/test_Consent_Map_Raw.R @@ -107,6 +107,28 @@ test_that("error given if required column not found",{ dfRDSL = dfRDSL_test %>% select(-RGMNDTN) ) ) + + + expect_error( + Consent_Map_Raw( + dfConsent_test, + dfRDSL = dfRDSL_test %>% select(- SubjectID) + ) + ) + + expect_error( + Consent_Map_Raw( + dfConsent_test, + dfRDSL = dfRDSL_test %>% select(- SiteID) + ) + ) + + expect_error( + Consent_Map_Raw( + dfConsent_test, + dfRDSL = dfRDSL_test %>% select(- RandDate) + ) + ) }) @@ -119,4 +141,82 @@ test_that("output is correct given clindata example input",{ }) +dfConsent_test_NA1 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, + NA, "MAINCONSENT", "Yes", "2014-12-25", + 1, "MAINCONSENT", "No", "2014-12-25" ) + +dfRDSL_test_NA1<- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, + 1, 1, "2013-12-25", + 2, 2, "2015-12-25") + + + +dfConsent_test_NA2 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, + 1, "MAINCONSENT", "Yes", "2014-12-25", + 1, "MAINCONSENT", "No", "2014-12-25" ) + +dfRDSL_test_NA2<- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, + NA, 1, "2013-12-25", + 2, 2, "2015-12-25") + + + + + +test_that("NA's in SubjectID and SUBJID are handled correctly",{ + expect_error(Consent_Map_Raw(dfConsent = dfConsent_test_NA1, dfRDSL = dfRDSL_test_NA1)) + expect_error(Consent_Map_Raw(dfConsent = dfConsent_test_NA2, dfRDSL = dfRDSL_test_NA2)) + +}) + +test_that("Incorrect strConsentReason throws errors",{ + expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = c("A","B"))) + expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = 1.23)) + expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = "Name_Not_in_data")) + +}) + + +dfConsent_test2 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, + 1, "MAINCONSENT", "Yes", "2014-12-25", + 1, "MAINCONSENT", "No", "2014-12-25") + +dfRDSL_test2 <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, + 1, 1, "2013-12-25", + 2, 2, "2015-12-25") + + +dfInput_test2 <- tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1) + + +test_that("NA's in data are removed and handled correctly",{ + dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,2] = NA + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) + + dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,3] = NA + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) + + dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1), suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in))) + + + +}) + +test_that("Warning provided for missing (NA) SiteID's in dfRDSL",{ + dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA + expect_warning(Consent_Map_Raw( dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in )) +}) + From ccf3ff0b289155802d2ddba6f57665c68457e707 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Thu, 3 Mar 2022 16:47:15 +0000 Subject: [PATCH 19/60] close #232 - update unit tests --- tests/testthat/test_AE_Assess.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test_AE_Assess.R b/tests/testthat/test_AE_Assess.R index 6a70f71cf..3f13f80f3 100644 --- a/tests/testthat/test_AE_Assess.R +++ b/tests/testthat/test_AE_Assess.R @@ -1,11 +1,11 @@ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae -) +) test_that("summary df created as expected and has correct structure",{ - ae_assessment <- AE_Assess(ae_input) + ae_assessment <- AE_Assess(ae_input) expect_true(is.data.frame(ae_assessment)) expect_equal(names(ae_assessment),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) @@ -34,5 +34,5 @@ test_that("incorrect inputs throw errors",{ test_that("Summary created when bDataList = FALSE has correct structure",{ ae_summary <- AE_Assess(ae_input, bDataList=FALSE) expect_equal(length(unique(ae_summary$SiteID)) , length(ae_summary$SiteID)) - expect_equal(names(ae_summary),c( "Assessment", "Label" , "SiteID" , "N" , "PValue" , "Flag")) -}) \ No newline at end of file + expect_equal(names(ae_summary),c("Assessment", "Label", "SiteID", "N", "Score", "Flag")) +}) From ba95cc2fb117912a1222a25292e91eab63abc31e Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Thu, 3 Mar 2022 11:09:44 -0800 Subject: [PATCH 20/60] commit latest changes for dev merge --- R/Consent_Assess.R | 20 ++++++++++++++++---- R/Consent_Map_Raw.R | 2 +- man/Consent_Assess.Rd | 7 +++++++ man/Consent_Map_Raw.Rd | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/R/Consent_Assess.R b/R/Consent_Assess.R index 8f4c637b8..c9ae3863d 100644 --- a/R/Consent_Assess.R +++ b/R/Consent_Assess.R @@ -16,12 +16,18 @@ #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. #' +#' @section Assessment methodology: +#' +#' This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or +#' Consent date later in time than the Randomization Date. 'N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites +#' With N greater than user specified `nThreshold` will be flagged. +#' #' #' #' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count. -#' @param nThreshold integer threshold values Flagging, integer values greater than will be flagged. -#' @param cLabel Assessment label -#' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned +#' @param nThreshold Any sites where 'N' is greater than nThreshold will be flagged. Default value is 0.5, which flags any site with one or more subjects meeting any of the criteria. +#' @param cLabel Assessment label. +#' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned. #' #' #' @examples @@ -46,9 +52,15 @@ Consent_Assess <- function( dfInput, nThreshold=0.5, cLabel="", bDataList=FALSE "dfInput is not a data.frame" = is.data.frame(dfInput), "cLabel is not character" = is.character(cLabel), "bDataList is not logical" = is.logical(bDataList), - "One or more of these columns: SubjectID, SiteID,and Count not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)) + "One or more of these columns: SubjectID, SiteID,and Count not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)), + "nThreshold must be numeric" = is.numeric(nThreshold), + "nThreshold must be length 1" = length(nThreshold) ==1 + + ) + + lAssess <- list() lAssess$dfInput <- dfInput lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = 'Count' ) diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index efc2bce82..29966e114 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -33,7 +33,7 @@ #' input <- Consent_Map_Raw( #' dfConsent = clindata::raw_consent, #' dfRDSL = clindata::rawplus_rdsl, -#' strConsentReason = "mainconsent" +#' strConsentReason = NULL #' ) #' #' @export diff --git a/man/Consent_Assess.Rd b/man/Consent_Assess.Rd index cdc367b0b..0d3895c55 100644 --- a/man/Consent_Assess.Rd +++ b/man/Consent_Assess.Rd @@ -42,6 +42,13 @@ The Assessment } } +\section{Assessment methodology}{ + + +This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or +Consent date later in time than the Randomization Date. 'N' in the summary represents the number of subjects in a study that meet one or more criteria. +} + \examples{ dfInput <- Consent_Map_Raw( diff --git a/man/Consent_Map_Raw.Rd b/man/Consent_Map_Raw.Rd index b73c44b22..df42be12b 100644 --- a/man/Consent_Map_Raw.Rd +++ b/man/Consent_Map_Raw.Rd @@ -48,7 +48,7 @@ The following columns are required: input <- Consent_Map_Raw( dfConsent = clindata::raw_consent, dfRDSL = clindata::rawplus_rdsl, - strConsentReason = "mainconsent" + strConsentReason = NULL ) } From 6ad43fb57649913ccc86d1d308453029abe0bd04 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Thu, 3 Mar 2022 19:34:03 +0000 Subject: [PATCH 21/60] close #231 - qc updates for Transform_EventCount() --- R/Transform_EventCount.R | 52 +++++++++++----------- man/Transform_EventCount.Rd | 7 ++- tests/testthat/test_Transform_EventCount.R | 24 ++++++---- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/R/Transform_EventCount.R b/R/Transform_EventCount.R index ddc809d49..27909b358 100644 --- a/R/Transform_EventCount.R +++ b/R/Transform_EventCount.R @@ -1,39 +1,40 @@ #' Transform Event Count -#' +#' #' Convert from ADaM format to needed input format for Safety Assessment #' @details -#' +#' #' This function transforms data to prepare it for the Analysis step -#' +#' #' @section Data Specification: -#' +#' #' The input data (`dfInput`) for the AE Assessment is typically created using any of these functions: #' \code{\link{AE_Map_Raw}} -#' \code{\link{AE_Map_Adam}} -#' \code{\link{PD_Map_Raw}} -#' \code{\link{IE_Map_Raw}} -#' \code{\link{Consent_Map_Raw}} -#' +#' \code{\link{AE_Map_Adam}} +#' \code{\link{PD_Map_Raw}} +#' \code{\link{IE_Map_Raw}} +#' \code{\link{Consent_Map_Raw}} +#' #' (`dfInput`) has the following required and optional columns: #' Required: #' - `SiteID` - Site ID #' - `Count` - Number of Adverse Events the actual name of this column is specified by the parameter cCountCol. #' Optional #' - `Exposure` - Number of days of exposure, name specified by cExposureCol. -#' -#' The input data has one or more rows per site. Transform_EventCount sums cCountCol for a TotalCount for each site. +#' +#' The input data has one or more rows per site. Transform_EventCount sums cCountCol for a TotalCount for each site. #' For data with an optional cExposureCol, a summed exposure is caculated for each site. #' -#' @param dfInput A data frame with one Record per person -#' @param cCountCol required. numerical or logical. Column to be counted. -#' @param cExposureCol Optional, numerical Exposure Column -#' +#' @param dfInput A data.frame with one record per person. +#' @param cCountCol Required. Numerical or logical. Column to be counted. +#' @param cExposureCol Optional. Numerical `Exposure` column. +#' #' @return data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if cExposureCol is used. -#' -#' @examples +#' +#' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) #' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) -#' +#' +#' @import dplyr #' #' @export @@ -41,9 +42,10 @@ Transform_EventCount <- function( dfInput , cCountCol, cExposureCol=NULL ){ stopifnot( "dfInput is not a data frame" = is.data.frame(dfInput), "cCountCol not found in input data" = cCountCol %in% names(dfInput), + "SiteID not found in input data" = "SiteID" %in% names(dfInput), "cCount column is not numeric or logical" = is.numeric(dfInput[[cCountCol]]) | is.logical(dfInput[[cCountCol]]) ) - if(anyNA(dfInput[[cCountCol]])) stop("NA's found in dfInput$Count") + if(anyNA(dfInput[[cCountCol]])) stop("NA's found in dfInput$Count") if(!is.null(cExposureCol)){ stopifnot( "cExposureCol is not found in input data" = cExposureCol %in% names(dfInput), @@ -58,21 +60,21 @@ Transform_EventCount <- function( dfInput , cCountCol, cExposureCol=NULL ){ if(is.null(cExposureCol)){ dfTransformed <- dfInput %>% - group_by(.data$SiteID) %>% + group_by(.data$SiteID) %>% summarise( - N=n(), + N=n(), TotalCount= sum(.data[[cCountCol]]), ) }else{ dfTransformed <- dfInput %>% - group_by(.data$SiteID) %>% + group_by(.data$SiteID) %>% summarise( - N=n(), + N=n(), TotalCount= sum(.data[[cCountCol]]), TotalExposure=sum(.data[[cExposureCol]]) - )%>% + )%>% mutate(Rate = .data$TotalCount/.data$TotalExposure) } return(dfTransformed) -} \ No newline at end of file +} diff --git a/man/Transform_EventCount.Rd b/man/Transform_EventCount.Rd index 9001fb6a8..605aeae60 100644 --- a/man/Transform_EventCount.Rd +++ b/man/Transform_EventCount.Rd @@ -7,11 +7,11 @@ Transform_EventCount(dfInput, cCountCol, cExposureCol = NULL) } \arguments{ -\item{dfInput}{A data frame with one Record per person} +\item{dfInput}{A data.frame with one record per person.} -\item{cCountCol}{required. numerical or logical. Column to be counted.} +\item{cCountCol}{Required. Numerical or logical. Column to be counted.} -\item{cExposureCol}{Optional, numerical Exposure Column} +\item{cExposureCol}{Optional. Numerical \code{Exposure} column.} } \value{ data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if cExposureCol is used. @@ -49,5 +49,4 @@ For data with an optional cExposureCol, a summed exposure is caculated for each dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) - } diff --git a/tests/testthat/test_Transform_EventCount.R b/tests/testthat/test_Transform_EventCount.R index 076a3eb32..8a1587143 100644 --- a/tests/testthat/test_Transform_EventCount.R +++ b/tests/testthat/test_Transform_EventCount.R @@ -1,17 +1,23 @@ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae -) +) + +test_that("input data for unit tests contains required columns", { + expect_true(all(c("SiteID", "Count") %in% names(ae_input))) +}) test_that("output created as expected and has correct structure",{ ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) expect_true(is.data.frame(ae_prep)) expect_equal(sort(unique(ae_input$SiteID)), sort(ae_prep$SiteID)) + expect_equal(names(Transform_EventCount(ae_input, cCountCol = "Count")), c("SiteID", "N", "TotalCount")) + expect_equal(names(Transform_EventCount(ae_input, cCountCol = "Count", cExposureCol = "Exposure")), c("SiteID", "N", "TotalCount", "TotalExposure", "Rate")) }) test_that("cCount works as expected",{ sim<-data.frame( - SiteID = rep("site1",30), + SiteID = rep("site1",30), event = c(rep(0,5),rep(1,15),rep(2,10)) ) EventCount <- Transform_EventCount(sim, cCountCol="event") @@ -22,7 +28,7 @@ test_that("cCount works as expected",{ ) EventCount2 <- Transform_EventCount(sim2, cCountCol="event") expect_equal(EventCount2,tibble(SiteID=c("site1", "site2", "site3"), N=c(10,8,12), TotalCount=c(5,8,22))) - + }) test_that("cExposureCol works as expected",{ @@ -35,7 +41,7 @@ test_that("cExposureCol works as expected",{ EventCount3 <- Transform_EventCount(sim3, cCountCol="event", cExposureCol = 'ndays') expect_equal(EventCount3,tibble(SiteID=c("site1", "site2", "site3"), N=c(11,7,12), TotalCount=c(5,7,24), TotalExposure = c(80,70,120), Rate = c(0.0625, 0.1, 0.2))) - + }) test_that("incorrect inputs throw errors",{ @@ -55,11 +61,11 @@ test_that("NA in Exposure throws a warning and returns correct data",{ expect_equal( suppressWarnings(Transform_EventCount(sim4, cCountCol="event", cExposureCol = 'ndays')), tibble( - SiteID=c("site1", "site2", "site3"), - N=c(9,7,10), + SiteID=c("site1", "site2", "site3"), + N=c(9,7,10), TotalCount=c(4,7,20), - TotalExposure = c(65,70,100), - Rate = c(4/65, 7/70, 20/100))) + TotalExposure = c(65,70,100), + Rate = c(4/65, 7/70, 20/100))) }) test_that("NA in Exposure is removed ",{ From 0605fba4943f7726fda940aff503e7204f648854 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Thu, 3 Mar 2022 21:29:17 +0000 Subject: [PATCH 22/60] update unit test --- tests/testthat/test_Transform_EventCount.R | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test_Transform_EventCount.R b/tests/testthat/test_Transform_EventCount.R index 8a1587143..fec6ca7ff 100644 --- a/tests/testthat/test_Transform_EventCount.R +++ b/tests/testthat/test_Transform_EventCount.R @@ -3,10 +3,6 @@ ae_input <- AE_Map_Adam( safetyData::adam_adae ) -test_that("input data for unit tests contains required columns", { - expect_true(all(c("SiteID", "Count") %in% names(ae_input))) -}) - test_that("output created as expected and has correct structure",{ ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) expect_true(is.data.frame(ae_prep)) @@ -47,6 +43,8 @@ test_that("cExposureCol works as expected",{ test_that("incorrect inputs throw errors",{ expect_error(Transform_EventCount(list())) expect_error(Transform_EventCount("Hi")) + expect_error(Transform_EventCount(ae_input, cCountCol="NotACol")) + expect_error(Transform_EventCount(ae_input, cExposureCol="NotACol")) }) test_that("NA in Exposure throws a warning and returns correct data",{ From 6367d8822e710a81c082f57fcb76b27b0cb79f3a Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Thu, 3 Mar 2022 14:00:33 -0800 Subject: [PATCH 23/60] added tests to Consent_Assess --- tests/testthat/test_AE_Assess.R | 8 +++++++- tests/testthat/test_Consent_Assess.R | 29 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test_AE_Assess.R b/tests/testthat/test_AE_Assess.R index 6a70f71cf..c575ef7d6 100644 --- a/tests/testthat/test_AE_Assess.R +++ b/tests/testthat/test_AE_Assess.R @@ -35,4 +35,10 @@ test_that("Summary created when bDataList = FALSE has correct structure",{ ae_summary <- AE_Assess(ae_input, bDataList=FALSE) expect_equal(length(unique(ae_summary$SiteID)) , length(ae_summary$SiteID)) expect_equal(names(ae_summary),c( "Assessment", "Label" , "SiteID" , "N" , "PValue" , "Flag")) -}) \ No newline at end of file +}) + + + +# Add tests for NA values in columns: SubjectID, SiteID, Count +# Add tests for nThreshold + diff --git a/tests/testthat/test_Consent_Assess.R b/tests/testthat/test_Consent_Assess.R index 150d91e7f..1bc104c98 100644 --- a/tests/testthat/test_Consent_Assess.R +++ b/tests/testthat/test_Consent_Assess.R @@ -27,12 +27,17 @@ test_that("list of df created when bDataList=TRUE",{ expect_equal(names(consent_list),c('dfInput','dfTransformed','dfAnalyzed','dfFlagged','dfSummary')) }) +# Add tests for NA values in columns: SubjectID, SiteID, Count +# Add tests for nThreshold + test_that("incorrect inputs throw errors",{ expect_error(Consent_Assess(list())) expect_error(Consent_Assess("Hi")) expect_error(Consent_Assess(consent_input, cLabel=123)) expect_error(Consent_Assess(consent_input, cMethod="abacus")) expect_error(Consent_Assess(consent_input, bDataList="Yes")) + expect_error(Consent_Assess(consent_input, nThreshold = "A")) + expect_error(Consent_Assess(consent_input, nThreshold = c(1,2))) }) @@ -54,10 +59,34 @@ target_output <- tibble::tribble( "Main Consent", "", 3, 1L, 1L, 1 ) +target_output_NA_SiteID <- tibble::tribble( + ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, + "Main Consent", "", 2, 2L, 1L, 1, + "Main Consent", "", 3, 1L, 1L, 1, + "Main Consent", "", NA, 1L, 1L, 1 +) + test_that("output is correct given example input",{ expect_equal(consent_summary,target_output) }) +test_that("NA in dfInput$SubjectID does not affect resulting dfSummary output for Consent_Assess",{ + consent_input_in <- consent_input; consent_input_in[1:2,"SubjectID"] = NA + consent_summary <- Consent_Assess(consent_input_in, bDataList=FALSE) + expect_equal(consent_summary,target_output) +}) + +test_that("NA in dfInput$SiteID results in NA for SiteID in dfSummary output for Consent_Assess",{ + consent_input_in <- consent_input; consent_input_in[1,"SiteID"] = NA + consent_summary <- Consent_Assess(consent_input_in, bDataList=FALSE) + expect_equal(consent_summary,target_output_NA_SiteID) +}) + +test_that("NA in dfInput$Count results in Error for Consent_Assess",{ + consent_input_in <- consent_input; consent_input_in[1,"Count"] = NA + expect_error(Consent_Assess(consent_input_in)) +}) + From ec2362e0e7473d973681f03f6d691b128422047f Mon Sep 17 00:00:00 2001 From: Doug Sanders <95380773+dsanders2gilead@users.noreply.github.com> Date: Thu, 3 Mar 2022 14:24:19 -0800 Subject: [PATCH 24/60] Update R/IE_Map_Raw.R Co-authored-by: jwildfire --- R/IE_Map_Raw.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 1026a827d..b86e07fcf 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -60,7 +60,7 @@ IE_Map_Raw <- function( dfIE_long <- dfIE %>% filter(.data$SUBJID !="")%>% select(.data$SUBJID, .data[[strCategoryCol]], .data[[strResultCol]]) %>% - mutate(expected=ifelse(.data[[strCategoryCol]] ==vCategoryValues[2],vExpectedResultValues[1],vExpectedResultValues[2])) %>% + mutate(expected=ifelse(.data[[strCategoryCol]] ==vCategoryValues[1],vExpectedResultValues[1],vExpectedResultValues[2])) %>% mutate(valid=.data[[strResultCol]]==.data$expected)%>% mutate(invalid=.data[[strResultCol]]!=.data$expected)%>% mutate(missing=!(.data[[strResultCol]] %in% vExpectedResultValues)) From 2996b42dcfebfb5e1debb7bb7c32c976ef54f4bc Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Thu, 3 Mar 2022 14:43:44 -0800 Subject: [PATCH 25/60] made suggested alignment changes to vCategoryValues and vExpectedResultValues --- R/IE_Map_Raw.R | 4 ++-- man/IE_Map_Raw.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index b86e07fcf..1efed3ba2 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -21,7 +21,7 @@ #' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID #' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' -#' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion"). +#' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). #' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". #' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". #' @@ -39,7 +39,7 @@ IE_Map_Raw <- function( dfIE = NULL, dfRDSL = NULL, strCategoryCol = 'IECAT', - vCategoryValues = c("Inclusion","Exclusion"), + vCategoryValues = c("Exclusion","Inclusion"), strResultCol = 'IEORRES_STD', vExpectedResultValues = c(0,1) ){ diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 0eed3e0ec..3be18abfc 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -8,7 +8,7 @@ IE_Map_Raw( dfIE = NULL, dfRDSL = NULL, strCategoryCol = "IECAT", - vCategoryValues = c("Inclusion", "Exclusion"), + vCategoryValues = c("Exclusion", "Inclusion"), strResultCol = "IEORRES_STD", vExpectedResultValues = c(0, 1) ) @@ -20,7 +20,7 @@ IE_Map_Raw( \item{strCategoryCol}{Name ofcCriteria category column. default = 'IECAT'} -\item{vCategoryValues}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Inclusion","Exclusion").} +\item{vCategoryValues}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion").} \item{strResultCol}{Name of criteria Result column. Default = "IEORRES_STD".} From e8463e79c5d5f2f1f275405ca5e23ce4fa948711 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Thu, 3 Mar 2022 22:58:45 +0000 Subject: [PATCH 26/60] closes #230 - qc updates for Summarize() --- R/Summarize.R | 24 +++++++++++++++++++----- man/Summarize.Rd | 19 ++++++++++++++++++- tests/testthat/test_Summarize.R | 9 ++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/R/Summarize.R b/R/Summarize.R index 6da11f241..13f4aba52 100644 --- a/R/Summarize.R +++ b/R/Summarize.R @@ -2,12 +2,24 @@ #' #' Create a concise summary of assessment results that is easy to aggregate across assessments #' +#' @details +#' +#' @section Data Specification: +#' +#' \code{Summarize} supports the input data (`dfFlagged`) from the \code{Flag} function. +#' +#' (`dfFlagged`) has the following required columns: +#' - `SiteID` - Site ID +#' - `N` - Total number of participants at site +#' - `Flag` - Flagging value of -1, 0, or 1 +#' - `strScoreCol` - Column from analysis results. Default is "PValue". +#' #' @param dfFlagged data frame in format produced by \code{\link{Flag}} #' @param strScoreCol column from analysis results to be copied to `dfSummary$Score` #' @param cAssessment brief description of current assessment #' @param cLabel brief description of line item in current assessment #' -#' @return Simplified finding data frame with columns for "SiteID", "N", "PValue", "Flag". +#' @return Simplified finding data frame with columns: Assessment, Label, SiteID, N, Pvalue, Flag #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) @@ -22,10 +34,12 @@ Summarize <- function( dfFlagged , strScoreCol="PValue", cAssessment="", cLabel=""){ stopifnot( - is.data.frame(dfFlagged), - is.character(cAssessment), - is.character(cLabel), - all(c("SiteID", "N", "Flag",strScoreCol) %in% names(dfFlagged)) + "dfFlagged is not a data frame" = is.data.frame(dfFlagged), + "cAssessment is not character" = is.character(cAssessment), + "cLabel is not character" = is.character(cLabel), + "One or more of these columns: SiteID, N, Flag not found in dfFlagged" = all(c("SiteID", "N", "Flag",strScoreCol) %in% names(dfFlagged)), + "cAssessment must be length of 1" = length(cAssessment) == 1, + "cLabel must be length of 1" = length(cLabel) == 1 ) dfSummary <- dfFlagged %>% mutate(Assessment = cAssessment) %>% diff --git a/man/Summarize.Rd b/man/Summarize.Rd index 47aa9f4c0..1308741e3 100644 --- a/man/Summarize.Rd +++ b/man/Summarize.Rd @@ -16,11 +16,28 @@ Summarize(dfFlagged, strScoreCol = "PValue", cAssessment = "", cLabel = "") \item{cLabel}{brief description of line item in current assessment} } \value{ -Simplified finding data frame with columns for "SiteID", "N", "PValue", "Flag". +Simplified finding data frame with columns: Assessment, Label, SiteID, N, Pvalue, Flag } \description{ Create a concise summary of assessment results that is easy to aggregate across assessments } +\details{ + +} +\section{Data Specification}{ + + +\code{Summarize} supports the input data (\code{dfFlagged}) from the \code{Flag} function. + +(\code{dfFlagged}) has the following required columns: +\itemize{ +\item \code{SiteID} - Site ID +\item \code{N} - Total number of participants at site +\item \code{Flag} - Flagging value of -1, 0, or 1 +\item \code{strScoreCol} - Column from analysis results. Default is "PValue". +} +} + \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) diff --git a/tests/testthat/test_Summarize.R b/tests/testthat/test_Summarize.R index f8c7b9469..3d4fd3c3a 100644 --- a/tests/testthat/test_Summarize.R +++ b/tests/testthat/test_Summarize.R @@ -1,10 +1,10 @@ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae -) +) dfTransformed <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) -dfAnalyzed <- gsm::Analyze_Poisson( dfTransformed) +dfAnalyzed <- gsm::Analyze_Poisson( dfTransformed) dfFlagged <- gsm::Flag(dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) test_that("output created as expected and has correct structure",{ @@ -18,6 +18,9 @@ test_that("incorrect inputs throw errors",{ expect_error(Summarize(list())) expect_error(Summarize("Hi")) expect_error(Summarize(ae_flag,12312)) + expect_error(Summarize(dfFlagged, strScoreCol = "wombat")) + expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", cLabel = c("pizza", "donuts"))) + expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", cAssessment = c("to assess", "to not assess"))) }) test_that("error given if required column not found",{ From e53884164b4835176ce5d4c741d7117b08b1c84f Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Fri, 4 Mar 2022 15:37:42 +0000 Subject: [PATCH 27/60] closes #229 - qc updates for Flag() --- R/Flag.R | 22 ++++++++++++---------- man/Flag.Rd | 6 +++--- tests/testthat/test_Flag.R | 12 +++++++----- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/R/Flag.R b/R/Flag.R index f76709dde..e7eb97855 100644 --- a/R/Flag.R +++ b/R/Flag.R @@ -15,9 +15,9 @@ #' - `strColumn` - A column to use for Thresholding (required) #' - 'strValueColumn' - A column to be used for the sign of the flag (optional) #' -#' @param dfAnalyzed data frame where flags should be added -#' @param strColumn Name of the Column to use for thresholding -#' @param vThreshold vector of 2 numeric values representing lower and upper threshold values. All values in strColumn are compared to vThreshold using strict comparisons. Values less than the lower threshold or greater than the upper threshold are flagged as -1 and 1 respectively. Values equal to the threshold values are set to 0 (i.e. not flagged). If NA is provided for either threshold value it is ignored, and no values are flagged based on the threshold. NA and NaN values in strColumn are given NA flag values. +#' @param dfAnalyzed data.frame where flags should be added. +#' @param strColumn Name of the column to use for thresholding. +#' @param vThreshold Vector of 2 numeric values representing lower and upper threshold values. All values in strColumn are compared to vThreshold using strict comparisons. Values less than the lower threshold or greater than the upper threshold are flagged as -1 and 1 respectively. Values equal to the threshold values are set to 0 (i.e. not flagged). If NA is provided for either threshold value it is ignored, and no values are flagged based on the threshold. NA and NaN values in strColumn are given NA flag values. #' @param strValueColumn Optional, Name of the Column to use for sign of Flag. If value for that row is higher than median of strValueColumn then Flag = 1, if lower then Flag = -1. #' #' @return input data frame with the columns added for "ThresholdLow","ThresholdHigh","ThresholdCol" and "Flag" @@ -38,16 +38,18 @@ Flag <- function( dfAnalyzed , strColumn="PValue", vThreshold=c(0.05,NA),strValueColumn = NULL){ stopifnot( - is.data.frame(dfAnalyzed), - is.character(strColumn), - is.numeric(vThreshold), - length(vThreshold) == 2, - strColumn %in% names(dfAnalyzed), - strValueColumn %in% names(dfAnalyzed) + "dfAnalyzed is not a data frame" = is.data.frame(dfAnalyzed), + "strColumn is not character" = is.character(strColumn), + "vThreshold is not numeric" = is.numeric(vThreshold), + "vThreshold must be length of 2" = length(vThreshold) == 2, + "strColumn must be length of 1" = length(strColumn) == 1, + "strColumn not found in dfAnalyzed" = strColumn %in% names(dfAnalyzed), + "strValueColumn not found in dfAnalyzed" = strValueColumn %in% names(dfAnalyzed), + "SiteID not found in dfAnalyzed" = "SiteID" %in% names(dfAnalyzed) ) if(all(!is.na(vThreshold))){ - stopifnot(vThreshold[2]>vThreshold[1]) + "vThreshold must contain a minimum and maximum value (i.e., vThreshold = c(1, 2))" = stopifnot(vThreshold[2]>vThreshold[1]) } dfFlagged<-dfAnalyzed %>% diff --git a/man/Flag.Rd b/man/Flag.Rd index 490d8af9c..af38301a0 100644 --- a/man/Flag.Rd +++ b/man/Flag.Rd @@ -12,11 +12,11 @@ Flag( ) } \arguments{ -\item{dfAnalyzed}{data frame where flags should be added} +\item{dfAnalyzed}{data.frame where flags should be added.} -\item{strColumn}{Name of the Column to use for thresholding} +\item{strColumn}{Name of the column to use for thresholding.} -\item{vThreshold}{vector of 2 numeric values representing lower and upper threshold values. All values in strColumn are compared to vThreshold using strict comparisons. Values less than the lower threshold or greater than the upper threshold are flagged as -1 and 1 respectively. Values equal to the threshold values are set to 0 (i.e. not flagged). If NA is provided for either threshold value it is ignored, and no values are flagged based on the threshold. NA and NaN values in strColumn are given NA flag values.} +\item{vThreshold}{Vector of 2 numeric values representing lower and upper threshold values. All values in strColumn are compared to vThreshold using strict comparisons. Values less than the lower threshold or greater than the upper threshold are flagged as -1 and 1 respectively. Values equal to the threshold values are set to 0 (i.e. not flagged). If NA is provided for either threshold value it is ignored, and no values are flagged based on the threshold. NA and NaN values in strColumn are given NA flag values.} \item{strValueColumn}{Optional, Name of the Column to use for sign of Flag. If value for that row is higher than median of strValueColumn then Flag = 1, if lower then Flag = -1.} } diff --git a/tests/testthat/test_Flag.R b/tests/testthat/test_Flag.R index 64e33d1f2..6eb06a30d 100644 --- a/tests/testthat/test_Flag.R +++ b/tests/testthat/test_Flag.R @@ -13,6 +13,8 @@ test_that("output created as expected and has correct structure",{ expect_true(is.data.frame(flag)) expect_equal(sort(unique(ae_input$SiteID)), sort(flag$SiteID)) expect_true(all(names(ae_anly_wilcoxon) %in% names(flag))) + expect_equal(names(flag), c("SiteID", "N", "TotalCount", "TotalExposure", "Rate", "Estimate", + "PValue", "ThresholdLow", "ThresholdHigh", "ThresholdCol", "Flag")) }) test_that("strFlagValueColumn paramter works as intended",{ @@ -40,18 +42,18 @@ test_that("Expected Columns are added to dfFlagged",{ }) test_that("vThreshold parameter works as intended",{ -sim1 <- Flag(data.frame(vals=seq(1:100)), strColumn="vals", vThreshold=c(10,NA)) +sim1 <- Flag(data.frame(SiteID = seq(1:100), vals=seq(1:100)), strColumn="vals", vThreshold=c(10,NA)) expect_equal(sim1$Flag, c(rep(-1,9), rep(0,91))) -sim2 <- Flag(data.frame(vals=seq(1:100)), strColumn="vals", vThreshold=c(NA,91)) +sim2 <- Flag(data.frame(SiteID = seq(1:100), vals=seq(1:100)), strColumn="vals", vThreshold=c(NA,91)) expect_equal(sim2$Flag, c(rep(0,91), rep(1,9))) -sim3 <- Flag(data.frame(vals=seq(1:100)), strColumn="vals", vThreshold=c(2,91)) +sim3 <- Flag(data.frame(SiteID = seq(1:100), vals=seq(1:100)), strColumn="vals", vThreshold=c(2,91)) expect_equal(sim3$Flag, c(-1,rep(0,90), rep(1,9))) -sim4 <- Flag(data.frame(vals=seq(from = -100, to = 100)), strColumn="vals", vThreshold=c(-91,91)) +sim4 <- Flag(data.frame(SiteID = seq(1:201), vals=seq(from = -100, to = 100)), strColumn="vals", vThreshold=c(-91,91)) expect_equal(sim4$Flag,c(rep(-1,9),rep(0,183), rep(1,9))) }) test_that("NA values in strColumn result in NA in Flag column",{ - NAsim <- Flag(data.frame(vals=c(seq(1:90),rep(NA,10))), strColumn="vals", vThreshold=c(10,NA)) + NAsim <- Flag(data.frame(SiteID = seq(1:100), vals=c(seq(1:90),rep(NA,10))), strColumn="vals", vThreshold=c(10,NA)) expect_equal(NAsim$Flag, c(rep(-1,9), rep(0,81),rep(NA,10))) }) From 72c464d4a4a36016fdefb6a8c902d1a35a6c0752 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Fri, 4 Mar 2022 17:20:58 +0000 Subject: [PATCH 28/60] closes #237 - standardize parameter naming conventions --- R/AE_Assess.R | 26 +++--- R/Analyze_Chisq.R | 2 +- R/Analyze_Fisher.R | 2 +- R/Analyze_Poisson.R | 48 +++++----- R/Analyze_Poisson_PredictBounds.R | 40 ++++----- R/Analyze_Wilcoxon.R | 6 +- R/Consent_Assess.R | 68 +++++++------- R/Flag.R | 2 +- R/IE_Assess.R | 58 ++++++------ R/PD_Assess.R | 73 ++++++++------- R/Summarize.R | 22 ++--- R/Transform_EventCount.R | 44 ++++----- R/Visualize_Poisson.R | 20 ++--- man/AE_Assess.Rd | 12 +-- man/Analyze_Chisq.Rd | 2 +- man/Analyze_Fisher.Rd | 2 +- man/Analyze_Poisson.Rd | 4 +- man/Analyze_Poisson_PredictBounds.Rd | 2 +- man/Analyze_Wilcoxon.Rd | 2 +- man/Consent_Assess.Rd | 10 +-- man/Flag.Rd | 2 +- man/IE_Assess.Rd | 10 +-- man/PD_Assess.Rd | 15 ++-- man/Summarize.Rd | 10 +-- man/Transform_EventCount.Rd | 18 ++-- man/Visualize_Poisson.Rd | 6 +- tests/testthat/test_AE_Assess.R | 6 +- tests/testthat/test_Analyze_Poisson.R | 6 +- tests/testthat/test_Analyze_Wilcoxon.R | 4 +- tests/testthat/test_Consent_Assess.R | 5 +- tests/testthat/test_Consent_Map_Raw.R | 40 ++++----- tests/testthat/test_Flag.R | 2 +- tests/testthat/test_IE_Assess.R | 6 +- tests/testthat/test_IE_Map_Raw.R | 42 ++++----- tests/testthat/test_PD_Assess.R | 6 +- tests/testthat/test_PD_Map_Raw.R | 100 ++++++++++----------- tests/testthat/test_Summarize.R | 6 +- tests/testthat/test_Transform_EventCount.R | 26 +++--- 38 files changed, 374 insertions(+), 381 deletions(-) diff --git a/R/AE_Assess.R b/R/AE_Assess.R index 1684e149d..03f7f4242 100644 --- a/R/AE_Assess.R +++ b/R/AE_Assess.R @@ -23,38 +23,38 @@ #' #' @section Statistical Assumptions: #' -#' A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `cMethod` parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in `vThreshold`. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. +#' A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `strMethod` parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in `vThreshold`. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. #' #' See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. #' #' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure #' @param vThreshold numeric vector with 2 threshold values. Defaults to c(-5,5) for method = "poisson" and c(.0001,NA) for method = Wilcoxon. -#' @param cLabel Assessment label -#' @param cMethod valid methods are "poisson" (the default), or "wilcoxon" +#' @param strLabel Assessment label +#' @param strMethod valid methods are "poisson" (the default), or "wilcoxon" #' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the Summary data frame is returned #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) #' SafetyAE <- AE_Assess( dfInput ) -#' SafetyAE_Wilk <- AE_Assess( dfInput, cMethod="wilcoxon") +#' SafetyAE_Wilk <- AE_Assess( dfInput, strMethod="wilcoxon") #' #' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. #' #' @export -AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bDataList=FALSE){ +AE_Assess <- function( dfInput, vThreshold=NULL, strLabel="", strMethod="poisson",bDataList=FALSE){ stopifnot( "dfInput is not a data.frame" = is.data.frame(dfInput), - "cLabel is not character" = is.character(cLabel), - "cMethod is not 'poisson' or 'wilcoxon'" = cMethod %in% c("poisson","wilcoxon"), + "strLabel is not character" = is.character(strLabel), + "strMethod is not 'poisson' or 'wilcoxon'" = strMethod %in% c("poisson","wilcoxon"), "bDataList is not logical" = is.logical(bDataList), "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count","Exposure", "Rate") %in% names(dfInput)), - "cMethod must be length 1" = length(cMethod) == 1 + "strMethod must be length 1" = length(strMethod) == 1 ) lAssess <- list() lAssess$dfInput <- dfInput - lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) - if(cMethod == "poisson"){ + lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) + if(strMethod == "poisson"){ if(is.null(vThreshold)){ vThreshold = c(-5,5) }else{ @@ -66,9 +66,9 @@ AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bD } lAssess$dfAnalyzed <- gsm::Analyze_Poisson( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'Residuals', vThreshold =vThreshold) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol = 'Residuals', cAssessment="Safety", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol = 'Residuals', strAssessment="Safety", strLabel= strLabel) - } else if(cMethod=="wilcoxon"){ + } else if(strMethod=="wilcoxon"){ if(is.null(vThreshold)){ vThreshold = c(0.0001,NA) }else{ @@ -81,7 +81,7 @@ AE_Assess <- function( dfInput, vThreshold=NULL, cLabel="", cMethod="poisson",bD } lAssess$dfAnalyzed <- gsm::Analyze_Wilcoxon( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'PValue', vThreshold =vThreshold, strValueColumn = 'Estimate') - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strAssessment="Safety", strLabel= strLabel) } if(bDataList){ diff --git a/R/Analyze_Chisq.R b/R/Analyze_Chisq.R index 84d293763..1651cfdc6 100644 --- a/R/Analyze_Chisq.R +++ b/R/Analyze_Chisq.R @@ -29,7 +29,7 @@ #' #' @examples #' dfInput <- Disp_Map(dfDisp = safetyData::adam_adsl, strCol = "DCREASCD",strReason = "Adverse Event") -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count' ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) #' dfAnalyzed <- Analyze_Chisq( dfTransformed ) #' #' @export diff --git a/R/Analyze_Fisher.R b/R/Analyze_Fisher.R index 653077819..37ceca2a6 100644 --- a/R/Analyze_Fisher.R +++ b/R/Analyze_Fisher.R @@ -30,7 +30,7 @@ #' #' @examples #' dfInput <- Disp_Map(dfDisp = safetyData::adam_adsl, strCol = "DCREASCD",strReason = "Adverse Event") -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count' ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) #' dfAnalyzed <- Analyze_Fisher( dfTransformed ) #' #' @export diff --git a/R/Analyze_Poisson.R b/R/Analyze_Poisson.R index a3da6c2ae..dd6eff55d 100644 --- a/R/Analyze_Poisson.R +++ b/R/Analyze_Poisson.R @@ -1,52 +1,52 @@ #' Poisson Analysis - Site Residuals -#' +#' #' @details #' -#' Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. -#' +#' Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. +#' #' @section Statistical Methods: -#' -#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Site-level residuals are calculated `stats::predict.glm` via `broom::augment`. -#' -#' @section Data Specification: -#' -#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +#' +#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Site-level residuals are calculated `stats::predict.glm` via `broom::augment`. +#' +#' @section Data Specification: +#' +#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `TotalCount` - Number of Events -#' - `TotalExposure` - Number of days of exposure +#' - `TotalCount` - Number of Events +#' - `TotalExposure` - Number of days of exposure +#' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. #' -#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. -#' #' @importFrom stats glm offset poisson pnorm #' @importFrom broom augment -#' +#' #' @return input data frame with columns added for "Residuals" and "PredictedCount" -#' -#' @examples +#' +#' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) -#' dfAnalyzed <- Analyze_Poisson( dfTransformed ) -#' +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) +#' dfAnalyzed <- Analyze_Poisson( dfTransformed ) +#' #' @export Analyze_Poisson <- function( dfTransformed ){ stopifnot( - is.data.frame(dfTransformed), - all(c("SiteID", "N", "TotalExposure", "TotalCount") %in% names(dfTransformed)) + is.data.frame(dfTransformed), + all(c("SiteID", "N", "TotalExposure", "TotalCount") %in% names(dfTransformed)) ) dfModel <- dfTransformed %>% mutate(LogExposure = log( .data$TotalExposure) ) cModel <- stats::glm( - TotalCount ~ stats::offset(LogExposure), family=stats::poisson(link="log"), + TotalCount ~ stats::offset(LogExposure), family=stats::poisson(link="log"), data=dfModel ) - dfAnalyzed <- broom::augment(cModel, dfModel, type.predict = "response") %>% + dfAnalyzed <- broom::augment(cModel, dfModel, type.predict = "response") %>% rename( - Residuals=.data$.resid, + Residuals=.data$.resid, PredictedCount=.data$.fitted, ) %>% select(.data$SiteID, .data$N, .data$TotalExposure, .data$TotalCount, .data$Rate, .data$Residuals, .data$PredictedCount) %>% diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R index 3221f3fec..51faedf12 100644 --- a/R/Analyze_Poisson_PredictBounds.R +++ b/R/Analyze_Poisson_PredictBounds.R @@ -1,35 +1,35 @@ #' Poisson Analysis - Predicted Boundaries -#' +#' #' @details #' -#' Fits a Poisson model to site level data and then calculates predicted count values and upper- and lower- bounds for across the full range of exposure values. -#' +#' Fits a Poisson model to site level data and then calculates predicted count values and upper- and lower- bounds for across the full range of exposure values. +#' #' @section Statistical Methods: -#' -#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Upper and lower boundary values are then calculated using the method described here TODO: Add link. In short, -#' -#' @section Data Specification: -#' -#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +#' +#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Upper and lower boundary values are then calculated using the method described here TODO: Add link. In short, +#' +#' @section Data Specification: +#' +#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `TotalCount` - Number of Events -#' - `TotalExposure` - Number of days of exposure +#' - `TotalCount` - Number of Events +#' - `TotalExposure` - Number of days of exposure +#' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. +#' @param vThreshold upper and lower boundaries in residual space. Should be identical to the threhsolds used AE_Assess(). #' -#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. -#' @param vThreshold upper and lower boundaries in residual space. Should be identical to the threhsolds used AE_Assess(). -#' #' @importFrom stats glm offset poisson pnorm #' @importFrom broom augment #' @importFrom lamW lambertW0 lambertWm1 -#' +#' #' @return data frame containing predicted boundary values with upper and lower bounds across the range of observed values -#' -#' @examples +#' +#' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' dfBounds <- Analyze_Poisson_PredictBounds(dfTransformed, c(-5,5)) -#' +#' #' @export Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold=c(-5,5)){ @@ -45,7 +45,7 @@ Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold=c(-5,5)){ min(dfTransformed$LogExposure)-0.05, max(dfTransformed$LogExposure)+0.05, by=0.05 - )) %>% + )) %>% mutate( vMu = as.numeric( exp( .data$LogExposure * cModel$coefficients[2] + cModel$coefficients[1] ))) %>% mutate( vWHi = (vThreshold[2]^2 - 2 * .data$vMu) / ( 2 * exp(1) * .data$vMu )) %>% mutate( vWLo = (vThreshold[1]^2 - 2 * .data$vMu) / ( 2 * exp(1) * .data$vMu )) %>% diff --git a/R/Analyze_Wilcoxon.R b/R/Analyze_Wilcoxon.R index c025f8bd0..43676b48a 100644 --- a/R/Analyze_Wilcoxon.R +++ b/R/Analyze_Wilcoxon.R @@ -31,7 +31,7 @@ #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' dfAnalyzed <- Analyze_Wilcoxon( dfTransformed , strOutcome ="Rate") #' #' @export @@ -44,11 +44,11 @@ Analyze_Wilcoxon <- function(dfTransformed , strOutcome = "Rate") { ) wilcoxon_model <- function(site){ - form <- as.formula(paste0(strOutcome," ~ as.character(SiteID) =='", site,"'")) + form <- as.formula(paste0(strOutcome," ~ as.character(SiteID) =='", site,"'")) wilcox.test(form, exact = FALSE, conf.int = TRUE, data=dfTransformed) } - dfAnalyzed <- dfTransformed %>% + dfAnalyzed <- dfTransformed %>% mutate(model = map(.data$SiteID, wilcoxon_model)) %>% mutate(summary = map(.data$model, broom::glance)) %>% unnest(summary) %>% diff --git a/R/Consent_Assess.R b/R/Consent_Assess.R index 2316f0eb9..bedd5f6f5 100644 --- a/R/Consent_Assess.R +++ b/R/Consent_Assess.R @@ -1,73 +1,69 @@ -#' Consent Assessment -#' +#' Consent Assessment +#' #' @details -#' -#' The Consent Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag sites with participants who started study activities before consent was finalized. More details regarding the data pipeline and statistical methods are described below. -#' +#' +#' The Consent Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag sites with participants who started study activities before consent was finalized. More details regarding the data pipeline and statistical methods are described below. +#' #' @section Data Specification: -#' -#' The input data (`dfInput`) for Consent Assessment is typically created using \code{\link{Consent_Map_Raw}} and should be one record per person with columns for: +#' +#' The input data (`dfInput`) for Consent Assessment is typically created using \code{\link{Consent_Map_Raw}} and should be one record per person with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `Count` - Number of findings of errors/outliers. -#' -#' The Assessment +#' - `Count` - Number of findings of errors/outliers. +#' +#' The Assessment #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. -#' +#' #' @section Assessment methodology: #' -#' This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or +#' This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or #' Consent date later in time than the Randomization Date. 'N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites -#' With N greater than user specified `nThreshold` will be flagged. -#' -#' -#' +#' With N greater than user specified `nThreshold` will be flagged. +#' +#' +#' #' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count. #' @param nThreshold Any sites where 'N' is greater than nThreshold will be flagged. Default value is 0.5, which flags any site with one or more subjects meeting any of the criteria. -#' @param cLabel Assessment label. +#' @param strLabel Assessment label. #' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned. #' #' -#' @examples -#' +#' @examples +#' #'dfInput <- Consent_Map_Raw( -#' dfConsent = clindata::raw_consent, -#' dfRDSL = clindata::rawplus_rdsl, +#' dfConsent = clindata::raw_consent, +#' dfRDSL = clindata::rawplus_rdsl, #' strConsentReason = NULL #') #' #'Consent_Assess(dfInput) -#' -#' #' -#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. -#' +#' +#' +#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. +#' #' @export -Consent_Assess <- function( dfInput, nThreshold=0.5, cLabel="", bDataList=FALSE){ - +Consent_Assess <- function( dfInput, nThreshold=0.5, strLabel="", bDataList=FALSE){ + stopifnot( "dfInput is not a data.frame" = is.data.frame(dfInput), - "cLabel is not character" = is.character(cLabel), + "strLabel is not character" = is.character(strLabel), "bDataList is not logical" = is.logical(bDataList), "One or more of these columns: SubjectID, SiteID,and Count not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)), "nThreshold must be numeric" = is.numeric(nThreshold), "nThreshold must be length 1" = length(nThreshold) ==1 - - ) - - - + lAssess <- list() lAssess$dfInput <- dfInput - lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = 'Count' ) + lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, strCountCol = 'Count' ) lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(Estimate = .data$TotalCount) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed ,vThreshold = c(NA,nThreshold), strColumn = "TotalCount" ) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", cAssessment="Main Consent", cLabel= cLabel) - + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", strAssessment="Main Consent", strLabel= strLabel) + if(bDataList){ return(lAssess) } else { diff --git a/R/Flag.R b/R/Flag.R index f76709dde..ee1f09201 100644 --- a/R/Flag.R +++ b/R/Flag.R @@ -24,7 +24,7 @@ #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' dfAnalyzed <- Analyze_Wilcoxon( dfTransformed) #' dfFlagged <- Flag( dfAnalyzed ) #PValue < 0.05 flagged #' dfFlagged10 <- Flag( dfAnalyzed, vThreshold=c(0.10,NA) ) #PValue <0.10 flagged diff --git a/R/IE_Assess.R b/R/IE_Assess.R index 2c102e753..b84702733 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -1,67 +1,67 @@ -#' Inclusion/Exclusion Assessment +#' Inclusion/Exclusion Assessment -#' +#' #' @details -#' -#' The Inclusion/Exclusion Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag sites with Inclusion / Exclusion irregularities. More details regarding the data pipeline and statistical methods are described below. -#' +#' +#' The Inclusion/Exclusion Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag sites with Inclusion / Exclusion irregularities. More details regarding the data pipeline and statistical methods are described below. +#' #' @section Data Specification: -#' -#' The input data (`dfInput`) for IE Assessment is typically created using \code{\link{IE_Map_Raw}} and should be one record per person with columns for: +#' +#' The input data (`dfInput`) for IE Assessment is typically created using \code{\link{IE_Map_Raw}} and should be one record per person with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `Count` - Number of findings of errors/outliers. -#' -#' The Assessment +#' - `Count` - Number of findings of errors/outliers. +#' +#' The Assessment #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. -#' -#' -#' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, +#' +#' +#' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, #' @param nThreshold integer threshold values Flagging, integer values greater than will be flagged. -#' @param cLabel Assessment label +#' @param strLabel Assessment label #' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned #' #' -#' @examples -#' +#' @examples +#' #' dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, #' "0142", "X194X", 9, #' "0308", "X159X", 9, #' "0776", "X194X", 8, #' "1032", "X033X", 9 #' ) -#' +#' #' ie_summary <- IE_Assess(dfInput) -#' +#' #' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, #' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -#' +#' #' ie_summary2 <- IE_Assess(ie_input) #' #' -#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. -#' +#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. +#' #' @export -IE_Assess <- function( dfInput, nThreshold=0.5, cLabel="", bDataList=FALSE){ - +IE_Assess <- function( dfInput, nThreshold=0.5, strLabel="", bDataList=FALSE){ + stopifnot( "dfInput is not a data.frame" = is.data.frame(dfInput), - "cLabel is not character" = is.character(cLabel), + "strLabel is not character" = is.character(strLabel), "bDataList is not logical" = is.logical(bDataList), "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)) ) - - + + lAssess <- list() lAssess$dfInput <- dfInput - lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = "Count") + lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, strCountCol = "Count") lAssess$dfAnalyzed <-lAssess$dfTransformed %>% mutate(Estimate = .data$TotalCount) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , vThreshold = c(NA,nThreshold), strColumn = "Estimate" ) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", cAssessment="Inclusion/Exclusion", cLabel= cLabel) - + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="TotalCount", strAssessment="Inclusion/Exclusion", strLabel= strLabel) + if(bDataList){ return(lAssess) } else { diff --git a/R/PD_Assess.R b/R/PD_Assess.R index d50f21a38..8be3ef73f 100644 --- a/R/PD_Assess.R +++ b/R/PD_Assess.R @@ -1,58 +1,57 @@ #' Protocol Deviation Assessment using Poisson Regression -#' +#' #' @details -#' -#' The Protocol Deviation Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag possible outliers. More details regarding the data pipeline and statistical methods are described below. -#' +#' +#' The Protocol Deviation Assessment uses the standard GSM data pipeline (TODO add link to data vignette) to flag possible outliers. More details regarding the data pipeline and statistical methods are described below. +#' #' @section Data Specification: -#' -#' The input data (`dfInput`) for the PD Assessment is typically created using \code{\link{PD_Map_Raw}} and should be one record per person with columns for: +#' +#' The input data (`dfInput`) for the PD Assessment is typically created using \code{\link{PD_Map_Raw}} and should be one record per person with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `Count` - Number of Adverse Events -#' - `Exposure` - Number of days of exposure -#' -#' The Assessment +#' - `Count` - Number of Adverse Events +#' - `Exposure` - Number of days of exposure +#' +#' The Assessment #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. #' - \code{\link{Analyze_Poisson}} or \code{\link{Analyze_Wilcoxon}} creates `dfAnalyzed`. #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. -#' -#' @section Statistical Assumptions: -#' -#' A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `cMethod` parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in `vThreshold`. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. -#' -#' See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. -#' +#' +#' @section Statistical Assumptions: +#' +#' A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `strMethod` parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in `vThreshold`. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. +#' +#' See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. +#' #' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure #' @param vThreshold list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = Wilcoxon -#' @param nCutoff optional parameter to control the auto-thresholding -#' @param cLabel Assessment label -#' @param cMethod valid methods are "poisson" (the default), or "wilcoxon" +#' @param strLabel Assessment label +#' @param strMethod valid methods are "poisson" (the default), or "wilcoxon" #' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the finding data frame is returned #' -#' @examples +#' @examples #' dfInput <- PD_Map_Raw(dfPD = clindata::raw_protdev, dfRDSL = clindata::rawplus_rdsl) #' SafetyPD <- PD_Assess( dfInput ) -#' SafetyPD_Wilk <- PD_Assess( dfInput, cMethod="wilcoxon") +#' SafetyPD_Wilk <- PD_Assess( dfInput, strMethod="wilcoxon") #' -#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. +#' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. #' #' @export -PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="poisson", bDataList=FALSE){ +PD_Assess <- function( dfInput, vThreshold=NULL, strLabel="",strMethod="poisson", bDataList=FALSE){ stopifnot( "dfInput is not a data.frame" = is.data.frame(dfInput), - "cLabel is not character" = is.character(cLabel), - "cMethod is not 'poisson' or 'wilcoxon'" = cMethod %in% c("poisson","wilcoxon"), + "strLabel is not character" = is.character(strLabel), + "strMethod is not 'poisson' or 'wilcoxon'" = strMethod %in% c("poisson","wilcoxon"), "bDataList is not logical" = is.logical(bDataList) ) - + lAssess <- list() lAssess$dfInput <- dfInput - lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, cCountCol = "Count", cExposureCol = "Exposure") - - if(cMethod == "poisson"){ + lAssess$dfTransformed <- gsm::Transform_EventCount( lAssess$dfInput, strCountCol = "Count", strExposureCol = "Exposure") + + if(strMethod == "poisson"){ if(is.null(vThreshold)){ vThreshold = c(-5,5) }else{ @@ -63,11 +62,11 @@ PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="p ) } - lAssess$dfAnalyzed <- gsm::Analyze_Poisson( lAssess$dfTransformed) + lAssess$dfAnalyzed <- gsm::Analyze_Poisson( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'Residuals', vThreshold =vThreshold) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="Residuals", cAssessment="Safety", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strScoreCol="Residuals", strAssessment="Safety", strLabel= strLabel) - } else if(cMethod=="wilcoxon"){ + } else if(strMethod=="wilcoxon"){ if(is.null(vThreshold)){ vThreshold = c(0.0001,NA) }else{ @@ -77,12 +76,12 @@ PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="p "Upper limit (second element) for Wilcoxon vThreshold is not NA"= is.na(vThreshold[2]), "vThreshold is not length 2"=length(vThreshold)==2 ) - } - lAssess$dfAnalyzed <- gsm::Analyze_Wilcoxon( lAssess$dfTransformed) + } + lAssess$dfAnalyzed <- gsm::Analyze_Wilcoxon( lAssess$dfTransformed) lAssess$dfFlagged <- gsm::Flag( lAssess$dfAnalyzed , strColumn = 'PValue', vThreshold =vThreshold) - lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, cAssessment="Safety", cLabel= cLabel) + lAssess$dfSummary <- gsm::Summarize( lAssess$dfFlagged, strAssessment="Safety", strLabel= strLabel) } - + if(bDataList){ return(lAssess) } else { diff --git a/R/Summarize.R b/R/Summarize.R index 13f4aba52..8464b370e 100644 --- a/R/Summarize.R +++ b/R/Summarize.R @@ -16,34 +16,34 @@ #' #' @param dfFlagged data frame in format produced by \code{\link{Flag}} #' @param strScoreCol column from analysis results to be copied to `dfSummary$Score` -#' @param cAssessment brief description of current assessment -#' @param cLabel brief description of line item in current assessment +#' @param strAssessment brief description of current assessment +#' @param strLabel brief description of line item in current assessment #' #' @return Simplified finding data frame with columns: Assessment, Label, SiteID, N, Pvalue, Flag #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' dfAnalyzed <- Analyze_Wilcoxon( dfTransformed) #' dfFlagged <- Flag( dfAnalyzed , strColumn = 'PValue', strValueColumn = 'Rate') -#' dfSummary <- Summarize(dfFlagged, cAssessment="Safety", cLabel= "") +#' dfSummary <- Summarize(dfFlagged, strAssessment="Safety", strLabel= "") #' #' @import dplyr #' #' @export -Summarize <- function( dfFlagged , strScoreCol="PValue", cAssessment="", cLabel=""){ +Summarize <- function( dfFlagged , strScoreCol="PValue", strAssessment="", strLabel=""){ stopifnot( "dfFlagged is not a data frame" = is.data.frame(dfFlagged), - "cAssessment is not character" = is.character(cAssessment), - "cLabel is not character" = is.character(cLabel), + "strAssessment is not character" = is.character(strAssessment), + "strLabel is not character" = is.character(strLabel), "One or more of these columns: SiteID, N, Flag not found in dfFlagged" = all(c("SiteID", "N", "Flag",strScoreCol) %in% names(dfFlagged)), - "cAssessment must be length of 1" = length(cAssessment) == 1, - "cLabel must be length of 1" = length(cLabel) == 1 + "strAssessment must be length of 1" = length(strAssessment) == 1, + "strLabel must be length of 1" = length(strLabel) == 1 ) dfSummary <- dfFlagged %>% - mutate(Assessment = cAssessment) %>% - mutate(Label = cLabel) %>% + mutate(Assessment = strAssessment) %>% + mutate(Label = strLabel) %>% rename(Score = strScoreCol)%>% select(.data$Assessment,.data$Label, .data$SiteID,.data$N, .data$Score, .data$Flag) %>% arrange(.data$Score) diff --git a/R/Transform_EventCount.R b/R/Transform_EventCount.R index 27909b358..c261262d9 100644 --- a/R/Transform_EventCount.R +++ b/R/Transform_EventCount.R @@ -17,61 +17,61 @@ #' (`dfInput`) has the following required and optional columns: #' Required: #' - `SiteID` - Site ID -#' - `Count` - Number of Adverse Events the actual name of this column is specified by the parameter cCountCol. +#' - `Count` - Number of Adverse Events the actual name of this column is specified by the parameter strCountCol. #' Optional -#' - `Exposure` - Number of days of exposure, name specified by cExposureCol. +#' - `Exposure` - Number of days of exposure, name specified by strExposureCol. #' -#' The input data has one or more rows per site. Transform_EventCount sums cCountCol for a TotalCount for each site. -#' For data with an optional cExposureCol, a summed exposure is caculated for each site. +#' The input data has one or more rows per site. Transform_EventCount sums strCountCol for a TotalCount for each site. +#' For data with an optional strExposureCol, a summed exposure is caculated for each site. #' #' @param dfInput A data.frame with one record per person. -#' @param cCountCol Required. Numerical or logical. Column to be counted. -#' @param cExposureCol Optional. Numerical `Exposure` column. +#' @param strCountCol Required. Numerical or logical. Column to be counted. +#' @param strExposureCol Optional. Numerical `Exposure` column. #' -#' @return data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if cExposureCol is used. +#' @return data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if strExposureCol is used. #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' #' @import dplyr #' #' @export -Transform_EventCount <- function( dfInput , cCountCol, cExposureCol=NULL ){ +Transform_EventCount <- function( dfInput , strCountCol, strExposureCol=NULL ){ stopifnot( "dfInput is not a data frame" = is.data.frame(dfInput), - "cCountCol not found in input data" = cCountCol %in% names(dfInput), + "strCountCol not found in input data" = strCountCol %in% names(dfInput), "SiteID not found in input data" = "SiteID" %in% names(dfInput), - "cCount column is not numeric or logical" = is.numeric(dfInput[[cCountCol]]) | is.logical(dfInput[[cCountCol]]) + "strCountCol is not numeric or logical" = is.numeric(dfInput[[strCountCol]]) | is.logical(dfInput[[strCountCol]]) ) - if(anyNA(dfInput[[cCountCol]])) stop("NA's found in dfInput$Count") - if(!is.null(cExposureCol)){ + if(anyNA(dfInput[[strCountCol]])) stop("NA's found in dfInput$Count") + if(!is.null(strExposureCol)){ stopifnot( - "cExposureCol is not found in input data" = cExposureCol %in% names(dfInput), - "cExposureColumn is not numeric" = is.numeric(dfInput[[cExposureCol]]) + "strExposureCol is not found in input data" = strExposureCol %in% names(dfInput), + "strExposureColumn is not numeric" = is.numeric(dfInput[[strExposureCol]]) ) - ExposureNACount <- sum(is.na(dfInput[[cExposureCol]])) + ExposureNACount <- sum(is.na(dfInput[[strExposureCol]])) if(ExposureNACount>0){ - warning(paste0("Dropped ",ExposureNACount," record(s) from dfInput where cExposureColumn is NA.")) - dfInput <- dfInput %>% filter(!is.na(.data[[cExposureCol]])) + warning(paste0("Dropped ",ExposureNACount," record(s) from dfInput where strExposureColumn is NA.")) + dfInput <- dfInput %>% filter(!is.na(.data[[strExposureCol]])) } } - if(is.null(cExposureCol)){ + if(is.null(strExposureCol)){ dfTransformed <- dfInput %>% group_by(.data$SiteID) %>% summarise( N=n(), - TotalCount= sum(.data[[cCountCol]]), + TotalCount= sum(.data[[strCountCol]]), ) }else{ dfTransformed <- dfInput %>% group_by(.data$SiteID) %>% summarise( N=n(), - TotalCount= sum(.data[[cCountCol]]), - TotalExposure=sum(.data[[cExposureCol]]) + TotalCount= sum(.data[[strCountCol]]), + TotalExposure=sum(.data[[strExposureCol]]) )%>% mutate(Rate = .data$TotalCount/.data$TotalExposure) } diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R index cb228e8a5..8ff8a51b6 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Poisson.R @@ -2,28 +2,28 @@ #' #' @param dfFlagged analyze_poisson results with flags added. #' @param dfBounds data.frame giving prediction bounds for range of dfFlagged -#' @param unit exposure time unit. Defaults to "days". +#' @param strUnit exposure time unit. Defaults to "days". #' #' @return site level plot object #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) #' dfAnalyzed <- Analyze_Poisson( dfTransformed) #' dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) -#' +#' #' @import ggplot2 #' #' @export -Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ +Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ ### Plot of data p <- ggplot( dfFlagged, aes( - x=.data$LogExposure, - y=.data$TotalCount, + x=.data$LogExposure, + y=.data$TotalCount, color=as.factor(.data$Flag)) ) + # Formatting @@ -39,7 +39,7 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ ) + # Add chart elements geom_point() + - xlab(paste0("Site Total Exposure (",unit," - log scale)")) + + xlab(paste0("Site Total Exposure (",strUnit," - log scale)")) + ylab("Site Total Events") + geom_text( data = dfFlagged%>%filter(.data$Flag !=0), @@ -47,13 +47,13 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, unit="days"){ vjust = 1.5, col="red", size=3.5 - ) - + ) + if(!is.null(dfBounds)){ p<-p+ geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$MeanCount), color="red") + geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$LowerCount), color="red", linetype="dashed") + - geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$UpperCount), color="red", linetype="dashed") + geom_line( data = dfBounds, aes( x = .data$LogExposure, y = .data$UpperCount), color="red", linetype="dashed") } return(p) diff --git a/man/AE_Assess.Rd b/man/AE_Assess.Rd index 0e920a063..cbfb72421 100644 --- a/man/AE_Assess.Rd +++ b/man/AE_Assess.Rd @@ -7,8 +7,8 @@ AE_Assess( dfInput, vThreshold = NULL, - cLabel = "", - cMethod = "poisson", + strLabel = "", + strMethod = "poisson", bDataList = FALSE ) } @@ -17,9 +17,9 @@ AE_Assess( \item{vThreshold}{numeric vector with 2 threshold values. Defaults to c(-5,5) for method = "poisson" and c(.0001,NA) for method = Wilcoxon.} -\item{cLabel}{Assessment label} +\item{strLabel}{Assessment label} -\item{cMethod}{valid methods are "poisson" (the default), or "wilcoxon"} +\item{strMethod}{valid methods are "poisson" (the default), or "wilcoxon"} \item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the Summary data frame is returned} } @@ -56,7 +56,7 @@ The Assessment \section{Statistical Assumptions}{ -A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{cMethod} parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in \code{vThreshold}. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. +A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{strMethod} parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in \code{vThreshold}. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. } @@ -64,6 +64,6 @@ See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additio \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) SafetyAE <- AE_Assess( dfInput ) -SafetyAE_Wilk <- AE_Assess( dfInput, cMethod="wilcoxon") +SafetyAE_Wilk <- AE_Assess( dfInput, strMethod="wilcoxon") } diff --git a/man/Analyze_Chisq.Rd b/man/Analyze_Chisq.Rd index 7bedb3cf6..4b84338ff 100644 --- a/man/Analyze_Chisq.Rd +++ b/man/Analyze_Chisq.Rd @@ -41,7 +41,7 @@ The input data (\code{ dfTransformed}) for the Analyze_Chisq is typically create \examples{ dfInput <- Disp_Map(dfDisp = safetyData::adam_adsl, strCol = "DCREASCD",strReason = "Adverse Event") -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count' ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) dfAnalyzed <- Analyze_Chisq( dfTransformed ) } diff --git a/man/Analyze_Fisher.Rd b/man/Analyze_Fisher.Rd index c6234b300..4272435f0 100644 --- a/man/Analyze_Fisher.Rd +++ b/man/Analyze_Fisher.Rd @@ -41,7 +41,7 @@ The input data (\code{ dfTransformed}) for the Analyze_Fisher is typically creat \examples{ dfInput <- Disp_Map(dfDisp = safetyData::adam_adsl, strCol = "DCREASCD",strReason = "Adverse Event") -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count' ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) dfAnalyzed <- Analyze_Fisher( dfTransformed ) } diff --git a/man/Analyze_Poisson.Rd b/man/Analyze_Poisson.Rd index b7ac646df..500ef3e3c 100644 --- a/man/Analyze_Poisson.Rd +++ b/man/Analyze_Poisson.Rd @@ -38,7 +38,7 @@ The input data (\code{ dfTransformed}) for the Analyze_Poisson is typically crea \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) -dfAnalyzed <- Analyze_Poisson( dfTransformed ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) +dfAnalyzed <- Analyze_Poisson( dfTransformed ) } diff --git a/man/Analyze_Poisson_PredictBounds.Rd b/man/Analyze_Poisson_PredictBounds.Rd index cc5def38c..abfef0df6 100644 --- a/man/Analyze_Poisson_PredictBounds.Rd +++ b/man/Analyze_Poisson_PredictBounds.Rd @@ -40,7 +40,7 @@ The input data (\code{ dfTransformed}) for the Analyze_Poisson is typically crea \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) dfBounds <- Analyze_Poisson_PredictBounds(dfTransformed, c(-5,5)) } diff --git a/man/Analyze_Wilcoxon.Rd b/man/Analyze_Wilcoxon.Rd index 8c3cd3fda..9253d9c37 100644 --- a/man/Analyze_Wilcoxon.Rd +++ b/man/Analyze_Wilcoxon.Rd @@ -42,7 +42,7 @@ The input data (\code{ dfTransformed}) for the Analyze_Wilcoxon is typically cre \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) dfAnalyzed <- Analyze_Wilcoxon( dfTransformed , strOutcome ="Rate") } diff --git a/man/Consent_Assess.Rd b/man/Consent_Assess.Rd index 69fefbb82..6cb01e75d 100644 --- a/man/Consent_Assess.Rd +++ b/man/Consent_Assess.Rd @@ -4,14 +4,14 @@ \alias{Consent_Assess} \title{Consent Assessment} \usage{ -Consent_Assess(dfInput, nThreshold = 0.5, cLabel = "", bDataList = FALSE) +Consent_Assess(dfInput, nThreshold = 0.5, strLabel = "", bDataList = FALSE) } \arguments{ \item{dfInput}{input data with one record per person and the following required columns: SubjectID, SiteID, Count.} \item{nThreshold}{Any sites where 'N' is greater than nThreshold will be flagged. Default value is 0.5, which flags any site with one or more subjects meeting any of the criteria.} -\item{cLabel}{Assessment label.} +\item{strLabel}{Assessment label.} \item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned.} } @@ -53,13 +53,13 @@ With N greater than user specified \code{nThreshold} will be flagged. \examples{ dfInput <- Consent_Map_Raw( -dfConsent = clindata::raw_consent, -dfRDSL = clindata::rawplus_rdsl, +dfConsent = clindata::raw_consent, +dfRDSL = clindata::rawplus_rdsl, strConsentReason = NULL ) Consent_Assess(dfInput) - + } diff --git a/man/Flag.Rd b/man/Flag.Rd index 490d8af9c..87a899c90 100644 --- a/man/Flag.Rd +++ b/man/Flag.Rd @@ -44,7 +44,7 @@ In short, the following columns are considered: \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) dfAnalyzed <- Analyze_Wilcoxon( dfTransformed) dfFlagged <- Flag( dfAnalyzed ) #PValue < 0.05 flagged dfFlagged10 <- Flag( dfAnalyzed, vThreshold=c(0.10,NA) ) #PValue <0.10 flagged diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 0548e79ed..09a7d2106 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -4,14 +4,14 @@ \alias{IE_Assess} \title{Inclusion/Exclusion Assessment} \usage{ -IE_Assess(dfInput, nThreshold = 0.5, cLabel = "", bDataList = FALSE) +IE_Assess(dfInput, nThreshold = 0.5, strLabel = "", bDataList = FALSE) } \arguments{ \item{dfInput}{input data with one record per person and the following required columns: SubjectID, SiteID, Count,} \item{nThreshold}{integer threshold values Flagging, integer values greater than will be flagged.} -\item{cLabel}{Assessment label} +\item{strLabel}{Assessment label} \item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned} } @@ -50,12 +50,12 @@ The Assessment "0776", "X194X", 8, "1032", "X033X", 9 ) - + ie_summary <- IE_Assess(dfInput) - + ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') - + ie_summary2 <- IE_Assess(ie_input) diff --git a/man/PD_Assess.Rd b/man/PD_Assess.Rd index 37881649c..7583b8436 100644 --- a/man/PD_Assess.Rd +++ b/man/PD_Assess.Rd @@ -7,9 +7,8 @@ PD_Assess( dfInput, vThreshold = NULL, - nCutoff = 1, - cLabel = "", - cMethod = "poisson", + strLabel = "", + strMethod = "poisson", bDataList = FALSE ) } @@ -18,11 +17,9 @@ PD_Assess( \item{vThreshold}{list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = Wilcoxon} -\item{nCutoff}{optional parameter to control the auto-thresholding} +\item{strLabel}{Assessment label} -\item{cLabel}{Assessment label} - -\item{cMethod}{valid methods are "poisson" (the default), or "wilcoxon"} +\item{strMethod}{valid methods are "poisson" (the default), or "wilcoxon"} \item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the finding data frame is returned} } @@ -58,7 +55,7 @@ The Assessment \section{Statistical Assumptions}{ -A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{cMethod} parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in \code{vThreshold}. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. +A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{strMethod} parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in \code{vThreshold}. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. } @@ -66,6 +63,6 @@ See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additio \examples{ dfInput <- PD_Map_Raw(dfPD = clindata::raw_protdev, dfRDSL = clindata::rawplus_rdsl) SafetyPD <- PD_Assess( dfInput ) -SafetyPD_Wilk <- PD_Assess( dfInput, cMethod="wilcoxon") +SafetyPD_Wilk <- PD_Assess( dfInput, strMethod="wilcoxon") } diff --git a/man/Summarize.Rd b/man/Summarize.Rd index 1308741e3..44096def2 100644 --- a/man/Summarize.Rd +++ b/man/Summarize.Rd @@ -4,16 +4,16 @@ \alias{Summarize} \title{Make Summary Data Frame} \usage{ -Summarize(dfFlagged, strScoreCol = "PValue", cAssessment = "", cLabel = "") +Summarize(dfFlagged, strScoreCol = "PValue", strAssessment = "", strLabel = "") } \arguments{ \item{dfFlagged}{data frame in format produced by \code{\link{Flag}}} \item{strScoreCol}{column from analysis results to be copied to \code{dfSummary$Score}} -\item{cAssessment}{brief description of current assessment} +\item{strAssessment}{brief description of current assessment} -\item{cLabel}{brief description of line item in current assessment} +\item{strLabel}{brief description of line item in current assessment} } \value{ Simplified finding data frame with columns: Assessment, Label, SiteID, N, Pvalue, Flag @@ -40,9 +40,9 @@ Create a concise summary of assessment results that is easy to aggregate across \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) dfAnalyzed <- Analyze_Wilcoxon( dfTransformed) dfFlagged <- Flag( dfAnalyzed , strColumn = 'PValue', strValueColumn = 'Rate') -dfSummary <- Summarize(dfFlagged, cAssessment="Safety", cLabel= "") +dfSummary <- Summarize(dfFlagged, strAssessment="Safety", strLabel= "") } diff --git a/man/Transform_EventCount.Rd b/man/Transform_EventCount.Rd index 605aeae60..a14b1cf78 100644 --- a/man/Transform_EventCount.Rd +++ b/man/Transform_EventCount.Rd @@ -4,17 +4,17 @@ \alias{Transform_EventCount} \title{Transform Event Count} \usage{ -Transform_EventCount(dfInput, cCountCol, cExposureCol = NULL) +Transform_EventCount(dfInput, strCountCol, strExposureCol = NULL) } \arguments{ \item{dfInput}{A data.frame with one record per person.} -\item{cCountCol}{Required. Numerical or logical. Column to be counted.} +\item{strCountCol}{Required. Numerical or logical. Column to be counted.} -\item{cExposureCol}{Optional. Numerical \code{Exposure} column.} +\item{strExposureCol}{Optional. Numerical \code{Exposure} column.} } \value{ -data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if cExposureCol is used. +data.frame with one row per site with columns SiteID, N, TotalCount with additional columns Exposure and Rate if strExposureCol is used. } \description{ Convert from ADaM format to needed input format for Safety Assessment @@ -36,17 +36,17 @@ The input data (\code{dfInput}) for the AE Assessment is typically created using Required: \itemize{ \item \code{SiteID} - Site ID -\item \code{Count} - Number of Adverse Events the actual name of this column is specified by the parameter cCountCol. +\item \code{Count} - Number of Adverse Events the actual name of this column is specified by the parameter strCountCol. Optional -\item \code{Exposure} - Number of days of exposure, name specified by cExposureCol. +\item \code{Exposure} - Number of days of exposure, name specified by strExposureCol. } -The input data has one or more rows per site. Transform_EventCount sums cCountCol for a TotalCount for each site. -For data with an optional cExposureCol, a summed exposure is caculated for each site. +The input data has one or more rows per site. Transform_EventCount sums strCountCol for a TotalCount for each site. +For data with an optional strExposureCol, a summed exposure is caculated for each site. } \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) } diff --git a/man/Visualize_Poisson.Rd b/man/Visualize_Poisson.Rd index 681c4d3bb..371c2b89b 100644 --- a/man/Visualize_Poisson.Rd +++ b/man/Visualize_Poisson.Rd @@ -4,14 +4,14 @@ \alias{Visualize_Poisson} \title{Site-level visualization of site-level Poisson Model results} \usage{ -Visualize_Poisson(dfFlagged, dfBounds = NULL, unit = "days") +Visualize_Poisson(dfFlagged, dfBounds = NULL, strUnit = "days") } \arguments{ \item{dfFlagged}{analyze_poisson results with flags added.} \item{dfBounds}{data.frame giving prediction bounds for range of dfFlagged} -\item{unit}{exposure time unit. Defaults to "days".} +\item{strUnit}{exposure time unit. Defaults to "days".} } \value{ site level plot object @@ -21,7 +21,7 @@ Site-level visualization of site-level Poisson Model results } \examples{ dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) dfAnalyzed <- Analyze_Poisson( dfTransformed) dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) diff --git a/tests/testthat/test_AE_Assess.R b/tests/testthat/test_AE_Assess.R index 9ce158372..aa77b593d 100644 --- a/tests/testthat/test_AE_Assess.R +++ b/tests/testthat/test_AE_Assess.R @@ -19,15 +19,15 @@ test_that("list of df created when bDataList=TRUE",{ test_that("incorrect inputs throw errors",{ expect_error(AE_Assess(list())) expect_error(AE_Assess("Hi")) - expect_error(AE_Assess(ae_input, cLabel=123)) - expect_error(AE_Assess(ae_input, cMethod="abacus")) + expect_error(AE_Assess(ae_input, strLabel=123)) + expect_error(AE_Assess(ae_input, strMethod="abacus")) expect_error(AE_Assess(ae_input, bDataList="Yes")) expect_error(AE_Assess(ae_input %>% select(-SubjectID))) expect_error(AE_Assess(ae_input %>% select(-SiteID))) expect_error(AE_Assess(ae_input %>% select(-Count))) expect_error(AE_Assess(ae_input %>% select(-Exposure))) expect_error(AE_Assess(ae_input %>% select(-Rate))) - expect_error(AE_Assess(ae_input, cMethod=c("wilcoxon", "poisson"))) + expect_error(AE_Assess(ae_input, strMethod=c("wilcoxon", "poisson"))) }) diff --git a/tests/testthat/test_Analyze_Poisson.R b/tests/testthat/test_Analyze_Poisson.R index 0eb9fa9ad..72dafc0da 100644 --- a/tests/testthat/test_Analyze_Poisson.R +++ b/tests/testthat/test_Analyze_Poisson.R @@ -1,10 +1,10 @@ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae -) +) test_that("output created as expected and has correct structure",{ - ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) + ae_prep <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) ae_anly <- Analyze_Poisson(ae_prep) expect_true(is.data.frame(ae_anly)) expect_equal(sort(unique(ae_input$SiteID)), sort(ae_anly$SiteID)) diff --git a/tests/testthat/test_Analyze_Wilcoxon.R b/tests/testthat/test_Analyze_Wilcoxon.R index 743ead3c5..5d9d0cd66 100644 --- a/tests/testthat/test_Analyze_Wilcoxon.R +++ b/tests/testthat/test_Analyze_Wilcoxon.R @@ -3,7 +3,7 @@ ae_input <- AE_Map_Adam( safetyData::adam_adae ) -ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) +ae_prep <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) test_that("output created as expected and has correct structure",{ aew_anly <-Analyze_Wilcoxon(ae_prep, strOutcome = "Rate") @@ -15,6 +15,8 @@ test_that("output created as expected and has correct structure",{ test_that("incorrect inputs throw errors",{ expect_error(Analyze_Wilcoxon(list())) expect_error(Analyze_Wilcoxon("Hi")) + expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = "coffee")) + expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = c("Rate", "something else"))) }) test_that("error given if required column not found",{ diff --git a/tests/testthat/test_Consent_Assess.R b/tests/testthat/test_Consent_Assess.R index 1bc104c98..c8f699371 100644 --- a/tests/testthat/test_Consent_Assess.R +++ b/tests/testthat/test_Consent_Assess.R @@ -16,7 +16,7 @@ dfRDSL_test <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, consent_input <- Consent_Map_Raw(dfConsent = dfConsent, dfRDSL= dfRDSL_test) test_that("summary df created as expected and has correct structure",{ - consent_list <- Consent_Assess(consent_input) + consent_list <- Consent_Assess(consent_input) expect_true(is.data.frame(consent_list)) expect_equal(names(consent_list),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) @@ -33,8 +33,7 @@ test_that("list of df created when bDataList=TRUE",{ test_that("incorrect inputs throw errors",{ expect_error(Consent_Assess(list())) expect_error(Consent_Assess("Hi")) - expect_error(Consent_Assess(consent_input, cLabel=123)) - expect_error(Consent_Assess(consent_input, cMethod="abacus")) + expect_error(Consent_Assess(consent_input, strLabel=123)) expect_error(Consent_Assess(consent_input, bDataList="Yes")) expect_error(Consent_Assess(consent_input, nThreshold = "A")) expect_error(Consent_Assess(consent_input, nThreshold = c(1,2))) diff --git a/tests/testthat/test_Consent_Map_Raw.R b/tests/testthat/test_Consent_Map_Raw.R index 97d2066c8..26d511b09 100644 --- a/tests/testthat/test_Consent_Map_Raw.R +++ b/tests/testthat/test_Consent_Map_Raw.R @@ -55,7 +55,7 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ expect_error( - Consent_Map_Raw( + Consent_Map_Raw( dfConsent = dfConsent_test %>% rename(ID = SUBJID), dfRDSL = dfRDSL_test ) @@ -66,14 +66,14 @@ test_that("error given if required column not found",{ dfRDSL = dfRDSL_test ) ) - + expect_error( Consent_Map_Raw( dfConsent_test %>% select(-INVID) , dfRDSL = dfRDSL_test ) ) - + expect_error( Consent_Map_Raw( dfConsent_test %>% select(-CONSCAT_STD), @@ -86,43 +86,43 @@ test_that("error given if required column not found",{ dfRDSL = dfRDSL_test ) ) - + expect_error( Consent_Map_Raw( dfConsent_test %>% select(-CONSDAT), dfRDSL = dfRDSL_test ) ) - + expect_error( Consent_Map_Raw( dfConsent_test, dfRDSL = dfRDSL_test %>% select(-SUBJID) ) ) - + expect_error( Consent_Map_Raw( dfConsent_test, dfRDSL = dfRDSL_test %>% select(-RGMNDTN) ) ) - - + + expect_error( Consent_Map_Raw( dfConsent_test, dfRDSL = dfRDSL_test %>% select(- SubjectID) ) ) - + expect_error( Consent_Map_Raw( dfConsent_test, dfRDSL = dfRDSL_test %>% select(- SiteID) ) ) - + expect_error( Consent_Map_Raw( dfConsent_test, @@ -133,12 +133,12 @@ test_that("error given if required column not found",{ test_that("output is correct given clindata example input",{ - + expect_equal(dfInput_test, Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test)) - - + + }) dfConsent_test_NA1 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, @@ -166,21 +166,21 @@ dfRDSL_test_NA2<- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, test_that("NA's in SubjectID and SUBJID are handled correctly",{ expect_error(Consent_Map_Raw(dfConsent = dfConsent_test_NA1, dfRDSL = dfRDSL_test_NA1)) expect_error(Consent_Map_Raw(dfConsent = dfConsent_test_NA2, dfRDSL = dfRDSL_test_NA2)) - + }) test_that("Incorrect strConsentReason throws errors",{ expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = c("A","B"))) expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = 1.23)) expect_error(Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = "Name_Not_in_data")) - + }) dfConsent_test2 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, 1, "MAINCONSENT", "Yes", "2014-12-25", 1, "MAINCONSENT", "No", "2014-12-25") - + dfRDSL_test2 <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, 1, 1, "2013-12-25", 2, 2, "2015-12-25") @@ -197,21 +197,21 @@ test_that("NA's in data are removed and handled correctly",{ expect_equal( tibble::tribble( ~SubjectID, ~SiteID, ~Count, 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) - + dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,3] = NA expect_equal( tibble::tribble( ~SubjectID, ~SiteID, ~Count, 1, 1, 1, 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) - + dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA expect_equal( tibble::tribble( ~SubjectID, ~SiteID, ~Count, 1, 1, 1, 1, 1, 1), suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in))) - - + + }) test_that("Warning provided for missing (NA) SiteID's in dfRDSL",{ diff --git a/tests/testthat/test_Flag.R b/tests/testthat/test_Flag.R index 64e33d1f2..b12355947 100644 --- a/tests/testthat/test_Flag.R +++ b/tests/testthat/test_Flag.R @@ -3,7 +3,7 @@ ae_input <- AE_Map_Adam( safetyData::adam_adae ) -ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) +ae_prep <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) ae_anly <- Analyze_Poisson(ae_prep) ae_anly_wilcoxon <- Analyze_Wilcoxon(ae_prep, strOutcome="Rate") diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index 08bf6600e..6d6cab33b 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -5,7 +5,7 @@ ie_input <- suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus test_that("summary df created as expected and has correct structure",{ - ie_list <- IE_Assess(ie_input) + ie_list <- IE_Assess(ie_input) expect_true(is.data.frame(ie_list)) expect_equal(names(ie_list),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) @@ -19,9 +19,9 @@ test_that("list of df created when bDataList=TRUE",{ test_that("incorrect inputs throw errors",{ expect_error(IE_Assess(list())) expect_error(IE_Assess("Hi")) - expect_error(IE_Assess(ie_input, cLabel=123)) - expect_error(IE_Assess(ie_input, cMethod="abacus")) + expect_error(IE_Assess(ie_input, strLabel=123)) expect_error(IE_Assess(ie_input, bDataList="Yes")) + expect_error(IE_Assess(ie_input, nThreshold=FALSE)) }) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 3e6e07fd6..971a9ac13 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -1,9 +1,9 @@ test_that("output created as expected and has correct structure",{ - ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) + ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_true(is.data.frame(ie_input)) - + expect_equal( names(ie_input), c("SubjectID","SiteID","Count")) @@ -16,7 +16,7 @@ test_that("incorrect inputs throw errors",{ test_that("incorrect inputs throw errors",{ - + expect_error(IE_Map_Raw(list(), list())) expect_error(IE_Map_Raw( clindata::raw_ie_all, list(), strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_error(IE_Map_Raw(list())) @@ -26,10 +26,10 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ expect_error( - IE_Map_Raw( + IE_Map_Raw( clindata::raw_ie_all %>% rename(ID = SUBJID), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -37,25 +37,25 @@ test_that("error given if required column not found",{ IE_Map_Raw( clindata::raw_ie_all , clindata::rawplus_rdsl%>% select(-SiteID), - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IECAT), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IETESTCD), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -63,26 +63,26 @@ test_that("error given if required column not found",{ IE_Map_Raw( clindata::raw_ie_all %>% select(-IETEST), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IEORRES), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) expect_silent( suppressWarnings( - IE_Map_Raw( + IE_Map_Raw( clindata::raw_ie_all %>% select(-PROJECT), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -95,7 +95,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ # vCategoryValues = c("Inclusion","Exclusion"), # strResultCol = 'IEORRES_STD', # vExpectedResultValues = c(0,1) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -104,7 +104,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ strResultCol = 'IEORRES' )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -113,7 +113,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ strResultCol = 'Not_A_Name' )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -123,7 +123,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ vExpectedResultValues = c("A",1,3) )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -136,7 +136,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ }) test_that("output is correct given clindata example input",{ - + dfIE <- clindata::raw_ie_all dfIE$SUBJID <- as.character(dfIE$SUBJID) @@ -147,7 +147,7 @@ dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, "1218", "X126X" ) - + dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, "0496", "X055X", 15L, diff --git a/tests/testthat/test_PD_Assess.R b/tests/testthat/test_PD_Assess.R index 0789ea419..9e02e7417 100644 --- a/tests/testthat/test_PD_Assess.R +++ b/tests/testthat/test_PD_Assess.R @@ -2,7 +2,7 @@ rdsl<-clindata::rawplus_rdsl %>% filter(RandFlag=="Y") pd_input <- PD_Map_Raw(dfPD = clindata::raw_protdev,dfRDSL = rdsl) test_that("summary df created as expected and has correct structure",{ - pd_assessment <- PD_Assess(pd_input) + pd_assessment <- PD_Assess(pd_input) expect_true(is.data.frame(pd_assessment)) expect_equal(names(pd_assessment),c("Assessment","Label", "SiteID", "N", "Score", "Flag")) }) @@ -16,8 +16,8 @@ test_that("list of df created when bDataList=TRUE",{ test_that("incorrect inputs throw errors",{ expect_error(PD_Assess(list())) expect_error(PD_Assess("Hi")) - expect_error(PD_Assess(pd_input, cLabel=123)) - expect_error(PD_Assess(pd_input, cMethod="abacus")) + expect_error(PD_Assess(pd_input, strLabel=123)) + expect_error(PD_Assess(pd_input, strMethod="abacus")) expect_error(PD_Assess(pd_input, bDataList="Yes")) }) diff --git a/tests/testthat/test_PD_Map_Raw.R b/tests/testthat/test_PD_Map_Raw.R index 75e2eef4b..6c243769e 100644 --- a/tests/testthat/test_PD_Map_Raw.R +++ b/tests/testthat/test_PD_Map_Raw.R @@ -7,7 +7,7 @@ test_that("output created as expected and has correct structure",{ }) test_that("incorrect inputs throw errors",{ - + expect_error(PD_Map_Raw(list(), list())) expect_error(PD_Map_Raw( clindata::raw_protdev, list())) expect_error(PD_Map_Raw(list(), clindata::rawplus_rdsl )) @@ -17,47 +17,47 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ expect_error( - PD_Map_Raw( - clindata::raw_protdev %>% rename(ID = SUBJID), - clindata::rawplus_rdsl + PD_Map_Raw( + clindata::raw_protdev %>% rename(ID = SUBJID), + clindata::rawplus_rdsl ) ) - + expect_error( PD_Map_Raw( clindata::raw_protdev , clindata::rawplus_rdsl %>% select(-SiteID) ) ) - + expect_error( - PD_Map_Raw( - clindata::raw_protdev , + PD_Map_Raw( + clindata::raw_protdev , clindata::rawplus_rdsl %>% select(-SubjectID) ) ) - - - + + + expect_error( - PD_Map_Raw( - clindata::raw_protdev , + PD_Map_Raw( + clindata::raw_protdev , clindata::rawplus_rdsl, strExposureCol="Exposure" ) ) - + expect_error( - PD_Map_Raw( - clindata::raw_protdev , + PD_Map_Raw( + clindata::raw_protdev , clindata::rawplus_rdsl %>% select(-SiteID) ) ) - - + + expect_silent( - PD_Map_Raw( - clindata::raw_protdev %>% select(-COUNTRY), + PD_Map_Raw( + clindata::raw_protdev %>% select(-COUNTRY), clindata::rawplus_rdsl ) ) @@ -65,30 +65,30 @@ test_that("error given if required column not found",{ test_that("output is correct given example input",{ - - + + dfPD <- tribble(~SUBJID, 1,1,1,1,2,2) - + dfTos<-tribble( ~SubjectID, ~SiteID, ~TimeOnStudy, 1, 1, 10, 2, 1, NA, 3, 1, 30 ) - - + + dfInput <-tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, 1, 1, 4, 10, 0.4, 2, 1, 2, NA, NA, - 3, 1, 0, 30, 0 + 3, 1, 0, 30, 0 ) - - + + expect_equal(dfInput, PD_Map_Raw(dfPD = dfPD, dfRDSL = dfTos)) - + dfPD2 <- tribble(~SUBJID, 1,1,1,1,2,2,4,4) - + dfTos2<-tribble( ~SubjectID, ~SiteID, ~TimeOnStudy, 1, 1, 10, @@ -96,8 +96,8 @@ test_that("output is correct given example input",{ 3, 1, 30, 4, 2, 50 ) - - + + dfInput2 <-tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, 1, 1, 4, 10, 0.4, @@ -105,19 +105,19 @@ test_that("output is correct given example input",{ 3, 1, 0, 30, 0 , 4, 2, 2, 50, .04 ) - - - + + + expect_equal(dfInput2, PD_Map_Raw(dfPD = dfPD2, dfRDSL = dfTos2)) - - - + + + }) test_that("NA values in input data are handled",{ - + dfPD3 <- tribble(~SUBJID, 1,1,1,1,2,2,4,4) - + dfTos3<-tribble( ~SubjectID, ~SiteID, ~TimeOnStudy, NA, 1, 10, @@ -125,8 +125,8 @@ test_that("NA values in input data are handled",{ 3, NA, 30, 4, 2, 50 ) - - + + dfInput3 <-tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, NA, 1, 0, 10, 0, @@ -134,11 +134,11 @@ test_that("NA values in input data are handled",{ 3, NA, 0, 30, 0 , 4, 2, 2, 50, .04 ) - + expect_equal(dfInput3, PD_Map_Raw(dfPD = dfPD3, dfRDSL = dfTos3)) - + dfPD4 <- tribble(~SUBJID, 1,NA,1,1,2,2,4,4) - + dfTos4<-tribble( ~SubjectID, ~SiteID, ~TimeOnStudy, NA, 1, 10, @@ -146,8 +146,8 @@ test_that("NA values in input data are handled",{ 3, NA, 30, 4, 2, 50 ) - - + + dfInput4 <-tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, NA, 1, 0, 10, 0, @@ -155,10 +155,10 @@ test_that("NA values in input data are handled",{ 3, NA, 0, 30, 0 , 4, 2, 2, 50, .04 ) - + expect_equal(dfInput4, PD_Map_Raw(dfPD = dfPD4, dfRDSL = dfTos4)) - - + + }) diff --git a/tests/testthat/test_Summarize.R b/tests/testthat/test_Summarize.R index 3d4fd3c3a..ef3e046d8 100644 --- a/tests/testthat/test_Summarize.R +++ b/tests/testthat/test_Summarize.R @@ -3,7 +3,7 @@ ae_input <- AE_Map_Adam( safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) +dfTransformed <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) dfAnalyzed <- gsm::Analyze_Poisson( dfTransformed) dfFlagged <- gsm::Flag(dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) @@ -19,8 +19,8 @@ test_that("incorrect inputs throw errors",{ expect_error(Summarize("Hi")) expect_error(Summarize(ae_flag,12312)) expect_error(Summarize(dfFlagged, strScoreCol = "wombat")) - expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", cLabel = c("pizza", "donuts"))) - expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", cAssessment = c("to assess", "to not assess"))) + expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", strLabel = c("pizza", "donuts"))) + expect_error(Summarize(dfFlagged, strScoreCol = "Residuals", strAssessment = c("to assess", "to not assess"))) }) test_that("error given if required column not found",{ diff --git a/tests/testthat/test_Transform_EventCount.R b/tests/testthat/test_Transform_EventCount.R index fec6ca7ff..0c52acec5 100644 --- a/tests/testthat/test_Transform_EventCount.R +++ b/tests/testthat/test_Transform_EventCount.R @@ -4,11 +4,11 @@ ae_input <- AE_Map_Adam( ) test_that("output created as expected and has correct structure",{ - ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) + ae_prep <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) expect_true(is.data.frame(ae_prep)) expect_equal(sort(unique(ae_input$SiteID)), sort(ae_prep$SiteID)) - expect_equal(names(Transform_EventCount(ae_input, cCountCol = "Count")), c("SiteID", "N", "TotalCount")) - expect_equal(names(Transform_EventCount(ae_input, cCountCol = "Count", cExposureCol = "Exposure")), c("SiteID", "N", "TotalCount", "TotalExposure", "Rate")) + expect_equal(names(Transform_EventCount(ae_input, strCountCol = "Count")), c("SiteID", "N", "TotalCount")) + expect_equal(names(Transform_EventCount(ae_input, strCountCol = "Count", strExposureCol = "Exposure")), c("SiteID", "N", "TotalCount", "TotalExposure", "Rate")) }) test_that("cCount works as expected",{ @@ -16,13 +16,13 @@ test_that("cCount works as expected",{ SiteID = rep("site1",30), event = c(rep(0,5),rep(1,15),rep(2,10)) ) - EventCount <- Transform_EventCount(sim, cCountCol="event") + EventCount <- Transform_EventCount(sim, strCountCol="event") expect_equal(EventCount, tibble(SiteID="site1", N=30, TotalCount=35)) sim2<-data.frame( SiteID = c(rep("site1",10), rep("site2",8),rep("site3",12)), event = c(rep(0,5),rep(1,15),rep(2,10)) ) - EventCount2 <- Transform_EventCount(sim2, cCountCol="event") + EventCount2 <- Transform_EventCount(sim2, strCountCol="event") expect_equal(EventCount2,tibble(SiteID=c("site1", "site2", "site3"), N=c(10,8,12), TotalCount=c(5,8,22))) }) @@ -34,7 +34,7 @@ test_that("cExposureCol works as expected",{ ndays = c(rep(5,6),rep(10,12),rep(10,12)) ) - EventCount3 <- Transform_EventCount(sim3, cCountCol="event", cExposureCol = 'ndays') + EventCount3 <- Transform_EventCount(sim3, strCountCol="event", strExposureCol = 'ndays') expect_equal(EventCount3,tibble(SiteID=c("site1", "site2", "site3"), N=c(11,7,12), TotalCount=c(5,7,24), TotalExposure = c(80,70,120), Rate = c(0.0625, 0.1, 0.2))) @@ -43,8 +43,8 @@ test_that("cExposureCol works as expected",{ test_that("incorrect inputs throw errors",{ expect_error(Transform_EventCount(list())) expect_error(Transform_EventCount("Hi")) - expect_error(Transform_EventCount(ae_input, cCountCol="NotACol")) - expect_error(Transform_EventCount(ae_input, cExposureCol="NotACol")) + expect_error(Transform_EventCount(ae_input, strCountCol="NotACol")) + expect_error(Transform_EventCount(ae_input, strExposureCol="NotACol")) }) test_that("NA in Exposure throws a warning and returns correct data",{ @@ -54,10 +54,10 @@ test_that("NA in Exposure throws a warning and returns correct data",{ ndays = c(NA,rep(5,5),NA, rep(10,11),NA, rep(10,10),NA) ) - expect_warning(Transform_EventCount(sim4, cCountCol="event", cExposureCol = 'ndays')) - expect_false(anyNA(suppressWarnings(Transform_EventCount(sim4, cCountCol="event", cExposureCol = 'ndays')) %>% pull(.data$TotalExposure))) + expect_warning(Transform_EventCount(sim4, strCountCol="event", strExposureCol = 'ndays')) + expect_false(anyNA(suppressWarnings(Transform_EventCount(sim4, strCountCol="event", strExposureCol = 'ndays')) %>% pull(.data$TotalExposure))) expect_equal( - suppressWarnings(Transform_EventCount(sim4, cCountCol="event", cExposureCol = 'ndays')), + suppressWarnings(Transform_EventCount(sim4, strCountCol="event", strExposureCol = 'ndays')), tibble( SiteID=c("site1", "site2", "site3"), N=c(9,7,10), @@ -69,13 +69,13 @@ test_that("NA in Exposure throws a warning and returns correct data",{ test_that("NA in Exposure is removed ",{ ae_input2 <-ae_input ae_input2[ 1, "Exposure"] = NA - expect_false( anyNA(suppressWarnings(Transform_EventCount(ae_input2, cCountCol = 'Count', cExposureCol = "Exposure")) %>% pull(.data$TotalExposure))) + expect_false( anyNA(suppressWarnings(Transform_EventCount(ae_input2, strCountCol = 'Count', strExposureCol = "Exposure")) %>% pull(.data$TotalExposure))) }) test_that("NA in Count throws an Error",{ ae_input2 <-ae_input ae_input2[ 1, "Count"] = NA - expect_error(suppressWarnings(Transform_EventCount(ae_input2, cCountCol = 'Count', cExposureCol = "Exposure"))) + expect_error(suppressWarnings(Transform_EventCount(ae_input2, strCountCol = 'Count', strExposureCol = "Exposure"))) }) From c2c6dc17532131f5f2dde0babffa4d53da31faae Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Fri, 4 Mar 2022 21:22:09 +0000 Subject: [PATCH 29/60] closes #228 - qc updates for Analyze_Wilcoxon() --- R/Analyze_Wilcoxon.R | 31 +++++++++++++++----------- man/Analyze_Wilcoxon.Rd | 13 ++++++----- tests/testthat/test_Analyze_Wilcoxon.R | 4 ++++ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/R/Analyze_Wilcoxon.R b/R/Analyze_Wilcoxon.R index c025f8bd0..96df38d68 100644 --- a/R/Analyze_Wilcoxon.R +++ b/R/Analyze_Wilcoxon.R @@ -8,26 +8,28 @@ #' #' @section Statistical Methods: #' -#' TODO Coming soon ... +#' A Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `strOutcome` parameter). #' #' @section Data Specification: #' -#' The input data (` dfTransformed`) for the Analyze_Wilcoxon is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: -#' - `SubjectID` - Unique subject ID +#' The input data (dfTransformed) for Analyze_Wilcoxon is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: #' - `SiteID` - Site ID -#' - `Count` - Number of Adverse Events -#' - `Exposure` - Number of days of exposure +#' - `N` - Number of participants +#' - `TotalCount` - Number of Adverse Events +#' - `TotalExposure` - Number of days of exposure +#' - `Rate` - Rate of exposure (TotalCount / TotalExposure) #' #' #' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}} #' @param strOutcome required, name of column in dfTransformed dataset to perform Wilcoxon test on. Default="Rate" #' +#' @import dplyr #' @importFrom stats wilcox.test as.formula -#' @importFrom purrr map map_df +#' @importFrom purrr map #' @importFrom broom glance #' @importFrom tidyr unnest #' -#' @return data.frame with one row per site, columns: SiteID, N , ..., Estimate, PValue +#' @return data.frame with one row per site, columns: SiteID, N, TotalCount, TotalExposure, Rate, Estimate, PValue #' #' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) @@ -39,19 +41,22 @@ Analyze_Wilcoxon <- function(dfTransformed , strOutcome = "Rate") { stopifnot( - is.data.frame(dfTransformed), - all(c("SiteID", "N", strOutcome) %in% names(dfTransformed)) + "dfTransformed is not a data.frame" = is.data.frame(dfTransformed), + "One or more of these columns: SiteID, N, or the value in strOutcome not found in dfTransformed" = all(c("SiteID", "N", strOutcome) %in% names(dfTransformed)), + "NA value(s) found in SiteID" = all(!is.na(dfTransformed[["SiteID"]])), + "strOutcome must be length 1" = length(strOutcome) == 1, + "strOutcome is not character" = is.character(strOutcome) ) wilcoxon_model <- function(site){ - form <- as.formula(paste0(strOutcome," ~ as.character(SiteID) =='", site,"'")) - wilcox.test(form, exact = FALSE, conf.int = TRUE, data=dfTransformed) + form <- as.formula(paste0(strOutcome," ~ as.character(SiteID) =='", site,"'")) + stats::wilcox.test(form, exact = FALSE, conf.int = TRUE, data=dfTransformed) } - dfAnalyzed <- dfTransformed %>% + dfAnalyzed <- dfTransformed %>% mutate(model = map(.data$SiteID, wilcoxon_model)) %>% mutate(summary = map(.data$model, broom::glance)) %>% - unnest(summary) %>% + tidyr::unnest(summary) %>% mutate(Estimate = .data$estimate *-1) %>% rename(PValue = .data[['p.value']]) %>% arrange(.data$PValue) %>% diff --git a/man/Analyze_Wilcoxon.Rd b/man/Analyze_Wilcoxon.Rd index 8c3cd3fda..9475c51c1 100644 --- a/man/Analyze_Wilcoxon.Rd +++ b/man/Analyze_Wilcoxon.Rd @@ -12,7 +12,7 @@ Analyze_Wilcoxon(dfTransformed, strOutcome = "Rate") \item{strOutcome}{required, name of column in dfTransformed dataset to perform Wilcoxon test on. Default="Rate"} } \value{ -data.frame with one row per site, columns: SiteID, N , ..., Estimate, PValue +data.frame with one row per site, columns: SiteID, N, TotalCount, TotalExposure, Rate, Estimate, PValue } \description{ Creates Analysis results data for Adverse Event assessment using the Wilcoxon sign-ranked test @@ -25,18 +25,19 @@ Fits a Wilcox Model to site-level data. \section{Statistical Methods}{ -TODO Coming soon ... +A Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{strOutcome} parameter). } \section{Data Specification}{ -The input data (\code{ dfTransformed}) for the Analyze_Wilcoxon is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +The input data (dfTransformed) for Analyze_Wilcoxon is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: \itemize{ -\item \code{SubjectID} - Unique subject ID \item \code{SiteID} - Site ID -\item \code{Count} - Number of Adverse Events -\item \code{Exposure} - Number of days of exposure +\item \code{N} - Number of participants +\item \code{TotalCount} - Number of Adverse Events +\item \code{TotalExposure} - Number of days of exposure +\item \code{Rate} - Rate of exposure (TotalCount / TotalExposure) } } diff --git a/tests/testthat/test_Analyze_Wilcoxon.R b/tests/testthat/test_Analyze_Wilcoxon.R index 743ead3c5..32eed10fc 100644 --- a/tests/testthat/test_Analyze_Wilcoxon.R +++ b/tests/testthat/test_Analyze_Wilcoxon.R @@ -15,10 +15,14 @@ test_that("output created as expected and has correct structure",{ test_that("incorrect inputs throw errors",{ expect_error(Analyze_Wilcoxon(list())) expect_error(Analyze_Wilcoxon("Hi")) + expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = "oops")) + expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = 1)) + expect_error(Analyze_Wilcoxon(ae_prep %>% mutate(SiteID = ifelse(SiteID == first(SiteID), NA, SiteID)))) }) test_that("error given if required column not found",{ expect_error(Analyze_Wilcoxon(ae_input %>% rename(total = TotalCount))) expect_error(Analyze_Wilcoxon(ae_input %>% select(-Rate))) + expect_error(Analyze_Wilcoxon(ae_input %>% select(-SiteID))) }) From fd507adb1b399f9b27ea81ec47783bb690e4d1b5 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Fri, 4 Mar 2022 22:04:39 +0000 Subject: [PATCH 30/60] closes 227 - qc updates for Analyze_Poisson() --- R/Analyze_Poisson.R | 54 ++++++++++++++------------- tests/testthat/test_Analyze_Poisson.R | 33 ++++++++++++++-- 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/R/Analyze_Poisson.R b/R/Analyze_Poisson.R index a3da6c2ae..120f05d10 100644 --- a/R/Analyze_Poisson.R +++ b/R/Analyze_Poisson.R @@ -1,52 +1,54 @@ #' Poisson Analysis - Site Residuals -#' +#' #' @details #' -#' Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. -#' +#' Fits a Poisson model to site level data and adds columns capturing Residual and Predicted Count for each site. +#' #' @section Statistical Methods: -#' -#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Site-level residuals are calculated `stats::predict.glm` via `broom::augment`. -#' -#' @section Data Specification: -#' -#' The input data (` dfTransformed`) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: -#' - `SubjectID` - Unique subject ID +#' +#' This function fits a poisson model to site-level data and then calculates residuals for each site. The poisson model is run using standard methods in the `stats` package by fitting a `glm` model with family set to `poisson` using a "log" link. Site-level residuals are calculated `stats::predict.glm` via `broom::augment`. +#' +#' @section Data Specification: +#' +#' The input data (`dfTransformed`) for Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: #' - `SiteID` - Site ID -#' - `TotalCount` - Number of Events -#' - `TotalExposure` - Number of days of exposure +#' - `N` - Number of participants +#' - `TotalCount` - Number of Adverse Events +#' - `TotalExposure` - Number of days of exposure +#' - `Rate` - Rate of exposure (TotalCount / TotalExposure) #' -#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. -#' +#' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure. +#' +#' @import dplyr #' @importFrom stats glm offset poisson pnorm #' @importFrom broom augment -#' -#' @return input data frame with columns added for "Residuals" and "PredictedCount" -#' -#' @examples +#' +#' @return input data.frame with columns added for "Residuals" and "PredictedCount" +#' +#' @examples #' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) #' dfTransformed <- Transform_EventCount( dfInput, cCountCol = 'Count', cExposureCol = "Exposure" ) -#' dfAnalyzed <- Analyze_Poisson( dfTransformed ) -#' +#' dfAnalyzed <- Analyze_Poisson( dfTransformed ) +#' #' @export - Analyze_Poisson <- function( dfTransformed ){ stopifnot( - is.data.frame(dfTransformed), - all(c("SiteID", "N", "TotalExposure", "TotalCount") %in% names(dfTransformed)) + "dfTransformed is not a data.frame" = is.data.frame(dfTransformed), + "One or more of these columns: SiteID, N, TotalExposure, TotalCount, Rate" = all(c("SiteID", "N", "TotalExposure", "TotalCount", "Rate") %in% names(dfTransformed)), + "NA value(s) found in SiteID" = all(!is.na(dfTransformed[["SiteID"]])) ) dfModel <- dfTransformed %>% mutate(LogExposure = log( .data$TotalExposure) ) cModel <- stats::glm( - TotalCount ~ stats::offset(LogExposure), family=stats::poisson(link="log"), + TotalCount ~ stats::offset(LogExposure), family=stats::poisson(link="log"), data=dfModel ) - dfAnalyzed <- broom::augment(cModel, dfModel, type.predict = "response") %>% + dfAnalyzed <- broom::augment(cModel, dfModel, type.predict = "response") %>% rename( - Residuals=.data$.resid, + Residuals=.data$.resid, PredictedCount=.data$.fitted, ) %>% select(.data$SiteID, .data$N, .data$TotalExposure, .data$TotalCount, .data$Rate, .data$Residuals, .data$PredictedCount) %>% diff --git a/tests/testthat/test_Analyze_Poisson.R b/tests/testthat/test_Analyze_Poisson.R index 0eb9fa9ad..81ca094b6 100644 --- a/tests/testthat/test_Analyze_Poisson.R +++ b/tests/testthat/test_Analyze_Poisson.R @@ -1,13 +1,26 @@ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae -) +) + +createNA <- function(x) { + + df <- AE_Map_Adam(safetyData::adam_adsl, safetyData::adam_adae) %>% + Transform_EventCount(cCountCol = "Count", cExposureCol = "Exposure") + + df[[x]][1] <- NA + + Analyze_Poisson(df) +} + + test_that("output created as expected and has correct structure",{ ae_prep <- Transform_EventCount( ae_input, cCountCol = 'Count', cExposureCol = "Exposure" ) ae_anly <- Analyze_Poisson(ae_prep) expect_true(is.data.frame(ae_anly)) expect_equal(sort(unique(ae_input$SiteID)), sort(ae_anly$SiteID)) + expect_equal(names(ae_anly), c("SiteID", "N", "TotalExposure", "TotalCount", "Rate", "Residuals", "PredictedCount")) }) test_that("incorrect inputs throw errors",{ @@ -17,6 +30,20 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ - expect_error(Analyze_Poisson(ae_input %>% rename(total = TotalCount))) + expect_error(Analyze_Poisson(ae_input %>% select(-SiteID))) + expect_error(Analyze_Poisson(ae_input %>% select(-N))) + expect_error(Analyze_Poisson(ae_input %>% select(-TotalCount))) + expect_error(Analyze_Poisson(ae_input %>% select(-TotalExposure))) expect_error(Analyze_Poisson(ae_input %>% select(-Rate))) }) + +test_that("NA values are caught", { + expect_error(createNA("SiteID")) + + # currently accept NA values + # expect_error(createNA("N")) + # expect_error(createNA("TotalCount")) + # expect_error(createNA("TotalExposure")) + # expect_error(createNA("Rate")) +}) + From 1d166288ec0fe182db9f2fc291646888df420bcd Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Fri, 4 Mar 2022 14:46:52 -0800 Subject: [PATCH 31/60] updated PD_Map and PD_Assess per QC standards --- R/PD_Assess.R | 23 +++++++++++--------- R/PD_Map_Raw.R | 11 +++++----- man/PD_Assess.Rd | 18 +++++++--------- man/PD_Map_Raw.Rd | 8 +++---- tests/testthat/test_PD_Assess.R | 36 +++++++++++++++++++++++++------- tests/testthat/test_PD_Map_Raw.R | 36 ++++++++++++++++++++++++++++++++ 6 files changed, 96 insertions(+), 36 deletions(-) diff --git a/R/PD_Assess.R b/R/PD_Assess.R index d50f21a38..6f890a99e 100644 --- a/R/PD_Assess.R +++ b/R/PD_Assess.R @@ -9,8 +9,9 @@ #' The input data (`dfInput`) for the PD Assessment is typically created using \code{\link{PD_Map_Raw}} and should be one record per person with columns for: #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' - `Count` - Number of Adverse Events +#' - `Count` - Number of protocal deviation events #' - `Exposure` - Number of days of exposure +#' - `Rate` - Rate of Exposure (Count / Exposure) #' #' The Assessment #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. @@ -22,14 +23,13 @@ #' #' A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the `cMethod` parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in `vThreshold`. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. #' -#' See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. +#' See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and their assumptions. #' -#' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure -#' @param vThreshold list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = Wilcoxon -#' @param nCutoff optional parameter to control the auto-thresholding -#' @param cLabel Assessment label -#' @param cMethod valid methods are "poisson" (the default), or "wilcoxon" -#' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the finding data frame is returned +#' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure, Rate. +#' @param vThreshold list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = "wilcoxon". +#' @param cLabel Assessment label. +#' @param cMethod valid methods are "poisson" (the default), or "wilcoxon". +#' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary data frame is returned. #' #' @examples #' dfInput <- PD_Map_Raw(dfPD = clindata::raw_protdev, dfRDSL = clindata::rawplus_rdsl) @@ -40,12 +40,15 @@ #' #' @export -PD_Assess <- function( dfInput, vThreshold=NULL, nCutoff=1, cLabel="",cMethod="poisson", bDataList=FALSE){ +PD_Assess <- function( dfInput, vThreshold=NULL, cLabel="",cMethod="poisson", bDataList=FALSE){ stopifnot( "dfInput is not a data.frame" = is.data.frame(dfInput), "cLabel is not character" = is.character(cLabel), + "Length of cLabel is not greater than 1" = length(cLabel) <=1 , "cMethod is not 'poisson' or 'wilcoxon'" = cMethod %in% c("poisson","wilcoxon"), - "bDataList is not logical" = is.logical(bDataList) + "cMethod must be length 1" = length(cMethod) == 1, + "bDataList is not logical" = is.logical(bDataList), + "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count","Exposure", "Rate") %in% names(dfInput)) ) lAssess <- list() diff --git a/R/PD_Map_Raw.R b/R/PD_Map_Raw.R index 81fb26a25..64e0fb920 100644 --- a/R/PD_Map_Raw.R +++ b/R/PD_Map_Raw.R @@ -20,11 +20,11 @@ #' #' #' -#' @param dfPD PD dataset with SUBJID column and rows for each Protocol Deviation -#' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol -#' @param strExposureCol Name of exposure column. 'TimeOnStudy' by default +#' @param dfPD PD dataset with required column SUBJID and rows for each Protocol Deviation. +#' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol. +#' @param strExposureCol Name of exposure column. 'TimeOnStudy' by default. #' -#' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count, Exposure, Rate +#' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count, Exposure, Rate. #' #' #' @examples @@ -37,9 +37,10 @@ PD_Map_Raw <- function( dfPD, dfRDSL, strExposureCol="TimeOnStudy" ){ stopifnot( "PD dataset not found"=is.data.frame(dfPD), - "Time on Study dataset is not found"=is.data.frame(dfRDSL), + "RDSL dataset is not found"=is.data.frame(dfRDSL), "SUBJID column not found in dfPD"="SUBJID" %in% names(dfPD), "strExposureCol is not character"=is.character(strExposureCol), + "Length of strExposureCol is not equal to 1"=length(strExposureCol) ==1 , "SubjectID, SiteID and strExposureCol columns not found in dfRDSL"=all(c("SubjectID","SiteID",strExposureCol) %in% names(dfRDSL)) ) diff --git a/man/PD_Assess.Rd b/man/PD_Assess.Rd index 37881649c..478805984 100644 --- a/man/PD_Assess.Rd +++ b/man/PD_Assess.Rd @@ -7,24 +7,21 @@ PD_Assess( dfInput, vThreshold = NULL, - nCutoff = 1, cLabel = "", cMethod = "poisson", bDataList = FALSE ) } \arguments{ -\item{dfInput}{input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure} +\item{dfInput}{input data with one record per person and the following required columns: SubjectID, SiteID, Count, Exposure, Rate.} -\item{vThreshold}{list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = Wilcoxon} +\item{vThreshold}{list of threshold values default c(-5,5) for method = "poisson", c(.0001,NA) for method = "wilcoxon".} -\item{nCutoff}{optional parameter to control the auto-thresholding} +\item{cLabel}{Assessment label.} -\item{cLabel}{Assessment label} +\item{cMethod}{valid methods are "poisson" (the default), or "wilcoxon".} -\item{cMethod}{valid methods are "poisson" (the default), or "wilcoxon"} - -\item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the finding data frame is returned} +\item{bDataList}{Should all assessment datasets be returned as a list? If False (the default), only the summary data frame is returned.} } \value{ If \code{bDataList} is false (the default), the summary data frame (\code{dfSummary}) is returned. If \code{bDataList} is true, a list containing all data in the standard data pipeline (\code{dfInput}, \code{dfTransformed}, \code{dfAnalyzed}, \code{dfFlagged} and \code{dfSummary}) is returned. @@ -42,8 +39,9 @@ The input data (\code{dfInput}) for the PD Assessment is typically created using \itemize{ \item \code{SubjectID} - Unique subject ID \item \code{SiteID} - Site ID -\item \code{Count} - Number of Adverse Events +\item \code{Count} - Number of protocal deviation events \item \code{Exposure} - Number of days of exposure +\item \code{Rate} - Rate of Exposure (Count / Exposure) } The Assessment @@ -60,7 +58,7 @@ The Assessment A Poisson or Wilcoxon model is used to generate estimates and p-values for each site (as specified with the \code{cMethod} parameter). Those model outputs are then used to flag possible outliers using the thresholds specified in \code{vThreshold}. In the Poisson model, sites with an estimand less than -5 are flagged as -1 and greater than 5 are flagged as 1 by default. For Wilcoxon, sites with p-values less than 0.0001 are flagged by default. -See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and thier assumptions. +See \code{\link{Analyze_Poisson}} and \code{\link{Analyze_Wilcoxon}} for additional details about the statistical methods and their assumptions. } \examples{ diff --git a/man/PD_Map_Raw.Rd b/man/PD_Map_Raw.Rd index e850f8da1..afa108fb3 100644 --- a/man/PD_Map_Raw.Rd +++ b/man/PD_Map_Raw.Rd @@ -7,14 +7,14 @@ PD_Map_Raw(dfPD, dfRDSL, strExposureCol = "TimeOnStudy") } \arguments{ -\item{dfPD}{PD dataset with SUBJID column and rows for each Protocol Deviation} +\item{dfPD}{PD dataset with required column SUBJID and rows for each Protocol Deviation.} -\item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol} +\item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID, SiteID, value specified in strExposureCol.} -\item{strExposureCol}{Name of exposure column. 'TimeOnStudy' by default} +\item{strExposureCol}{Name of exposure column. 'TimeOnStudy' by default.} } \value{ -Data frame with one record per person data frame with columns: SubjectID, SiteID, Count, Exposure, Rate +Data frame with one record per person data frame with columns: SubjectID, SiteID, Count, Exposure, Rate. } \description{ Convert from raw data format to needed input format for Safety Assessment diff --git a/tests/testthat/test_PD_Assess.R b/tests/testthat/test_PD_Assess.R index 0789ea419..dc109b8b7 100644 --- a/tests/testthat/test_PD_Assess.R +++ b/tests/testthat/test_PD_Assess.R @@ -19,17 +19,39 @@ test_that("incorrect inputs throw errors",{ expect_error(PD_Assess(pd_input, cLabel=123)) expect_error(PD_Assess(pd_input, cMethod="abacus")) expect_error(PD_Assess(pd_input, bDataList="Yes")) -}) - - -test_that("incorrect inputs throw errors",{ + expect_error(PD_Assess(pd_input %>% select(-SubjectID))) expect_error(PD_Assess(pd_input %>% select(-SiteID))) expect_error(PD_Assess(pd_input %>% select(-Count))) expect_error(PD_Assess(pd_input %>% select(-Exposure))) + expect_error(PD_Assess(pd_input %>% select(-Rate))) + expect_error(PD_Assess(pd_input, cMethod=c("wilcoxon", "poisson"))) + expect_error(PD_Assess(pd_input, vThreshold = "A")) + expect_error(PD_Assess(pd_input, vThreshold = 1)) + expect_error(PD_Assess(pd_input, cLabel = iris)) +}) + +test_that("Confirm expected functionality for PD_Assess input clabel ",{ + rdsl<-clindata::rawplus_rdsl %>% filter(RandFlag=="Y") + pd_input <- PD_Map_Raw(dfPD = clindata::raw_protdev,dfRDSL = rdsl) + pd_summary_df <- PD_Assess(pd_input, cLabel = "test_label") + expect_equal(pd_summary_df[1,"Label", drop = TRUE], 'test_label') +}) + +test_that("Confirm expected functionality for PD_Assess input cMethod ",{ + rdsl<-clindata::rawplus_rdsl %>% filter(RandFlag=="Y") + pd_input <- PD_Map_Raw(dfPD = clindata::raw_protdev,dfRDSL = rdsl) + pd_list <- PD_Assess(pd_input, cMethod = 'wilcoxon', bDataList = TRUE) + expect_true('PValue' %in% names(pd_list$dfAnalyzed)) + pd_list <- PD_Assess(pd_input, cMethod = 'poisson', bDataList = TRUE) + pd_list$dfAnalyzed + expect_true('PredictedCount' %in% names(pd_list$dfAnalyzed)) + }) -pd_list <- PD_Assess(pd_input, bDataList=TRUE) -expect_true(is.list(pd_list)) -expect_equal(names(pd_list),c('dfInput','dfTransformed','dfAnalyzed','dfFlagged','dfSummary')) +test_that("NA in dfInput$Count results in Error for PD_Assess",{ + pd_input_in <- pd_input; pd_input_in[1,"Count"] = NA + expect_error(PD_Assess(pd_input_in)) +}) + diff --git a/tests/testthat/test_PD_Map_Raw.R b/tests/testthat/test_PD_Map_Raw.R index 75e2eef4b..e9db43412 100644 --- a/tests/testthat/test_PD_Map_Raw.R +++ b/tests/testthat/test_PD_Map_Raw.R @@ -161,5 +161,41 @@ test_that("NA values in input data are handled",{ }) +test_that("strExposure user input error is handled correctly", { + expect_error( + PD_Map_Raw(clindata::raw_protdev,clindata::rawplus_rdsl, strExposureCol = 123) + ) + + expect_error( + PD_Map_Raw(clindata::raw_protdev,clindata::rawplus_rdsl, strExposureCol = c("A", "B")) + ) +}) + +test_that("Non-default value for strExposureCol is handled correctly",{ + dfPD4 <- tribble(~SUBJID, 1,NA,1,1,2,2,4,4) + + dfTos4<-tribble( + ~SubjectID, ~SiteID, ~TimeInOurClinicalTrial, + NA, 1, 10, + 2, 1, NA, + 3, NA, 30, + 4, 2, 50 + ) + + + dfInput4 <-tribble( + ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, + NA, 1, 0, 10, 0, + 2, 1, 2, NA, NA, + 3, NA, 0, 30, 0 , + 4, 2, 2, 50, .04 + ) + + expect_equal(dfInput4, PD_Map_Raw(dfPD = dfPD4, dfRDSL = dfTos4, strExposureCol = 'TimeInOurClinicalTrial')) + expect_error( PD_Map_Raw(dfPD = dfPD4, dfRDSL = dfTos4, strExposureCol = 'IncorrectColumnName')) + expect_error( PD_Map_Raw(dfPD = dfPD4, dfRDSL = dfTos4)) +}) + + From 17dd7a8f23d6da943de3cc301cce7f240c91c89f Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 16:02:39 +0000 Subject: [PATCH 32/60] closes 210 - qc updates for IE_Map_Raw() --- R/IE_Map_Raw.R | 70 ++++++++++++++++---------------- man/IE_Map_Raw.Rd | 8 ++-- tests/testthat/test_IE_Map_Raw.R | 66 ++++++++++++++++++------------ 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 1efed3ba2..4e90543db 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -1,14 +1,14 @@ #' Inclusion/Exclusion Assessment Mapping from Raw Data- Make Input Data -#' +#' #' Convert from raw data format to needed input format for Inclusion/Exclusion Assessment -#' +#' #' @details -#' -#' This function creates the required input for \code{\link{IE_Assess}}. -#' +#' +#' This function creates the required input for \code{\link{IE_Assess}}. +#' #' @section Data Specification: -#' -#' +#' +#' #' The following columns are required: #' - `dfIE` #' - `SUBJID` - Unique subject ID @@ -17,27 +17,27 @@ #' - `dfRDSL` #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID -#' -#' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. +#' +#' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. By default, includes required columns SUBJID, IVID, IECAT, IETESTCD, IEORRES. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID #' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' #' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). #' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". #' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". -#' +#' #' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count -#' +#' #' @examples #' -#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, +#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, #' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -#' +#' #' @import dplyr -#' -#' @export -IE_Map_Raw <- function( - dfIE = NULL, - dfRDSL = NULL, +#' +#' @export +IE_Map_Raw <- function( + dfIE, + dfRDSL, strCategoryCol = 'IECAT', vCategoryValues = c("Exclusion","Inclusion"), strResultCol = 'IEORRES_STD', @@ -45,49 +45,51 @@ IE_Map_Raw <- function( ){ ### Requires raw ie dataset - if(is.null(dfIE)) stop("IE dataset not found") if( ! all(c("SUBJID", strCategoryCol, strResultCol) %in% names(dfIE)) ) stop(paste0("SUBJID, ",strCategoryCol,", and " , strResultCol, " columns are required in ie dataset") ) - if(is.null(dfRDSL)) stop("RDSL dataset not found") if( !(all(c("SubjectID","SiteID") %in% names(dfRDSL)))) stop("SubjectID and SiteID column are required in RDSL dataset" ) - + stopifnot( "length of vExpectedResultValues is not equal to 2"= (length( vExpectedResultValues) ==2), - "length of vCategoryValues is not equal to 2"= (length( vCategoryValues) ==2) - - ) - + "length of vCategoryValues is not equal to 2"= (length( vCategoryValues) ==2), + "IE dataset not found" = !is.null(dfIE), + "dfRDSL dataset not found" = !is.null(dfRDSL), + "dfIE$SUBJID contains NA value(s)" = all(!is.na(dfIE[["SUBJID"]])), + "strCategoryCol contains NA value(s)" = all(!is.na(dfIE[[strCategoryCol]])), + "strResultCol contains NA value(s)" = all(!is.na(dfIE[[strResultCol]])) + ) + # filter records where SUBJID is missing and create basic flags - dfIE_long <- dfIE %>% + dfIE_long <- dfIE %>% filter(.data$SUBJID !="")%>% select(.data$SUBJID, .data[[strCategoryCol]], .data[[strResultCol]]) %>% mutate(expected=ifelse(.data[[strCategoryCol]] ==vCategoryValues[1],vExpectedResultValues[1],vExpectedResultValues[2])) %>% mutate(valid=.data[[strResultCol]]==.data$expected)%>% mutate(invalid=.data[[strResultCol]]!=.data$expected)%>% mutate(missing=!(.data[[strResultCol]] %in% vExpectedResultValues)) - + # collapse long data to one record per participant dfIE_Subj <- dfIE_long %>% group_by(.data$SUBJID) %>% summarise( - Total=n(), - Valid=sum(.data$valid), - Invalid=sum(.data$invalid), + Total=n(), + Valid=sum(.data$valid), + Invalid=sum(.data$invalid), Missing=sum(.data$missing) )%>% mutate(Count = .data$Invalid + .data$Missing) %>% rename(SubjectID = .data$SUBJID) %>% select(.data$SubjectID, .data$Count) %>% ungroup() - + missIE <- anti_join( dfIE_Subj, dfRDSL, by="SubjectID") if( nrow(missIE) > 0 ) warning("Not all SubjectID in IE found in RDSL") - + # merge IE and RDSL - dfInput <- dfRDSL %>% + dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID)%>% inner_join(dfIE_Subj, by="SubjectID") %>% select(.data$SubjectID, .data$SiteID, .data$Count) - + #Throw warning if a an ID in IE isn't found in RDSL return(dfInput) diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 3be18abfc..3ed3f35ec 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -5,8 +5,8 @@ \title{Inclusion/Exclusion Assessment Mapping from Raw Data- Make Input Data} \usage{ IE_Map_Raw( - dfIE = NULL, - dfRDSL = NULL, + dfIE, + dfRDSL, strCategoryCol = "IECAT", vCategoryValues = c("Exclusion", "Inclusion"), strResultCol = "IEORRES_STD", @@ -14,7 +14,7 @@ IE_Map_Raw( ) } \arguments{ -\item{dfIE}{ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol.} +\item{dfIE}{ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. By default, includes required columns SUBJID, IVID, IECAT, IETESTCD, IEORRES.} \item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID SiteID} @@ -56,7 +56,7 @@ The following columns are required: \examples{ -dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, +dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') } diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 3e6e07fd6..57e76eba2 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -1,22 +1,17 @@ test_that("output created as expected and has correct structure",{ - ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) + ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_true(is.data.frame(ie_input)) - + expect_equal( names(ie_input), c("SubjectID","SiteID","Count")) }) test_that("incorrect inputs throw errors",{ - expect_error(IE_Map_Raw(list(), list())) - expect_error(IE_Map_Raw("Hi","Mom")) -}) - - -test_that("incorrect inputs throw errors",{ - + expect_error(IE_Map_Raw(list(), list())) + expect_error(IE_Map_Raw("Hi","Mom")) expect_error(IE_Map_Raw(list(), list())) expect_error(IE_Map_Raw( clindata::raw_ie_all, list(), strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_error(IE_Map_Raw(list())) @@ -26,10 +21,10 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ expect_error( - IE_Map_Raw( + IE_Map_Raw( clindata::raw_ie_all %>% rename(ID = SUBJID), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -37,25 +32,25 @@ test_that("error given if required column not found",{ IE_Map_Raw( clindata::raw_ie_all , clindata::rawplus_rdsl%>% select(-SiteID), - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IECAT), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IETESTCD), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -63,26 +58,26 @@ test_that("error given if required column not found",{ IE_Map_Raw( clindata::raw_ie_all %>% select(-IETEST), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) - + expect_error( IE_Map_Raw( clindata::raw_ie_all %>% select(-IEORRES), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) expect_silent( suppressWarnings( - IE_Map_Raw( + IE_Map_Raw( clindata::raw_ie_all %>% select(-PROJECT), clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES' ) ) @@ -95,7 +90,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ # vCategoryValues = c("Inclusion","Exclusion"), # strResultCol = 'IEORRES_STD', # vExpectedResultValues = c(0,1) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -104,7 +99,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ strResultCol = 'IEORRES' )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -113,7 +108,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ strResultCol = 'Not_A_Name' )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -123,7 +118,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ vExpectedResultValues = c("A",1,3) )) ) - + expect_error( suppressWarnings(IE_Map_Raw( clindata::raw_ie_all, @@ -136,7 +131,7 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ }) test_that("output is correct given clindata example input",{ - + dfIE <- clindata::raw_ie_all dfIE$SUBJID <- as.character(dfIE$SUBJID) @@ -147,7 +142,7 @@ dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, "1218", "X126X" ) - + dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, "0496", "X055X", 15L, @@ -184,4 +179,21 @@ expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', s }) +test_that("NA values are handled correctly", { + + ieNASUBJID <- clindata::raw_ie_all %>% + mutate(SUBJID = rep(c(NA, "1234"), nrow(clindata::raw_ie_all)/2)) + + ieNAstrCategoryCol <- clindata::raw_ie_all %>% + mutate(IECAT_STD = rep(c(NA, "INCLUSION"), nrow(clindata::raw_ie_all)/2)) + + ieNAstrResultCol <- clindata::raw_ie_all %>% + mutate(IEORRES = rep(c(0, NA), nrow(clindata::raw_ie_all)/2)) + + expect_error(IE_Map_Raw(ieNASUBJID , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) + expect_error(IE_Map_Raw(ieNAstrCategoryCol , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) + expect_error(IE_Map_Raw(ieNAstrResultCol , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) +}) + + From 4d7ae7798ea132384fd3eb82331df67e829a8e7d Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 16:08:20 +0000 Subject: [PATCH 33/60] fix tests --- tests/testthat/test_Analyze_Wilcoxon.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test_Analyze_Wilcoxon.R b/tests/testthat/test_Analyze_Wilcoxon.R index 32eed10fc..265fb4c4c 100644 --- a/tests/testthat/test_Analyze_Wilcoxon.R +++ b/tests/testthat/test_Analyze_Wilcoxon.R @@ -21,8 +21,8 @@ test_that("incorrect inputs throw errors",{ }) test_that("error given if required column not found",{ - expect_error(Analyze_Wilcoxon(ae_input %>% rename(total = TotalCount))) - expect_error(Analyze_Wilcoxon(ae_input %>% select(-Rate))) - expect_error(Analyze_Wilcoxon(ae_input %>% select(-SiteID))) + expect_error(Analyze_Wilcoxon(ae_prep %>% rename(total = TotalCount))) + expect_error(Analyze_Wilcoxon(ae_prep %>% select(-Rate))) + expect_error(Analyze_Wilcoxon(ae_prep %>% select(-SiteID))) }) From db20462781cd7f72a5c0a7476912621022afd8d7 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 16:25:19 +0000 Subject: [PATCH 34/60] fix merge conflict again --- tests/testthat/test_Analyze_Wilcoxon.R | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/testthat/test_Analyze_Wilcoxon.R b/tests/testthat/test_Analyze_Wilcoxon.R index 2e9d9398e..12c5cf905 100644 --- a/tests/testthat/test_Analyze_Wilcoxon.R +++ b/tests/testthat/test_Analyze_Wilcoxon.R @@ -15,14 +15,10 @@ test_that("output created as expected and has correct structure",{ test_that("incorrect inputs throw errors",{ expect_error(Analyze_Wilcoxon(list())) expect_error(Analyze_Wilcoxon("Hi")) -<<<<<<< HEAD - expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = "oops")) expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = 1)) expect_error(Analyze_Wilcoxon(ae_prep %>% mutate(SiteID = ifelse(SiteID == first(SiteID), NA, SiteID)))) -======= expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = "coffee")) expect_error(Analyze_Wilcoxon(ae_prep, strOutcome = c("Rate", "something else"))) ->>>>>>> dev }) test_that("error given if required column not found",{ From 80dafe458e3de7ba7a5887edc052f407de56d5e6 Mon Sep 17 00:00:00 2001 From: Nathan Kosiba Date: Mon, 7 Mar 2022 18:37:56 +0000 Subject: [PATCH 35/60] migrate AE_Assess qualification to new structure, add double programming to data pipeline tests --- inst/qualification/specs.yaml | 45 + tests/testthat/helper-qualification.R | 58 + tests/testthat/test-test_qual_T1_1.R | 34 + tests/testthat/test-test_qual_T1_2.R | 35 + tests/testthat/test-test_qual_T1_3.R | 41 + tests/testthat/test-test_qual_T1_4.R | 42 + tests/testthat/test-test_qual_T1_5.R | 52 + tests/testthat/test-test_qual_T1_6.R | 59 + tests/testthat/test-test_qual_T1_7.R | 20 + vignettes/qualification.Rmd | 163 --- vignettes/qualification.log | 1173 ----------------- vignettes/validation/.gitignore | 1 - vignettes/validation/change_log.md | 3 - .../Specifications_for_AE_Assess.md | 21 - .../Specifications_for_AE_Map_Raw.md | 16 - .../test_cases/Test_Cases_for_AE_Assess.md | 24 - .../test_cases/Test_Cases_for_AE_Map_Raw.md | 19 - .../test_code/Tests_for_AE_Assess.R | 318 ----- .../test_code/Tests_for_AE_Map_Raw.R | 232 ---- vignettes/validation/validation.yml | 21 - 20 files changed, 386 insertions(+), 1991 deletions(-) create mode 100644 inst/qualification/specs.yaml create mode 100644 tests/testthat/helper-qualification.R create mode 100644 tests/testthat/test-test_qual_T1_1.R create mode 100644 tests/testthat/test-test_qual_T1_2.R create mode 100644 tests/testthat/test-test_qual_T1_3.R create mode 100644 tests/testthat/test-test_qual_T1_4.R create mode 100644 tests/testthat/test-test_qual_T1_5.R create mode 100644 tests/testthat/test-test_qual_T1_6.R create mode 100644 tests/testthat/test-test_qual_T1_7.R delete mode 100644 vignettes/qualification.Rmd delete mode 100644 vignettes/qualification.log delete mode 100644 vignettes/validation/.gitignore delete mode 100644 vignettes/validation/change_log.md delete mode 100644 vignettes/validation/requirements/Specifications_for_AE_Assess.md delete mode 100644 vignettes/validation/requirements/Specifications_for_AE_Map_Raw.md delete mode 100644 vignettes/validation/test_cases/Test_Cases_for_AE_Assess.md delete mode 100644 vignettes/validation/test_cases/Test_Cases_for_AE_Map_Raw.md delete mode 100644 vignettes/validation/test_code/Tests_for_AE_Assess.R delete mode 100644 vignettes/validation/test_code/Tests_for_AE_Map_Raw.R delete mode 100644 vignettes/validation/validation.yml diff --git a/inst/qualification/specs.yaml b/inst/qualification/specs.yaml new file mode 100644 index 000000000..121e388c5 --- /dev/null +++ b/inst/qualification/specs.yaml @@ -0,0 +1,45 @@ +S1_1: + Description: Given correct input data an Adverse Event assessment can be done using the poisson method + Risk: High + Impact: High + Tests: + - T1_1 + - T1_2 +S1_2: + Description: Given correct input data an Adverse Event assessment can be done using the wilcoxon method + Risk: High + Impact: High + Tests: + - T1_3 + - T1_4 +S1_3: + Description: Assessments are correctly grouped by the site variable + Risk: Low + Impact: High + Tests: + - T1_1 + - T1_2 + - T1_3 + - T1_4 +S1_4: + Description: Given correct input data an flags will correctly be applied to records thatmeet flagging criteria + Risk: Medium + Impact: High + Tests: + - T1_1 + - T1_2 + - T1_3 + - T1_4 +S1_5: + Description: Assessment can return all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) + Risk: Low + Impact: Medium + Tests: + - T1_5 + - T1_6 +S1_6: + Description: Ensure that missing and invalid data are handled correctly + Risk: Low + Impact: Medium + Tests: + - T1_7 diff --git a/tests/testthat/helper-qualification.R b/tests/testthat/helper-qualification.R new file mode 100644 index 000000000..7ac1101c3 --- /dev/null +++ b/tests/testthat/helper-qualification.R @@ -0,0 +1,58 @@ +qualification_transform_counts <- function(dfTransformed){ + dfTransformed <- dfTransformed %>% + filter(!is.na(.data$Exposure)) %>% + group_by(.data$SiteID) %>% + summarise( + N = n(), + TotalCount= sum(.data$Count), + TotalExposure=sum(.data$Exposure) + )%>% + mutate(Rate = .data$TotalCount / .data$TotalExposure) %>% + select(SiteID, N, TotalCount, TotalExposure, Rate) + + return(dfTransformed) +} + +qualification_analyze_poisson <- function(dfTransformed){ + + dfTransformed$LogExposure <- log(dfTransformed$TotalExposure) + + model <- glm(TotalCount ~ stats::offset(LogExposure), family=poisson(link="log"), + data=dfTransformed) + + outputDF <- dfTransformed %>% + mutate( + Residuals = unname(residuals(model)), + PredictedCount = exp(LogExposure*model$coefficients[2]+model$coefficients[1]) + ) %>% + arrange(Residuals) %>% + select(SiteID, N, TotalExposure, TotalCount, Rate, Residuals, PredictedCount) + + return(outputDF) +} + +qualification_analyze_wilcoxon <- function(dfTransformed){ + sites <- unique(dfTransformed$SiteID) + statistics <- rep(NA, length(sites)) + pvals <- rep(NA, length(sites)) + estimates <- rep(NA, length(sites)) + dfSummary <- data.frame(matrix(NA, nrow = length(sites), ncol = 8)) + colnames(dfSummary) <- c( "N" , "Mean" , "SD", "Median", "Q1", "Q3", "Min", "Max" ) + + for( i in 1:length(sites) ){ + testres <- wilcox.test( dfTransformed$Rate ~ dfTransformed$SiteID == sites[i], exact = FALSE, conf.int = TRUE) + + pvals[i] <- testres$p.value + estimates[i] <- testres$estimate*-1 + } + + outputDF <- data.frame( + dfTransformed, + PValue = pvals, + Estimate = estimates + ) %>% + arrange(PValue) %>% + select(SiteID, N, TotalCount, TotalExposure, Rate, Estimate, PValue) + + return(outputDF) +} diff --git a/tests/testthat/test-test_qual_T1_1.R b/tests/testthat/test-test_qual_T1_1.R new file mode 100644 index 000000000..f283fb8e7 --- /dev/null +++ b/tests/testthat/test-test_qual_T1_1.R @@ -0,0 +1,34 @@ +test_that("AE assessment can return a correctly assessed data frame for the poisson test grouped by the study variable when given correct input data from safetyData and the results should be flagged correctly.", { + # gsm analysis + dfInput <- gsm::AE_Map_Adam( + dfADSL = safetyData::adam_adsl, + dfADAE = safetyData::adam_adae + ) + + test_1 <- AE_Assess( + dfInput = dfInput, + strMethod = "poisson" + ) + + # Double Programming + t1 <- dfInput %>% + qualification_transform_counts() %>% + qualification_analyze_poisson() %>% + mutate( + Score = Residuals, + Flag = case_when( + Score < -5 ~ -1, + Score > 5 ~ 1, + is.na(Score) ~ NA_real_, + is.nan(Score) ~ NA_real_, + TRUE ~ 0), + Assessment = "Safety", + Label = "") %>% + select("Assessment", "Label", "SiteID", "N", "Score", "Flag" ) + + # set classes lost in analyze + class(t1) <- c("tbl_df", "tbl", "data.frame") + + # compare results + expect_equal(test_1, t1) +}) diff --git a/tests/testthat/test-test_qual_T1_2.R b/tests/testthat/test-test_qual_T1_2.R new file mode 100644 index 000000000..0fa2914af --- /dev/null +++ b/tests/testthat/test-test_qual_T1_2.R @@ -0,0 +1,35 @@ +test_that("AE assessment can return a correctly assessed data frame for the poisson test grouped by the study variable when given correct input data from clindata and the results should be flagged correctly using a custom threshold", { + # gsm analysis + dfInput <- gsm::AE_Map_Raw( + dfAE = clindata::raw_ae, + dfRDSL = clindata::rawplus_rdsl + ) + + test_2 <- suppressWarnings(AE_Assess( + dfInput = dfInput, + strMethod = "poisson", + vThreshold = c(-3,3) + )) + + # Double Programming + t2 <- dfInput %>% + qualification_transform_counts() %>% + qualification_analyze_poisson() %>% + mutate( + Score = Residuals, + Flag = case_when( + Score < -3 ~ -1, + Score > 3 ~ 1, + is.na(Score) ~ NA_real_, + is.nan(Score) ~ NA_real_, + TRUE ~ 0), + Assessment = "Safety", + Label = "") %>% + select("Assessment", "Label", "SiteID", "N", "Score", "Flag" ) + + # set classes lost in analyze + class(t2) <- c("tbl_df", "tbl", "data.frame") + + # compare results + expect_equal(test_2, t2) +}) diff --git a/tests/testthat/test-test_qual_T1_3.R b/tests/testthat/test-test_qual_T1_3.R new file mode 100644 index 000000000..5b04d21a5 --- /dev/null +++ b/tests/testthat/test-test_qual_T1_3.R @@ -0,0 +1,41 @@ +test_that("AE assessment can return a correctly assessed data frame for the wilcoxon test grouped by the study variable when given correct input data from safetyData and the results should be flagged correctly.", { + # gsm analysis + dfInput <- gsm::AE_Map_Adam( + dfADSL = safetyData::adam_adsl, + dfADAE = safetyData::adam_adae + ) + + test_3 <- AE_Assess( + dfInput = dfInput, + strMethod = "wilcoxon" + ) + + # Double Programming + t3 <- dfInput %>% + qualification_transform_counts() %>% + qualification_analyze_wilcoxon() %>% + mutate( + Score = PValue, + Flag = case_when( + Score < 0.0001 ~ -1, + is.na(Score) ~ NA_real_, + is.nan(Score) ~ NA_real_, + TRUE ~ 0), + Assessment = "Safety", + Label = "") %>% + mutate( + median = median(Estimate), + Flag = case_when( + Flag != 0 & Estimate < median ~ -1, + Flag != 0 & Estimate >= median ~ 1, + TRUE ~ Flag + )) %>% + select("Assessment", "Label", "SiteID", "N", "Score", "Flag" ) + + # set classes lost in analyze + class(t3) <- c("tbl_df", "tbl", "data.frame") + + # compare results + expect_equal(test_3, t3) + +}) diff --git a/tests/testthat/test-test_qual_T1_4.R b/tests/testthat/test-test_qual_T1_4.R new file mode 100644 index 000000000..a54574894 --- /dev/null +++ b/tests/testthat/test-test_qual_T1_4.R @@ -0,0 +1,42 @@ +test_that("AE assessment can return a correctly assessed data frame for the wilcoxon test grouped by the study variable when given correct input data from clindata and the results should be flagged correctly using a custom threshold.", { + # gsm analysis + dfInput <- gsm::AE_Map_Raw( + dfAE = clindata::raw_ae, + dfRDSL = clindata::rawplus_rdsl + ) + + test_4 <- suppressWarnings(AE_Assess( + dfInput = dfInput, + strMethod = "wilcoxon", + vThreshold = c(.1, NA) + )) + + # Double Programming + t4 <- dfInput %>% + qualification_transform_counts() %>% + qualification_analyze_wilcoxon() %>% + mutate( + Score = PValue, + Flag = case_when( + Score < 0.1 ~ -1, + is.na(Score) ~ NA_real_, + is.nan(Score) ~ NA_real_, + TRUE ~ 0 + ), + Assessment = "Safety", + Label = "") %>% + mutate( + median = median(Estimate), + Flag = case_when( + Flag != 0 & Estimate < median ~ -1, + Flag != 0 & Estimate >= median ~ 1, + TRUE ~ Flag + )) %>% + select("Assessment", "Label", "SiteID", "N", "Score", "Flag" ) + + # set classes lost in analyze + class(t4) <- c("tbl_df", "tbl", "data.frame") + + # compare results + expect_equal(test_4, t4) +}) diff --git a/tests/testthat/test-test_qual_T1_5.R b/tests/testthat/test-test_qual_T1_5.R new file mode 100644 index 000000000..cf01a9b7f --- /dev/null +++ b/tests/testthat/test-test_qual_T1_5.R @@ -0,0 +1,52 @@ +test_that("Test that Assessment can return all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) for a poisson test", { + dfInput <- gsm::AE_Map_Raw( + dfAE = clindata::raw_ae, + dfRDSL = clindata::rawplus_rdsl + ) + + # gsm data + test_5 <- suppressWarnings(AE_Assess( + dfInput = dfInput, + bDataList = TRUE + )) + + # double programming + t5_input <- dfInput + + t5_transformed <- dfInput %>% + qualification_transform_counts() + + t5_analyzed <- t5_transformed %>% + qualification_analyze_poisson() + + class(t5_analyzed) <- c("tbl_df", "tbl", "data.frame") + + t5_flagged <- t5_analyzed %>% + mutate( + ThresholdLow = -5, + ThresholdHigh = 5, + ThresholdCol = "Residuals", + Flag = case_when( + Residuals < -5 ~ -1, + Residuals > 5 ~ 1, + is.na(Residuals) ~ NA_real_, + is.nan(Residuals) ~ NA_real_, + TRUE ~ 0), + ) + + t5_summary <- t5_flagged %>% + mutate( + Assessment = "Safety", + Label = "", + Score = Residuals + ) %>% + select(Assessment, Label, SiteID, N, Score, Flag) + + t5 <- list("dfInput" = t5_input, + "dfTransformed" = t5_transformed, + "dfAnalyzed" = t5_analyzed, + "dfFlagged" = t5_flagged, + "dfSummary" = t5_summary) + + expect_equal(test_5, t5) +}) diff --git a/tests/testthat/test-test_qual_T1_6.R b/tests/testthat/test-test_qual_T1_6.R new file mode 100644 index 000000000..08db5a97f --- /dev/null +++ b/tests/testthat/test-test_qual_T1_6.R @@ -0,0 +1,59 @@ +test_that("Test that Assessment can return all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) for a wilcoxon test", { + dfInput <- gsm::AE_Map_Raw( + dfAE = clindata::raw_ae, + dfRDSL = clindata::rawplus_rdsl + ) + + # gsm data + test_6 <- suppressWarnings(AE_Assess( + dfInput = dfInput, + strMethod = "wilcoxon", + bDataList = TRUE + )) + + # double programming + t6_input <- dfInput + + t6_transformed <- dfInput %>% + qualification_transform_counts() + + t6_analyzed <- t6_transformed %>% + qualification_analyze_wilcoxon() + + class(t6_analyzed) <- c("tbl_df", "tbl", "data.frame") + names(t6_analyzed$Estimate) <- rep("difference in location", nrow(t6_analyzed)) + + t6_flagged <- t6_analyzed %>% + mutate( + ThresholdLow = .0001, + ThresholdHigh = NA_integer_, + ThresholdCol = "PValue", + Flag = case_when( + PValue < 0.0001 ~ -1, + is.na(PValue) ~ NA_real_, + is.nan(PValue) ~ NA_real_, + TRUE ~ 0), + median = median(Estimate), + Flag = case_when( + Flag != 0 & Estimate < median ~ -1, + Flag != 0 & Estimate >= median ~ 1, + TRUE ~ Flag) + ) %>% + select(-median) + + t6_summary <- t6_flagged %>% + mutate( + Assessment = "Safety", + Label = "", + Score = PValue + ) %>% + select(Assessment, Label, SiteID, N, Score, Flag) + + t6 <- list("dfInput" = t6_input, + "dfTransformed" = t6_transformed, + "dfAnalyzed" = t6_analyzed, + "dfFlagged" = t6_flagged, + "dfSummary" = t6_summary) + + expect_equal(test_6, t6) +}) diff --git a/tests/testthat/test-test_qual_T1_7.R b/tests/testthat/test-test_qual_T1_7.R new file mode 100644 index 000000000..cfe8ff9a6 --- /dev/null +++ b/tests/testthat/test-test_qual_T1_7.R @@ -0,0 +1,20 @@ +test_that("Test that (NA, NaN) in input exposure data throws a warning and drops the participant(s) from the analysis.", { + dfInput <- gsm::AE_Map_Raw( + dfAE = clindata::raw_ae, + dfRDSL = clindata::rawplus_rdsl + ) + + # data + # several NA values + dfInputWithNA1 <- dfInput %>% + mutate(Exposure = ifelse(substr(SubjectID,4,4) == 1, Exposure, NA_integer_), + Rate = ifelse(is.na(Exposure), Exposure, NA_integer_)) + + # one NA value + dfInputWithNA2 <- dfInput %>% + mutate(Exposure = ifelse(SubjectID == "1396", NA_integer_, Exposure), + Rate = ifelse(is.na(Exposure), Exposure, NA_integer_)) + + expect_warning(AE_Assess(dfInputWithNA1)) + expect_warning(AE_Assess(dfInputWithNA2)) +}) diff --git a/vignettes/qualification.Rmd b/vignettes/qualification.Rmd deleted file mode 100644 index f768e6666..000000000 --- a/vignettes/qualification.Rmd +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Validation Report for gsm -author: Gilead BioStats -date: "`r Sys.Date()`" -output: - pdf_document: - toc: true - fig_crop: false - toc_depth: 2 - number_sections: true -vignette: > - %\VignetteIndexEntry{Validation Report} - \usepackage[utf8]{inputenc} - %\VignetteEngine{knitr::rmarkdown_notangle} -header-includes: - - \usepackage{array} - - \usepackage{float} - - \usepackage{multirow} - - \usepackage{longtable} - - \usepackage{booktabs} - - \usepackage{titling} - - \pretitle{\begin{center} - \includegraphics[width=2in,height=2in]{hex-gsm.png}\LARGE\\} - - \posttitle{\end{center}} ---- - - -```{r, setup, echo=FALSE,warning=FALSE} -suppressPackageStartupMessages({ - library(valtools) - library(knitr) - library(kableExtra) - library(magrittr) - library(devtools) - library(gsm) -}) - -opts_chunk$set( - collapse = TRUE, - comment = "#>", - eval = TRUE, - echo = FALSE, - results = "asis", - message = FALSE, - tidy = FALSE -) - -options( - knitr.kable.NA = '', - knitr.duplicate.label = "allow" -) - -``` - -```{r shared-obj} -all_sig <- vt_scrape_sig_table() -``` - -\newpage - -# Certifications - -## Signatures - -**AUTHOR** My signature designates authorship of this document. - -```{r validation-lead-sig-block} -all_sig[grepl("qualification lead",all_sig$role, ignore.case = TRUE),] %>% - set_rownames(seq_len(nrow(.))) %>% - vt_kable_sig_table() -``` - -**APPROVAL** I have reviewed this document and approve its content. - -```{r sig-block} - -all_sig[!grepl("validation lead",all_sig$role, ignore.case = TRUE),] %>% - set_rownames(seq_len(nrow(.))) %>% - vt_kable_sig_table() - -``` - -The effective date of this document is the last date of signature. - -\newpage - -# Release details - -## Package Information - -### Change Log - -```{r change-log-table} -vt_scrape_change_log() %>% - vt_kable_change_log() -``` - -### Validation Environment - -```{r env-table} -vt_scrape_val_env() %>% - vt_kable_val_env() -``` - - -## Authors - -### Requirements - - -```{r req-authors} -vt_scrape_requirement_editors() %>% - vt_kable_requirement_editors() -``` - -### Functions - -```{r func-authors} -# vt_scrape_function_editors(tags = c("editor", "editDate")) %>% -# vt_kable_function_editors() - -``` - -### Test Case Authors - -```{r test-case-authors} -vt_scrape_test_case_editors() %>% - vt_kable_test_case_editors() -``` - -### Test Code Authors - -```{r test-code-authors} -vt_scrape_test_code_editors() %>% - vt_kable_test_code_editors() -``` - -## Traceability - -```{r traceability} -vt_scrape_coverage_matrix() %>% - vt_kable_coverage_matrix() -``` - -\clearpage - -# Risk Assessment - -```{r risk} -vt_scrape_risk_assessment() %>% - vt_kable_risk_assessment() -``` - -\newpage - -# Validation - - - -```{r child-files-evaluation} -child_files <- vt_get_child_files() -vt_file(vt_path(child_files),dynamic_referencing = FALSE) -``` diff --git a/vignettes/qualification.log b/vignettes/qualification.log deleted file mode 100644 index df6c35eef..000000000 --- a/vignettes/qualification.log +++ /dev/null @@ -1,1173 +0,0 @@ -This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex 2020.2.7) 18 FEB 2022 21:15 -entering extended mode - restricted \write18 enabled. - %&-line parsing enabled. -**/tmp/RtmpAsfFRb/preview-7222c41ca52.dir/qualification.tex -(/tmp/RtmpAsfFRb/preview-7222c41ca52.dir/qualification.tex -LaTeX2e <2017-04-15> -Babel <3.18> and hyphenation patterns for 3 language(s) loaded. -(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls -Document Class: article 2014/09/29 v1.4h Standard LaTeX document class -(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo -File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option) -) -\c@part=\count79 -\c@section=\count80 -\c@subsection=\count81 -\c@subsubsection=\count82 -\c@paragraph=\count83 -\c@subparagraph=\count84 -\c@figure=\count85 -\c@table=\count86 -\abovecaptionskip=\skip41 -\belowcaptionskip=\skip42 -\bibindent=\dimen102 -) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty -Package: amsmath 2017/09/02 v2.17a AMS math features -\@mathmargin=\skip43 -For additional information on amsmath, use the `?' option. -(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty -Package: amstext 2000/06/29 v2.01 AMS text -(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty -File: amsgen.sty 1999/11/30 v2.0 generic functions -\@emptytoks=\toks14 -\ex@=\dimen103 -)) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty -Package: amsbsy 1999/11/29 v1.2d Bold Symbols -\pmbraise@=\dimen104 -) (/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty -Package: amsopn 2016/03/08 v2.02 operator names -) -\inf@bad=\count87 -LaTeX Info: Redefining \frac on input line 213. -\uproot@=\count88 -\leftroot@=\count89 -LaTeX Info: Redefining \overline on input line 375. -\classnum@=\count90 -\DOTSCASE@=\count91 -LaTeX Info: Redefining \ldots on input line 472. -LaTeX Info: Redefining \dots on input line 475. -LaTeX Info: Redefining \cdots on input line 596. -\Mathstrutbox@=\box26 -\strutbox@=\box27 -\big@size=\dimen105 -LaTeX Font Info: Redeclaring font encoding OML on input line 712. -LaTeX Font Info: Redeclaring font encoding OMS on input line 713. -\macc@depth=\count92 -\c@MaxMatrixCols=\count93 -\dotsspace@=\muskip10 -\c@parentequation=\count94 -\dspbrk@lvl=\count95 -\tag@help=\toks15 -\row@=\count96 -\column@=\count97 -\maxfields@=\count98 -\andhelp@=\toks16 -\eqnshift@=\dimen106 -\alignsep@=\dimen107 -\tagshift@=\dimen108 -\tagwidth@=\dimen109 -\totwidth@=\dimen110 -\lineht@=\dimen111 -\@envbody=\toks17 -\multlinegap=\skip44 -\multlinetaggap=\skip45 -\mathdisplay@stack=\toks18 -LaTeX Info: Redefining \[ on input line 2817. -LaTeX Info: Redefining \] on input line 2818. -) (/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty -Package: amssymb 2013/01/14 v3.01 AMS font symbols -(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty -Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support -\symAMSa=\mathgroup4 -\symAMSb=\mathgroup5 -LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' -(Font) U/euf/m/n --> U/euf/b/n on input line 106. -)) (/usr/share/texmf/tex/latex/lm/lmodern.sty -Package: lmodern 2009/10/30 v1.6 Latin Modern Fonts -LaTeX Font Info: Overwriting symbol font `operators' in version `normal' -(Font) OT1/cmr/m/n --> OT1/lmr/m/n on input line 22. -LaTeX Font Info: Overwriting symbol font `letters' in version `normal' -(Font) OML/cmm/m/it --> OML/lmm/m/it on input line 23. -LaTeX Font Info: Overwriting symbol font `symbols' in version `normal' -(Font) OMS/cmsy/m/n --> OMS/lmsy/m/n on input line 24. -LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal' -(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 25. -LaTeX Font Info: Overwriting symbol font `operators' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 26. -LaTeX Font Info: Overwriting symbol font `letters' in version `bold' -(Font) OML/cmm/b/it --> OML/lmm/b/it on input line 27. -LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' -(Font) OMS/cmsy/b/n --> OMS/lmsy/b/n on input line 28. -LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' -(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 29. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 31. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal' -(Font) OT1/cmss/m/n --> OT1/lmss/m/n on input line 32. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal' -(Font) OT1/cmr/m/it --> OT1/lmr/m/it on input line 33. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal' -(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 34. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 35. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' -(Font) OT1/cmss/bx/n --> OT1/lmss/bx/n on input line 36. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' -(Font) OT1/cmr/bx/it --> OT1/lmr/bx/it on input line 37. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' -(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 38. -) (/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty -Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional -) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifluatex.sty -Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO) -Package ifluatex Info: LuaTeX not detected. -) (/usr/share/texlive/texmf-dist/tex/latex/base/fontenc.sty -Package: fontenc 2017/04/05 v2.0i Standard LaTeX package -(/usr/share/texlive/texmf-dist/tex/latex/base/t1enc.def -File: t1enc.def 2017/04/05 v2.0i Standard LaTeX file -LaTeX Font Info: Redeclaring font encoding T1 on input line 48. -)) (/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty -Package: inputenc 2015/03/17 v1.2c Input encoding file -\inpenc@prehook=\toks19 -\inpenc@posthook=\toks20 -(/usr/share/texlive/texmf-dist/tex/latex/base/utf8.def -File: utf8.def 2017/01/28 v1.1t UTF-8 support for inputenc -Now handling font encoding OML ... -... no UTF-8 mapping file for font encoding OML -Now handling font encoding T1 ... -... processing UTF-8 mapping file for font encoding T1 -(/usr/share/texlive/texmf-dist/tex/latex/base/t1enc.dfu -File: t1enc.dfu 2017/01/28 v1.1t UTF-8 support for inputenc - defining Unicode char U+00A0 (decimal 160) - defining Unicode char U+00A1 (decimal 161) - defining Unicode char U+00A3 (decimal 163) - defining Unicode char U+00AB (decimal 171) - defining Unicode char U+00AD (decimal 173) - defining Unicode char U+00BB (decimal 187) - defining Unicode char U+00BF (decimal 191) - defining Unicode char U+00C0 (decimal 192) - defining Unicode char U+00C1 (decimal 193) - defining Unicode char U+00C2 (decimal 194) - defining Unicode char U+00C3 (decimal 195) - defining Unicode char U+00C4 (decimal 196) - defining Unicode char U+00C5 (decimal 197) - defining Unicode char U+00C6 (decimal 198) - defining Unicode char U+00C7 (decimal 199) - defining Unicode char U+00C8 (decimal 200) - defining Unicode char U+00C9 (decimal 201) - defining Unicode char U+00CA (decimal 202) - defining Unicode char U+00CB (decimal 203) - defining Unicode char U+00CC (decimal 204) - defining Unicode char U+00CD (decimal 205) - defining Unicode char U+00CE (decimal 206) - defining Unicode char U+00CF (decimal 207) - defining Unicode char U+00D0 (decimal 208) - defining Unicode char U+00D1 (decimal 209) - defining Unicode char U+00D2 (decimal 210) - defining Unicode char U+00D3 (decimal 211) - defining Unicode char U+00D4 (decimal 212) - defining Unicode char U+00D5 (decimal 213) - defining Unicode char U+00D6 (decimal 214) - defining Unicode char U+00D8 (decimal 216) - defining Unicode char U+00D9 (decimal 217) - defining Unicode char U+00DA (decimal 218) - defining Unicode char U+00DB (decimal 219) - defining Unicode char U+00DC (decimal 220) - defining Unicode char U+00DD (decimal 221) - defining Unicode char U+00DE (decimal 222) - defining Unicode char U+00DF (decimal 223) - defining Unicode char U+00E0 (decimal 224) - defining Unicode char U+00E1 (decimal 225) - defining Unicode char U+00E2 (decimal 226) - defining Unicode char U+00E3 (decimal 227) - defining Unicode char U+00E4 (decimal 228) - defining Unicode char U+00E5 (decimal 229) - defining Unicode char U+00E6 (decimal 230) - defining Unicode char U+00E7 (decimal 231) - defining Unicode char U+00E8 (decimal 232) - defining Unicode char U+00E9 (decimal 233) - defining Unicode char U+00EA (decimal 234) - defining Unicode char U+00EB (decimal 235) - defining Unicode char U+00EC (decimal 236) - defining Unicode char U+00ED (decimal 237) - defining Unicode char U+00EE (decimal 238) - defining Unicode char U+00EF (decimal 239) - defining Unicode char U+00F0 (decimal 240) - defining Unicode char U+00F1 (decimal 241) - defining Unicode char U+00F2 (decimal 242) - defining Unicode char U+00F3 (decimal 243) - defining Unicode char U+00F4 (decimal 244) - defining Unicode char U+00F5 (decimal 245) - defining Unicode char U+00F6 (decimal 246) - defining Unicode char U+00F8 (decimal 248) - defining Unicode char U+00F9 (decimal 249) - defining Unicode char U+00FA (decimal 250) - defining Unicode char U+00FB (decimal 251) - defining Unicode char U+00FC (decimal 252) - defining Unicode char U+00FD (decimal 253) - defining Unicode char U+00FE (decimal 254) - defining Unicode char U+00FF (decimal 255) - defining Unicode char U+0100 (decimal 256) - defining Unicode char U+0101 (decimal 257) - defining Unicode char U+0102 (decimal 258) - defining Unicode char U+0103 (decimal 259) - defining Unicode char U+0104 (decimal 260) - defining Unicode char U+0105 (decimal 261) - defining Unicode char U+0106 (decimal 262) - defining Unicode char U+0107 (decimal 263) - defining Unicode char U+0108 (decimal 264) - defining Unicode char U+0109 (decimal 265) - defining Unicode char U+010A (decimal 266) - defining Unicode char U+010B (decimal 267) - defining Unicode char U+010C (decimal 268) - defining Unicode char U+010D (decimal 269) - defining Unicode char U+010E (decimal 270) - defining Unicode char U+010F (decimal 271) - defining Unicode char U+0110 (decimal 272) - defining Unicode char U+0111 (decimal 273) - defining Unicode char U+0112 (decimal 274) - defining Unicode char U+0113 (decimal 275) - defining Unicode char U+0114 (decimal 276) - defining Unicode char U+0115 (decimal 277) - defining Unicode char U+0116 (decimal 278) - defining Unicode char U+0117 (decimal 279) - defining Unicode char U+0118 (decimal 280) - defining Unicode char U+0119 (decimal 281) - defining Unicode char U+011A (decimal 282) - defining Unicode char U+011B (decimal 283) - defining Unicode char U+011C (decimal 284) - defining Unicode char U+011D (decimal 285) - defining Unicode char U+011E (decimal 286) - defining Unicode char U+011F (decimal 287) - defining Unicode char U+0120 (decimal 288) - defining Unicode char U+0121 (decimal 289) - defining Unicode char U+0122 (decimal 290) - defining Unicode char U+0123 (decimal 291) - defining Unicode char U+0124 (decimal 292) - defining Unicode char U+0125 (decimal 293) - defining Unicode char U+0128 (decimal 296) - defining Unicode char U+0129 (decimal 297) - defining Unicode char U+012A (decimal 298) - defining Unicode char U+012B (decimal 299) - defining Unicode char U+012C (decimal 300) - defining Unicode char U+012D (decimal 301) - defining Unicode char U+012E (decimal 302) - defining Unicode char U+012F (decimal 303) - defining Unicode char U+0130 (decimal 304) - defining Unicode char U+0131 (decimal 305) - defining Unicode char U+0132 (decimal 306) - defining Unicode char U+0133 (decimal 307) - defining Unicode char U+0134 (decimal 308) - defining Unicode char U+0135 (decimal 309) - defining Unicode char U+0136 (decimal 310) - defining Unicode char U+0137 (decimal 311) - defining Unicode char U+0139 (decimal 313) - defining Unicode char U+013A (decimal 314) - defining Unicode char U+013B (decimal 315) - defining Unicode char U+013C (decimal 316) - defining Unicode char U+013D (decimal 317) - defining Unicode char U+013E (decimal 318) - defining Unicode char U+0141 (decimal 321) - defining Unicode char U+0142 (decimal 322) - defining Unicode char U+0143 (decimal 323) - defining Unicode char U+0144 (decimal 324) - defining Unicode char U+0145 (decimal 325) - defining Unicode char U+0146 (decimal 326) - defining Unicode char U+0147 (decimal 327) - defining Unicode char U+0148 (decimal 328) - defining Unicode char U+014A (decimal 330) - defining Unicode char U+014B (decimal 331) - defining Unicode char U+014C (decimal 332) - defining Unicode char U+014D (decimal 333) - defining Unicode char U+014E (decimal 334) - defining Unicode char U+014F (decimal 335) - defining Unicode char U+0150 (decimal 336) - defining Unicode char U+0151 (decimal 337) - defining Unicode char U+0152 (decimal 338) - defining Unicode char U+0153 (decimal 339) - defining Unicode char U+0154 (decimal 340) - defining Unicode char U+0155 (decimal 341) - defining Unicode char U+0156 (decimal 342) - defining Unicode char U+0157 (decimal 343) - defining Unicode char U+0158 (decimal 344) - defining Unicode char U+0159 (decimal 345) - defining Unicode char U+015A (decimal 346) - defining Unicode char U+015B (decimal 347) - defining Unicode char U+015C (decimal 348) - defining Unicode char U+015D (decimal 349) - defining Unicode char U+015E (decimal 350) - defining Unicode char U+015F (decimal 351) - defining Unicode char U+0160 (decimal 352) - defining Unicode char U+0161 (decimal 353) - defining Unicode char U+0162 (decimal 354) - defining Unicode char U+0163 (decimal 355) - defining Unicode char U+0164 (decimal 356) - defining Unicode char U+0165 (decimal 357) - defining Unicode char U+0168 (decimal 360) - defining Unicode char U+0169 (decimal 361) - defining Unicode char U+016A (decimal 362) - defining Unicode char U+016B (decimal 363) - defining Unicode char U+016C (decimal 364) - defining Unicode char U+016D (decimal 365) - defining Unicode char U+016E (decimal 366) - defining Unicode char U+016F (decimal 367) - defining Unicode char U+0170 (decimal 368) - defining Unicode char U+0171 (decimal 369) - defining Unicode char U+0172 (decimal 370) - defining Unicode char U+0173 (decimal 371) - defining Unicode char U+0174 (decimal 372) - defining Unicode char U+0175 (decimal 373) - defining Unicode char U+0176 (decimal 374) - defining Unicode char U+0177 (decimal 375) - defining Unicode char U+0178 (decimal 376) - defining Unicode char U+0179 (decimal 377) - defining Unicode char U+017A (decimal 378) - defining Unicode char U+017B (decimal 379) - defining Unicode char U+017C (decimal 380) - defining Unicode char U+017D (decimal 381) - defining Unicode char U+017E (decimal 382) - defining Unicode char U+01CD (decimal 461) - defining Unicode char U+01CE (decimal 462) - defining Unicode char U+01CF (decimal 463) - defining Unicode char U+01D0 (decimal 464) - defining Unicode char U+01D1 (decimal 465) - defining Unicode char U+01D2 (decimal 466) - defining Unicode char U+01D3 (decimal 467) - defining Unicode char U+01D4 (decimal 468) - defining Unicode char U+01E2 (decimal 482) - defining Unicode char U+01E3 (decimal 483) - defining Unicode char U+01E6 (decimal 486) - defining Unicode char U+01E7 (decimal 487) - defining Unicode char U+01E8 (decimal 488) - defining Unicode char U+01E9 (decimal 489) - defining Unicode char U+01EA (decimal 490) - defining Unicode char U+01EB (decimal 491) - defining Unicode char U+01F0 (decimal 496) - defining Unicode char U+01F4 (decimal 500) - defining Unicode char U+01F5 (decimal 501) - defining Unicode char U+0218 (decimal 536) - defining Unicode char U+0219 (decimal 537) - defining Unicode char U+021A (decimal 538) - defining Unicode char U+021B (decimal 539) - defining Unicode char U+0232 (decimal 562) - defining Unicode char U+0233 (decimal 563) - defining Unicode char U+1E02 (decimal 7682) - defining Unicode char U+1E03 (decimal 7683) - defining Unicode char U+200C (decimal 8204) - defining Unicode char U+2010 (decimal 8208) - defining Unicode char U+2011 (decimal 8209) - defining Unicode char U+2012 (decimal 8210) - defining Unicode char U+2013 (decimal 8211) - defining Unicode char U+2014 (decimal 8212) - defining Unicode char U+2015 (decimal 8213) - defining Unicode char U+2018 (decimal 8216) - defining Unicode char U+2019 (decimal 8217) - defining Unicode char U+201A (decimal 8218) - defining Unicode char U+201C (decimal 8220) - defining Unicode char U+201D (decimal 8221) - defining Unicode char U+201E (decimal 8222) - defining Unicode char U+2030 (decimal 8240) - defining Unicode char U+2031 (decimal 8241) - defining Unicode char U+2039 (decimal 8249) - defining Unicode char U+203A (decimal 8250) - defining Unicode char U+2423 (decimal 9251) - defining Unicode char U+1E20 (decimal 7712) - defining Unicode char U+1E21 (decimal 7713) -) -Now handling font encoding OT1 ... -... processing UTF-8 mapping file for font encoding OT1 -(/usr/share/texlive/texmf-dist/tex/latex/base/ot1enc.dfu -File: ot1enc.dfu 2017/01/28 v1.1t UTF-8 support for inputenc - defining Unicode char U+00A0 (decimal 160) - defining Unicode char U+00A1 (decimal 161) - defining Unicode char U+00A3 (decimal 163) - defining Unicode char U+00AD (decimal 173) - defining Unicode char U+00B8 (decimal 184) - defining Unicode char U+00BF (decimal 191) - defining Unicode char U+00C5 (decimal 197) - defining Unicode char U+00C6 (decimal 198) - defining Unicode char U+00D8 (decimal 216) - defining Unicode char U+00DF (decimal 223) - defining Unicode char U+00E6 (decimal 230) - defining Unicode char U+00EC (decimal 236) - defining Unicode char U+00ED (decimal 237) - defining Unicode char U+00EE (decimal 238) - defining Unicode char U+00EF (decimal 239) - defining Unicode char U+00F8 (decimal 248) - defining Unicode char U+0131 (decimal 305) - defining Unicode char U+0141 (decimal 321) - defining Unicode char U+0142 (decimal 322) - defining Unicode char U+0152 (decimal 338) - defining Unicode char U+0153 (decimal 339) - defining Unicode char U+0174 (decimal 372) - defining Unicode char U+0175 (decimal 373) - defining Unicode char U+0176 (decimal 374) - defining Unicode char U+0177 (decimal 375) - defining Unicode char U+0218 (decimal 536) - defining Unicode char U+0219 (decimal 537) - defining Unicode char U+021A (decimal 538) - defining Unicode char U+021B (decimal 539) - defining Unicode char U+2013 (decimal 8211) - defining Unicode char U+2014 (decimal 8212) - defining Unicode char U+2018 (decimal 8216) - defining Unicode char U+2019 (decimal 8217) - defining Unicode char U+201C (decimal 8220) - defining Unicode char U+201D (decimal 8221) -) -Now handling font encoding OMS ... -... processing UTF-8 mapping file for font encoding OMS -(/usr/share/texlive/texmf-dist/tex/latex/base/omsenc.dfu -File: omsenc.dfu 2017/01/28 v1.1t UTF-8 support for inputenc - defining Unicode char U+00A7 (decimal 167) - defining Unicode char U+00B6 (decimal 182) - defining Unicode char U+00B7 (decimal 183) - defining Unicode char U+2020 (decimal 8224) - defining Unicode char U+2021 (decimal 8225) - defining Unicode char U+2022 (decimal 8226) -) -Now handling font encoding OMX ... -... no UTF-8 mapping file for font encoding OMX -Now handling font encoding U ... -... no UTF-8 mapping file for font encoding U - defining Unicode char U+00A9 (decimal 169) - defining Unicode char U+00AA (decimal 170) - defining Unicode char U+00AE (decimal 174) - defining Unicode char U+00BA (decimal 186) - defining Unicode char U+02C6 (decimal 710) - defining Unicode char U+02DC (decimal 732) - defining Unicode char U+200C (decimal 8204) - defining Unicode char U+2026 (decimal 8230) - defining Unicode char U+2122 (decimal 8482) - defining Unicode char U+2423 (decimal 9251) -)) (/usr/share/texlive/texmf-dist/tex/latex/base/textcomp.sty -Package: textcomp 2017/04/05 v2.0i Standard LaTeX package -Package textcomp Info: Sub-encoding information: -(textcomp) 5 = only ISO-Adobe without \textcurrency -(textcomp) 4 = 5 + \texteuro -(textcomp) 3 = 4 + \textohm -(textcomp) 2 = 3 + \textestimated + \textcurrency -(textcomp) 1 = TS1 - \textcircled - \t -(textcomp) 0 = TS1 (full) -(textcomp) Font families with sub-encoding setting implement -(textcomp) only a restricted character set as indicated. -(textcomp) Family '?' is the default used for unknown fonts. -(textcomp) See the documentation for details. -Package textcomp Info: Setting ? sub-encoding to TS1/1 on input line 79. -(/usr/share/texlive/texmf-dist/tex/latex/base/ts1enc.def -File: ts1enc.def 2001/06/05 v3.0e (jk/car/fm) Standard LaTeX file -Now handling font encoding TS1 ... -... processing UTF-8 mapping file for font encoding TS1 -(/usr/share/texlive/texmf-dist/tex/latex/base/ts1enc.dfu -File: ts1enc.dfu 2017/01/28 v1.1t UTF-8 support for inputenc - defining Unicode char U+00A2 (decimal 162) - defining Unicode char U+00A3 (decimal 163) - defining Unicode char U+00A4 (decimal 164) - defining Unicode char U+00A5 (decimal 165) - defining Unicode char U+00A6 (decimal 166) - defining Unicode char U+00A7 (decimal 167) - defining Unicode char U+00A8 (decimal 168) - defining Unicode char U+00A9 (decimal 169) - defining Unicode char U+00AA (decimal 170) - defining Unicode char U+00AC (decimal 172) - defining Unicode char U+00AE (decimal 174) - defining Unicode char U+00AF (decimal 175) - defining Unicode char U+00B0 (decimal 176) - defining Unicode char U+00B1 (decimal 177) - defining Unicode char U+00B2 (decimal 178) - defining Unicode char U+00B3 (decimal 179) - defining Unicode char U+00B4 (decimal 180) - defining Unicode char U+00B5 (decimal 181) - defining Unicode char U+00B6 (decimal 182) - defining Unicode char U+00B7 (decimal 183) - defining Unicode char U+00B9 (decimal 185) - defining Unicode char U+00BA (decimal 186) - defining Unicode char U+00BC (decimal 188) - defining Unicode char U+00BD (decimal 189) - defining Unicode char U+00BE (decimal 190) - defining Unicode char U+00D7 (decimal 215) - defining Unicode char U+00F7 (decimal 247) - defining Unicode char U+0192 (decimal 402) - defining Unicode char U+02C7 (decimal 711) - defining Unicode char U+02D8 (decimal 728) - defining Unicode char U+02DD (decimal 733) - defining Unicode char U+0E3F (decimal 3647) - defining Unicode char U+2016 (decimal 8214) - defining Unicode char U+2020 (decimal 8224) - defining Unicode char U+2021 (decimal 8225) - defining Unicode char U+2022 (decimal 8226) - defining Unicode char U+2030 (decimal 8240) - defining Unicode char U+2031 (decimal 8241) - defining Unicode char U+203B (decimal 8251) - defining Unicode char U+203D (decimal 8253) - defining Unicode char U+2044 (decimal 8260) - defining Unicode char U+204E (decimal 8270) - defining Unicode char U+2052 (decimal 8274) - defining Unicode char U+20A1 (decimal 8353) - defining Unicode char U+20A4 (decimal 8356) - defining Unicode char U+20A6 (decimal 8358) - defining Unicode char U+20A9 (decimal 8361) - defining Unicode char U+20AB (decimal 8363) - defining Unicode char U+20AC (decimal 8364) - defining Unicode char U+20B1 (decimal 8369) - defining Unicode char U+2103 (decimal 8451) - defining Unicode char U+2116 (decimal 8470) - defining Unicode char U+2117 (decimal 8471) - defining Unicode char U+211E (decimal 8478) - defining Unicode char U+2120 (decimal 8480) - defining Unicode char U+2122 (decimal 8482) - defining Unicode char U+2126 (decimal 8486) - defining Unicode char U+2127 (decimal 8487) - defining Unicode char U+212E (decimal 8494) - defining Unicode char U+2190 (decimal 8592) - defining Unicode char U+2191 (decimal 8593) - defining Unicode char U+2192 (decimal 8594) - defining Unicode char U+2193 (decimal 8595) - defining Unicode char U+2329 (decimal 9001) - defining Unicode char U+232A (decimal 9002) - defining Unicode char U+2422 (decimal 9250) - defining Unicode char U+25E6 (decimal 9702) - defining Unicode char U+25EF (decimal 9711) - defining Unicode char U+266A (decimal 9834) -)) -LaTeX Info: Redefining \oldstylenums on input line 334. -Package textcomp Info: Setting cmr sub-encoding to TS1/0 on input line 349. -Package textcomp Info: Setting cmss sub-encoding to TS1/0 on input line 350. -Package textcomp Info: Setting cmtt sub-encoding to TS1/0 on input line 351. -Package textcomp Info: Setting cmvtt sub-encoding to TS1/0 on input line 352. -Package textcomp Info: Setting cmbr sub-encoding to TS1/0 on input line 353. -Package textcomp Info: Setting cmtl sub-encoding to TS1/0 on input line 354. -Package textcomp Info: Setting ccr sub-encoding to TS1/0 on input line 355. -Package textcomp Info: Setting ptm sub-encoding to TS1/4 on input line 356. -Package textcomp Info: Setting pcr sub-encoding to TS1/4 on input line 357. -Package textcomp Info: Setting phv sub-encoding to TS1/4 on input line 358. -Package textcomp Info: Setting ppl sub-encoding to TS1/3 on input line 359. -Package textcomp Info: Setting pag sub-encoding to TS1/4 on input line 360. -Package textcomp Info: Setting pbk sub-encoding to TS1/4 on input line 361. -Package textcomp Info: Setting pnc sub-encoding to TS1/4 on input line 362. -Package textcomp Info: Setting pzc sub-encoding to TS1/4 on input line 363. -Package textcomp Info: Setting bch sub-encoding to TS1/4 on input line 364. -Package textcomp Info: Setting put sub-encoding to TS1/5 on input line 365. -Package textcomp Info: Setting uag sub-encoding to TS1/5 on input line 366. -Package textcomp Info: Setting ugq sub-encoding to TS1/5 on input line 367. -Package textcomp Info: Setting ul8 sub-encoding to TS1/4 on input line 368. -Package textcomp Info: Setting ul9 sub-encoding to TS1/4 on input line 369. -Package textcomp Info: Setting augie sub-encoding to TS1/5 on input line 370. -Package textcomp Info: Setting dayrom sub-encoding to TS1/3 on input line 371. -Package textcomp Info: Setting dayroms sub-encoding to TS1/3 on input line 372. - -Package textcomp Info: Setting pxr sub-encoding to TS1/0 on input line 373. -Package textcomp Info: Setting pxss sub-encoding to TS1/0 on input line 374. -Package textcomp Info: Setting pxtt sub-encoding to TS1/0 on input line 375. -Package textcomp Info: Setting txr sub-encoding to TS1/0 on input line 376. -Package textcomp Info: Setting txss sub-encoding to TS1/0 on input line 377. -Package textcomp Info: Setting txtt sub-encoding to TS1/0 on input line 378. -Package textcomp Info: Setting lmr sub-encoding to TS1/0 on input line 379. -Package textcomp Info: Setting lmdh sub-encoding to TS1/0 on input line 380. -Package textcomp Info: Setting lmss sub-encoding to TS1/0 on input line 381. -Package textcomp Info: Setting lmssq sub-encoding to TS1/0 on input line 382. -Package textcomp Info: Setting lmvtt sub-encoding to TS1/0 on input line 383. -Package textcomp Info: Setting lmtt sub-encoding to TS1/0 on input line 384. -Package textcomp Info: Setting qhv sub-encoding to TS1/0 on input line 385. -Package textcomp Info: Setting qag sub-encoding to TS1/0 on input line 386. -Package textcomp Info: Setting qbk sub-encoding to TS1/0 on input line 387. -Package textcomp Info: Setting qcr sub-encoding to TS1/0 on input line 388. -Package textcomp Info: Setting qcs sub-encoding to TS1/0 on input line 389. -Package textcomp Info: Setting qpl sub-encoding to TS1/0 on input line 390. -Package textcomp Info: Setting qtm sub-encoding to TS1/0 on input line 391. -Package textcomp Info: Setting qzc sub-encoding to TS1/0 on input line 392. -Package textcomp Info: Setting qhvc sub-encoding to TS1/0 on input line 393. -Package textcomp Info: Setting futs sub-encoding to TS1/4 on input line 394. -Package textcomp Info: Setting futx sub-encoding to TS1/4 on input line 395. -Package textcomp Info: Setting futj sub-encoding to TS1/4 on input line 396. -Package textcomp Info: Setting hlh sub-encoding to TS1/3 on input line 397. -Package textcomp Info: Setting hls sub-encoding to TS1/3 on input line 398. -Package textcomp Info: Setting hlst sub-encoding to TS1/3 on input line 399. -Package textcomp Info: Setting hlct sub-encoding to TS1/5 on input line 400. -Package textcomp Info: Setting hlx sub-encoding to TS1/5 on input line 401. -Package textcomp Info: Setting hlce sub-encoding to TS1/5 on input line 402. -Package textcomp Info: Setting hlcn sub-encoding to TS1/5 on input line 403. -Package textcomp Info: Setting hlcw sub-encoding to TS1/5 on input line 404. -Package textcomp Info: Setting hlcf sub-encoding to TS1/5 on input line 405. -Package textcomp Info: Setting pplx sub-encoding to TS1/3 on input line 406. -Package textcomp Info: Setting pplj sub-encoding to TS1/3 on input line 407. -Package textcomp Info: Setting ptmx sub-encoding to TS1/4 on input line 408. -Package textcomp Info: Setting ptmj sub-encoding to TS1/4 on input line 409. -) (/usr/share/texlive/texmf-dist/tex/latex/upquote/upquote.sty -Package: upquote 2012/04/19 v1.3 upright-quote and grave-accent glyphs in verba -tim -) (/usr/share/texlive/texmf-dist/tex/latex/microtype/microtype.sty -Package: microtype 2018/01/14 v2.7a Micro-typographical refinements (RS) -(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty -Package: keyval 2014/10/28 v1.15 key=value parser (DPC) -\KV@toks@=\toks21 -) -\MT@toks=\toks22 -\MT@count=\count99 -LaTeX Info: Redefining \textls on input line 793. -\MT@outer@kern=\dimen112 -LaTeX Info: Redefining \textmicrotypecontext on input line 1339. -\MT@listname@count=\count100 -(/usr/share/texlive/texmf-dist/tex/latex/microtype/microtype-pdftex.def -File: microtype-pdftex.def 2018/01/14 v2.7a Definitions specific to pdftex (RS) - -LaTeX Info: Redefining \lsstyle on input line 913. -LaTeX Info: Redefining \lslig on input line 913. -\MT@outer@space=\skip46 -) -Package microtype Info: Loading configuration file microtype.cfg. -(/usr/share/texlive/texmf-dist/tex/latex/microtype/microtype.cfg -File: microtype.cfg 2018/01/14 v2.7a microtype main configuration file (RS) -)) (/usr/share/texlive/texmf-dist/tex/latex/parskip/parskip.sty -Package: parskip 2001/04/09 non-zero parskip adjustments -) (/usr/share/texlive/texmf-dist/tex/latex/xcolor/xcolor.sty -Package: xcolor 2016/05/11 v2.12 LaTeX color extensions (UK) -(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg -File: color.cfg 2016/01/02 v1.6 sample color configuration -) -Package xcolor Info: Driver file: pdftex.def on input line 225. -(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def -File: pdftex.def 2018/01/08 v1.0l Graphics/color driver for pdftex -) -Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1348. -Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1352. -Package xcolor Info: Model `RGB' extended on input line 1364. -Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1366. -Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1367. -Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1368. -Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1369. -Package xcolor Info: Model `Gray' substituted by `gray' on input line 1370. -Package xcolor Info: Model `wave' substituted by `hsb' on input line 1371. -) (/usr/share/texlive/texmf-dist/tex/latex/xurl/xurl.sty -Package: xurl 2018/01/09 v 0.03 modify URL breaks -(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty -\Urlmuskip=\muskip11 -Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc. -)) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/bookmark.sty -Package: bookmark 2016/05/17 v1.26 PDF bookmarks (HO) -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdfescape.sty -Package: pdfescape 2016/05/16 v1.14 Implements pdfTeX's escape features (HO) -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty -Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO) -) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty -Package: pdftexcmds 2018/01/21 v0.26 Utility functions of pdfTeX for LuaTeX (HO -) -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty -Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO) -) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifpdf.sty -Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch -) -Package pdftexcmds Info: LuaTeX not detected. -Package pdftexcmds Info: \pdf@primitive is available. -Package pdftexcmds Info: \pdf@ifprimitive is available. -Package pdftexcmds Info: \pdfdraftmode found. -)) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifvtex.sty -Package: ifvtex 2016/05/16 v1.6 Detect VTeX and its facilities (HO) -Package ifvtex Info: VTeX not detected. -) (/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty -Package: hyperref 2018/02/06 v6.86b Hypertext links for LaTeX -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty -Package: hobsub-hyperref 2016/05/16 v1.14 Bundle oberdiek, subset hyperref (HO) - -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty -Package: hobsub-generic 2016/05/16 v1.14 Bundle oberdiek, subset generic (HO) -Package: hobsub 2016/05/16 v1.14 Construct package bundles (HO) -Package hobsub Info: Skipping package `infwarerr' (already loaded). -Package hobsub Info: Skipping package `ltxcmds' (already loaded). -Package hobsub Info: Skipping package `ifluatex' (already loaded). -Package hobsub Info: Skipping package `ifvtex' (already loaded). -Package: intcalc 2016/05/16 v1.2 Expandable calculations with integers (HO) -Package hobsub Info: Skipping package `ifpdf' (already loaded). -Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO) -Package etexcmds Info: Could not find \expanded. -(etexcmds) That can mean that you are not using pdfTeX 1.50 or -(etexcmds) that some package has redefined \expanded. -(etexcmds) In the latter case, load this package earlier. -Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO) -Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO) -Package hobsub Info: Skipping package `pdftexcmds' (already loaded). -Package hobsub Info: Skipping package `pdfescape' (already loaded). -Package: bigintcalc 2016/05/16 v1.4 Expandable calculations on big integers (HO -) -Package: bitset 2016/05/16 v1.2 Handle bit-vector datatype (HO) -Package: uniquecounter 2016/05/16 v1.3 Provide unlimited unique counter (HO) -) -Package hobsub Info: Skipping package `hobsub' (already loaded). -Package: letltxmacro 2016/05/16 v1.5 Let assignment for LaTeX macros (HO) -Package: hopatch 2016/05/16 v1.3 Wrapper for package hooks (HO) -Package: xcolor-patch 2016/05/16 xcolor patch -Package: atveryend 2016/05/16 v1.9 Hooks at the very end of document (HO) -Package atveryend Info: \enddocument detected (standard20110627). -Package: atbegshi 2016/06/09 v1.18 At begin shipout hook (HO) -Package: refcount 2016/05/16 v3.5 Data extraction from label references (HO) -Package: hycolor 2016/05/16 v1.8 Color options for hyperref/bookmark (HO) -) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/auxhook.sty -Package: auxhook 2016/05/16 v1.4 Hooks for auxiliary files (HO) -) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty -Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO) -) -\@linkdim=\dimen113 -\Hy@linkcounter=\count101 -\Hy@pagecounter=\count102 -(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def -File: pd1enc.def 2018/02/06 v6.86b Hyperref: PDFDocEncoding definition (HO) -Now handling font encoding PD1 ... -... no UTF-8 mapping file for font encoding PD1 -) -\Hy@SavedSpaceFactor=\count103 -(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg -File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive -) -Package hyperref Info: Option `unicode' set `true' on input line 4383. -(/usr/share/texlive/texmf-dist/tex/latex/hyperref/puenc.def -File: puenc.def 2018/02/06 v6.86b Hyperref: PDF Unicode definition (HO) -Now handling font encoding PU ... -... no UTF-8 mapping file for font encoding PU -) -Package hyperref Info: Hyper figures OFF on input line 4509. -Package hyperref Info: Link nesting OFF on input line 4514. -Package hyperref Info: Hyper index ON on input line 4517. -Package hyperref Info: Plain pages OFF on input line 4524. -Package hyperref Info: Backreferencing OFF on input line 4529. -Package hyperref Info: Implicit mode ON; LaTeX internals redefined. -Package hyperref Info: Bookmarks ON on input line 4762. -\c@Hy@tempcnt=\count104 -LaTeX Info: Redefining \url on input line 5115. -\XeTeXLinkMargin=\dimen114 -\Fld@menulength=\count105 -\Field@Width=\dimen115 -\Fld@charsize=\dimen116 -Package hyperref Info: Hyper figures OFF on input line 6369. -Package hyperref Info: Link nesting OFF on input line 6374. -Package hyperref Info: Hyper index ON on input line 6377. -Package hyperref Info: backreferencing OFF on input line 6384. -Package hyperref Info: Link coloring OFF on input line 6389. -Package hyperref Info: Link coloring with OCG OFF on input line 6394. -Package hyperref Info: PDF/A mode OFF on input line 6399. -LaTeX Info: Redefining \ref on input line 6439. -LaTeX Info: Redefining \pageref on input line 6443. -\Hy@abspage=\count106 -\c@Item=\count107 -\c@Hfootnote=\count108 -) -Package hyperref Info: Driver (autodetected): hpdftex. -(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def -File: hpdftex.def 2018/02/06 v6.86b Hyperref driver for pdfTeX -\Fld@listcount=\count109 -\c@bookmark@seq@number=\count110 -(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty -Package: rerunfilecheck 2016/05/16 v1.8 Rerun checks for auxiliary files (HO) -Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 -82. -) -\Hy@SectionHShift=\skip47 -) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/bkm-pdftex.def -File: bkm-pdftex.def 2016/05/17 v1.26 bookmark driver for pdfTeX (HO) -\BKM@id=\count111 -)) (/usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty -Package: geometry 2010/09/12 v5.6 Page Geometry -\Gm@cnth=\count112 -\Gm@cntv=\count113 -\c@Gm@tempcnt=\count114 -\Gm@bindingoffset=\dimen117 -\Gm@wd@mp=\dimen118 -\Gm@odd@mp=\dimen119 -\Gm@even@mp=\dimen120 -\Gm@layoutwidth=\dimen121 -\Gm@layoutheight=\dimen122 -\Gm@layouthoffset=\dimen123 -\Gm@layoutvoffset=\dimen124 -\Gm@dimlist=\toks23 -) (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty -Package: graphicx 2017/06/01 v1.1a Enhanced LaTeX Graphics (DPC,SPQR) -(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty -Package: graphics 2017/06/25 v1.2c Standard LaTeX Graphics (DPC,SPQR) -(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty -Package: trig 2016/01/03 v1.10 sin cos tan (DPC) -) (/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg -File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration -) -Package graphics Info: Driver file: pdftex.def on input line 99. -) -\Gin@req@height=\dimen125 -\Gin@req@width=\dimen126 -) (/usr/share/texlive/texmf-dist/tex/latex/tools/array.sty -Package: array 2016/10/06 v2.4d Tabular extension package (FMi) -\col@sep=\dimen127 -\extrarowheight=\dimen128 -\NC@list=\toks24 -\extratabsurround=\skip48 -\backup@length=\skip49 -) (/usr/share/texlive/texmf-dist/tex/latex/float/float.sty -Package: float 2001/11/08 v1.3d Float enhancements (AL) -\c@float@type=\count115 -\float@exts=\toks25 -\float@box=\box28 -\@float@everytoks=\toks26 -\@floatcapt=\box29 -) (/usr/share/texlive/texmf-dist/tex/latex/multirow/multirow.sty -Package: multirow 2016/11/25 v2.2 Span multiple rows of a table -\multirow@colwidth=\skip50 -\multirow@cntb=\count116 -\multirow@dima=\skip51 -\bigstrutjot=\dimen129 -) (/usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty -Package: longtable 2014/10/28 v4.11 Multi-page Table package (DPC) -\LTleft=\skip52 -\LTright=\skip53 -\LTpre=\skip54 -\LTpost=\skip55 -\LTchunksize=\count117 -\LTcapwidth=\dimen130 -\LT@head=\box30 -\LT@firsthead=\box31 -\LT@foot=\box32 -\LT@lastfoot=\box33 -\LT@cols=\count118 -\LT@rows=\count119 -\c@LT@tables=\count120 -\c@LT@chunks=\count121 -\LT@p@ftn=\toks27 -) (/usr/share/texlive/texmf-dist/tex/latex/booktabs/booktabs.sty -Package: booktabs 2016/04/27 v1.618033 publication quality tables -\heavyrulewidth=\dimen131 -\lightrulewidth=\dimen132 -\cmidrulewidth=\dimen133 -\belowrulesep=\dimen134 -\belowbottomsep=\dimen135 -\aboverulesep=\dimen136 -\abovetopsep=\dimen137 -\cmidrulesep=\dimen138 -\cmidrulekern=\dimen139 -\defaultaddspace=\dimen140 -\@cmidla=\count122 -\@cmidlb=\count123 -\@aboverulesep=\dimen141 -\@belowrulesep=\dimen142 -\@thisruleclass=\count124 -\@lastruleclass=\count125 -\@thisrulewidth=\dimen143 -) (/usr/share/texlive/texmf-dist/tex/latex/titling/titling.sty -Package: titling 2009/09/04 v2.1d maketitle typesetting -\thanksmarkwidth=\skip56 -\thanksmargin=\skip57 -\droptitle=\skip58 -) (/usr/share/texlive/texmf-dist/tex/latex/wrapfig/wrapfig.sty -\wrapoverhang=\dimen144 -\WF@size=\dimen145 -\c@WF@wrappedlines=\count126 -\WF@box=\box34 -\WF@everypar=\toks28 -Package: wrapfig 2003/01/31 v 3.6 -) (/usr/share/texlive/texmf-dist/tex/latex/colortbl/colortbl.sty -Package: colortbl 2012/02/13 v1.0a Color table columns (DPC) -\everycr=\toks29 -\minrowclearance=\skip59 -) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/pdflscape.sty -Package: pdflscape 2016/05/14 v0.11 Display of landscape pages in PDF (HO) -(/usr/share/texlive/texmf-dist/tex/latex/graphics/lscape.sty -Package: lscape 2000/10/22 v3.01 Landscape Pages (DPC) -) -Package pdflscape Info: Auto-detected driver: pdftex on input line 81. -) (/usr/share/texlive/texmf-dist/tex/latex/tabu/tabu.sty -Package: tabu 2011/02/26 v2.8 - flexible LaTeX tabulars (FC) -(/usr/share/texlive/texmf-dist/tex/latex/varwidth/varwidth.sty -Package: varwidth 2009/03/30 ver 0.92; Variable-width minipages -\@vwid@box=\box35 -\sift@deathcycles=\count127 -\@vwid@loff=\dimen146 -\@vwid@roff=\dimen147 -) -\c@taburow=\count128 -\tabu@nbcols=\count129 -\tabu@cnt=\count130 -\tabu@Xcol=\count131 -\tabu@alloc=\count132 -\tabu@nested=\count133 -\tabu@target=\dimen148 -\tabu@spreadtarget=\dimen149 -\tabu@naturalX=\dimen150 -\tabucolX=\dimen151 -\tabu@Xsum=\dimen152 -\extrarowdepth=\dimen153 -\abovetabulinesep=\dimen154 -\belowtabulinesep=\dimen155 -\tabustrutrule=\dimen156 -\tabu@thebody=\toks30 -\tabu@footnotes=\toks31 -\tabu@box=\box36 -\tabu@arstrutbox=\box37 -\tabu@hleads=\box38 -\tabu@vleads=\box39 -\tabu@cellskip=\skip60 -) (/usr/share/texlive/texmf-dist/tex/latex/threeparttable/threeparttable.sty -Package: threeparttable 2003/06/13 v 3.0 -\@tempboxb=\box40 -) (/usr/share/texlive/texmf-dist/tex/latex/threeparttablex/threeparttablex.sty -Package: threeparttablex 2013/07/23 v0.3 by daleif -(/usr/share/texlive/texmf-dist/tex/latex/environ/environ.sty -Package: environ 2014/05/04 v0.3 A new way to define environments -(/usr/share/texlive/texmf-dist/tex/latex/trimspaces/trimspaces.sty -Package: trimspaces 2009/09/17 v1.1 Trim spaces around a token list -)) -\TPTL@width=\skip61 -) (/usr/share/texlive/texmf-dist/tex/generic/ulem/ulem.sty -\UL@box=\box41 -\UL@hyphenbox=\box42 -\UL@skip=\skip62 -\UL@hook=\toks32 -\UL@height=\dimen157 -\UL@pe=\count134 -\UL@pixel=\dimen158 -\ULC@box=\box43 -Package: ulem 2012/05/18 -\ULdepth=\dimen159 -) (/usr/share/texlive/texmf-dist/tex/latex/makecell/makecell.sty -Package: makecell 2009/08/03 V0.1e Managing of Tab Column Heads and Cells -\rotheadsize=\dimen160 -\c@nlinenum=\count135 -\TeXr@lab=\toks33 -) (./qualification.aux) -\openout1 = `qualification.aux'. - -LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 92. -LaTeX Font Info: Try loading font information for TS1+cmr on input line 92. -(/usr/share/texlive/texmf-dist/tex/latex/base/ts1cmr.fd -File: ts1cmr.fd 2014/09/29 v2.5h Standard LaTeX font definitions -) -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Checking defaults for PU/pdf/m/n on input line 92. -LaTeX Font Info: ... okay on input line 92. -LaTeX Font Info: Try loading font information for T1+lmr on input line 92. -(/usr/share/texmf/tex/latex/lm/t1lmr.fd -File: t1lmr.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Info: Redefining \microtypecontext on input line 92. -Package microtype Info: Generating PDF output. -Package microtype Info: Character protrusion enabled (level 2). -Package microtype Info: Using protrusion set `basicmath'. -Package microtype Info: Automatic font expansion enabled (level 2), -(microtype) stretch: 20, shrink: 20, step: 1, non-selected. -Package microtype Info: Using default expansion set `basictext'. -Package microtype Info: No adjustment of tracking. -Package microtype Info: No adjustment of interword spacing. -Package microtype Info: No adjustment of character kerning. -(/usr/share/texlive/texmf-dist/tex/latex/microtype/mt-cmr.cfg -File: mt-cmr.cfg 2013/05/19 v2.2 microtype config. file: Computer Modern Roman -(RS) -) (/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii -[Loading MPS to PDF converter (version 2006.09.02).] -\scratchcounter=\count136 -\scratchdimen=\dimen161 -\scratchbox=\box44 -\nofMPsegments=\count137 -\nofMParguments=\count138 -\everyMPshowfont=\toks34 -\MPscratchCnt=\count139 -\MPscratchDim=\dimen162 -\MPnumerator=\count140 -\makeMPintoPDFobject=\count141 -\everyMPtoPDFconversion=\toks35 -) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty -Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf -(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty -Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO) -) -Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 -38. -Package grfext Info: Graphics extension search list: -(grfext) [.pdf,.png,.jpg,.mps,.jpeg,.jbig2,.jb2,.PDF,.PNG,.JPG,.JPE -G,.JBIG2,.JB2,.eps] -(grfext) \AppendGraphicsExtensions on input line 456. -(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg -File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv -e -)) -\AtBeginShipoutBox=\box45 -Package hyperref Info: Link coloring OFF on input line 92. -(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty -Package: nameref 2016/05/21 v2.44 Cross-referencing by name of section -(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty -Package: gettitlestring 2016/05/16 v1.5 Cleanup title references (HO) -) -\c@section@level=\count142 -) -LaTeX Info: Redefining \ref on input line 92. -LaTeX Info: Redefining \pageref on input line 92. -LaTeX Info: Redefining \nameref on input line 92. -*geometry* driver: auto-detecting -*geometry* detected driver: pdftex -*geometry* verbose mode - [ preamble ] result: -* driver: pdftex -* paper: -* layout: -* layoutoffset:(h,v)=(0.0pt,0.0pt) -* modes: -* h-part:(L,W,R)=(72.26999pt, 469.75502pt, 72.26999pt) -* v-part:(T,H,B)=(72.26999pt, 650.43001pt, 72.26999pt) -* \paperwidth=614.295pt -* \paperheight=794.96999pt -* \textwidth=469.75502pt -* \textheight=650.43001pt -* \oddsidemargin=0.0pt -* \evensidemargin=0.0pt -* \topmargin=-37.0pt -* \headheight=12.0pt -* \headsep=25.0pt -* \topskip=10.0pt -* \footskip=30.0pt -* \marginparwidth=65.0pt -* \marginparsep=11.0pt -* \columnsep=10.0pt -* \skip\footins=9.0pt plus 4.0pt minus 2.0pt -* \hoffset=0.0pt -* \voffset=0.0pt -* \mag=1000 -* \@twocolumnfalse -* \@twosidefalse -* \@mparswitchfalse -* \@reversemarginfalse -* (1in=72.27pt=25.4mm, 1cm=28.453pt) - - -File: hex-gsm.png Graphic file (type png) - -Package pdftex.def Info: hex-gsm.png used on input line 93. -(pdftex.def) Requested size: 124.91203pt x 144.54623pt. -LaTeX Font Info: Try loading font information for OT1+lmr on input line 93. -(/usr/share/texmf/tex/latex/lm/ot1lmr.fd -File: ot1lmr.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: Try loading font information for OML+lmm on input line 93. -(/usr/share/texmf/tex/latex/lm/omllmm.fd -File: omllmm.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: Try loading font information for OMS+lmsy on input line 93. - -(/usr/share/texmf/tex/latex/lm/omslmsy.fd -File: omslmsy.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: Try loading font information for OMX+lmex on input line 93. - -(/usr/share/texmf/tex/latex/lm/omxlmex.fd -File: omxlmex.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <12> on input line 93. -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <8> on input line 93. -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <6> on input line 93. -LaTeX Font Info: Try loading font information for U+msa on input line 93. -(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd -File: umsa.fd 2013/01/14 v3.01 AMS symbols A -) (/usr/share/texlive/texmf-dist/tex/latex/microtype/mt-msa.cfg -File: mt-msa.cfg 2006/02/04 v1.1 microtype config. file: AMS symbols (a) (RS) -) -LaTeX Font Info: Try loading font information for U+msb on input line 93. -(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd -File: umsb.fd 2013/01/14 v3.01 AMS symbols B -) (/usr/share/texlive/texmf-dist/tex/latex/microtype/mt-msb.cfg -File: mt-msb.cfg 2005/06/01 v1.0 microtype config. file: AMS symbols (b) (RS) -) (./qualification.toc -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <10> on input line 2. -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <7> on input line 2. -LaTeX Font Info: External font `lmex10' loaded for size -(Font) <5> on input line 2. -) -\tf@toc=\write3 -\openout3 = `qualification.toc'. - -[1 - -{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map} <./hex-gsm.png>] -Overfull \hbox (15.46773pt too wide) in paragraph at lines 109--116 -[][] - [] - - -Overfull \hbox (16.10669pt too wide) in paragraph at lines 119--128 -[][] - [] - -[2] - -LaTeX Warning: `!h' float specifier changed to `!ht'. - -[3] -Underfull \vbox (badness 10000) detected at line 311 - [] - -[4] -Underfull \vbox (badness 10000) detected at line 345 - [] - -[5 - -] -LaTeX Font Info: Try loading font information for TS1+lmr on input line 354. - -(/usr/share/texmf/tex/latex/lm/ts1lmr.fd -File: ts1lmr.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: Try loading font information for T1+lmtt on input line 366. - -(/usr/share/texmf/tex/latex/lm/t1lmtt.fd -File: t1lmtt.fd 2009/10/30 v1.6 Font defs for Latin Modern -) -LaTeX Font Info: Try loading font information for TS1+lmtt on input line 425 -. -(/usr/share/texmf/tex/latex/lm/ts1lmtt.fd -File: ts1lmtt.fd 2009/10/30 v1.6 Font defs for Latin Modern -) - -LaTeX Warning: `!h' float specifier changed to `!ht'. - - -LaTeX Warning: `!h' float specifier changed to `!ht'. - -Package atveryend Info: Empty hook `BeforeClearDocument' on input line 542. -[6] [7] -Package atveryend Info: Empty hook `AfterLastShipout' on input line 542. -(./qualification.aux) -Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 542. -Package atveryend Info: Empty hook `AtEndAfterFileList' on input line 542. -Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 542. - ) -Here is how much of TeX's memory you used: - 14535 strings out of 494923 - 208357 string characters out of 6180743 - 327182 words of memory out of 5000000 - 17522 multiletter control sequences out of 15000+600000 - 54787 words of font info for 70 fonts, out of 8000000 for 9000 - 14 hyphenation exceptions out of 8191 - 34i,11n,38p,373b,451s stack positions out of 5000i,500n,10000p,200000b,80000s -{/usr/share/texmf/fonts/enc/dvips/lm/lm-ts1.enc}{/usr/share/texmf/fonts/enc/d -vips/lm/lm-ec.enc} -Output written on qualification.pdf (7 pages, 284971 bytes). -PDF statistics: - 150 PDF objects out of 1000 (max. 8388607) - 130 compressed objects within 2 object streams - 39 named destinations out of 1000 (max. 500000) - 10310 words of extra memory for PDF output out of 12000 (max. 10000000) - diff --git a/vignettes/validation/.gitignore b/vignettes/validation/.gitignore deleted file mode 100644 index f9be8dfe0..000000000 --- a/vignettes/validation/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!* diff --git a/vignettes/validation/change_log.md b/vignettes/validation/change_log.md deleted file mode 100644 index 068d73560..000000000 --- a/vignettes/validation/change_log.md +++ /dev/null @@ -1,3 +0,0 @@ -# 0.0.0 2022-02-16 - -* [validation] Validation release notes for version 0.0.0 diff --git a/vignettes/validation/requirements/Specifications_for_AE_Assess.md b/vignettes/validation/requirements/Specifications_for_AE_Assess.md deleted file mode 100644 index ea857f04d..000000000 --- a/vignettes/validation/requirements/Specifications_for_AE_Assess.md +++ /dev/null @@ -1,21 +0,0 @@ -#' @title Specifications for AE Assessment -#' @editor Nathan Kosiba -#' @editDate 2022-02-08 -#' @riskAssessment -#' 1.1: 1, High Risk, High Impact -#' 1.2: 1, High Risk, High Impact -#' 1.3: 3, Low Risk, High Impact -#' 1.4: 2, Medium Risk, High Impact -#' 1.5: 4, Low Risk, Medium Impact -#' 1.6: 3, Medium Risk, Medium Impact - -+ 1.1 Given correct input data an Adverse Event assessment can be done using -the poisson method -+ 1.2 Given correct input data an Adverse Event assessment can be done using -the wilcoxon method -+ 1.3 Assessments are correctly grouped by the site variable -+ 1.4 Given correct input data an flags will correctly be applied to records that -meet flagging criteria -+ 1.5 Assessment can return all data in the standard data pipeline -(`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) -+ 1.6 Ensure that missing and invalid data are handled correctly diff --git a/vignettes/validation/requirements/Specifications_for_AE_Map_Raw.md b/vignettes/validation/requirements/Specifications_for_AE_Map_Raw.md deleted file mode 100644 index 52aa51bca..000000000 --- a/vignettes/validation/requirements/Specifications_for_AE_Map_Raw.md +++ /dev/null @@ -1,16 +0,0 @@ -#' @title Specifications for AE Map Raw -#' @editor Matt Roumaya -#' @editDate 2022-02-14 -#' @riskAssessment -#' 2.1: 3, Low Risk, Medium Impact -#' 2.2: 3, Medium Risk, High Impact -#' 2.3: 3, Medium Risk, High Impact -#' 2.4: 1, Medium Risk, Low Impact -#' 2.5: 1, Medium Risk, Low Impact - -+ 2.1 Given correct input data, a tibble/data.frame is produced with expected -dimensions -+ 2.2 Given correct input data, `Count` is calculated correctly -+ 2.3 Given correct input data, `Rate` is calculated correctly -+ 2.4 Missing data is handled correctly -+ 2.5 Duplicate data is handled correctly diff --git a/vignettes/validation/test_cases/Test_Cases_for_AE_Assess.md b/vignettes/validation/test_cases/Test_Cases_for_AE_Assess.md deleted file mode 100644 index 1e84f0731..000000000 --- a/vignettes/validation/test_cases/Test_Cases_for_AE_Assess.md +++ /dev/null @@ -1,24 +0,0 @@ -#' @title Test_Cases_for_AE_Assessment -#' @editor Nathan Kosiba -#' @editDate 2022-02-22 -#' @coverage -#' 1.1: 1.1, 1.3, 1.4 -#' 1.2: 1.2, 1.3, 1.4 -#' 1.3: 1.5 -#' 1.4: 1.6 -#' 1.5: 1.6 - - -+ Setup is documented in the test_code/*.R file. - -+ 1.1 Test that the AE assessment can return a correctly assessed data frame -for the poisson test grouped by the study variable when given correct input data -and the results should be flagged correctly. -+ 1.2 Test that the AE assessment can return a correctly assessed data frame -for the wilcoxon test grouped by the study variable when given correct input data -and the results should be flagged correctly. -+ 1.3 Test that Assessment can return all data in the standard data pipeline -(`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) -+ 1.4 Test that (NA, NaN) in input exposure data throws a warning and -drops the participant(s) from the analysis. -+ 1.5 Test that (NA, NaN) in input count data throws an error. diff --git a/vignettes/validation/test_cases/Test_Cases_for_AE_Map_Raw.md b/vignettes/validation/test_cases/Test_Cases_for_AE_Map_Raw.md deleted file mode 100644 index ae92c6615..000000000 --- a/vignettes/validation/test_cases/Test_Cases_for_AE_Map_Raw.md +++ /dev/null @@ -1,19 +0,0 @@ -#' @title Test_Cases_for_AE_Map_Raw -#' @editor Matt Roumaya -#' @editDate 2022-02-14 -#' @coverage -#' 2.1: 2.1 -#' 2.2: 2.2 -#' 2.3: 2.3 -#' 2.4: 2.4 -#' 2.5: 2.5 - - -+ Setup is documented in the test_code/*.R file. - -+ 2.1 Test that AE_Map_Raw can return a tibble/data.frame given correct input -data. -+ 2.2 Test that Count is calculated correctly using minimal sample data. -+ 2.3 Test that Rate is calculated correctly using minimal sample data. -+ 2.4 Test that missing data throws a warning and is dropped correctly. -+ 2.5 Test that duplicate data throws a warning and is handled correctly. diff --git a/vignettes/validation/test_code/Tests_for_AE_Assess.R b/vignettes/validation/test_code/Tests_for_AE_Assess.R deleted file mode 100644 index 086882f15..000000000 --- a/vignettes/validation/test_code/Tests_for_AE_Assess.R +++ /dev/null @@ -1,318 +0,0 @@ -# Test setup -library(gsm) -library(tidyverse) -library(testthat) -library(safetyData) - - -# general data ------------------------------------------------------------ - -dfADSL <- safetyData::adam_adsl -dfADAE <- safetyData::adam_adae - -dfInput <- gsm::AE_Map_Adam( - dfADSL = dfADSL, - dfADAE = dfADAE -) - - -# poisson data ------------------------------------------------------------ - -expectedOutput_Poisson <- dplyr::tribble( - ~Assessment, ~Label, ~SiteID, ~N, ~PValue, ~Flag, - "Safety", "", "705", 16L, 0.0000000000826737854296997, -1, - "Safety", "", "701", 41L, 0.0000283727759492465, 0, - "Safety", "", "715", 8L, 0.000111810890487798, 0, - "Safety", "", "716", 24L, 0.000133299808050092, 0, - "Safety", "", "718", 13L, 0.000339416106757253, 0, - "Safety", "", "711", 4L, 0.00347231444695581, 0, - "Safety", "", "713", 9L, 0.0104472139607388, 0, - "Safety", "", "703", 18L, 0.0425642468439372, 0, - "Safety", "", "702", 1L, 0.0440257544160385, 0, - "Safety", "", "706", 3L, 0.0626607908003469, 0, - "Safety", "", "709", 21L, 0.0875843645147626, 0, - "Safety", "", "717", 7L, 0.0880581938959983, 0, - "Safety", "", "710", 31L, 0.442917883338279, 0, - "Safety", "", "707", 2L, 0.461206125136541, 0, - "Safety", "", "708", 25L, 0.595361600709241, 0, - "Safety", "", "714", 6L, 0.708639504442164, 0, - "Safety", "", "704", 25L, 0.877647247203658, 0 -) %>% - dplyr::mutate( - dplyr::across(Assessment:SiteID, as.character), - dplyr::across(N, as.integer), - dplyr::across(PValue:Flag, as.numeric) - ) - -attr(expectedOutput_Poisson$SiteID, "label") <- "Study Site Identifier" - - -# wilcoxon data ----------------------------------------------------------- - -expectedOutput_Wilcoxon <- dplyr::tribble( - ~Assessment, ~Label, ~SiteID, ~N, ~PValue, ~Flag, - "Safety", "", "702", 1, 0.12578642463894, 0, - "Safety", "", "705", 1, 0.12578642463894, 0, - "Safety", "", "711", 1, 0.184572552839883, 0, - "Safety", "", "715", 1, 0.184572552839883, 0, - "Safety", "", "706", 1, 0.261572236013949, 0, - "Safety", "", "716", 1, 0.261572236013949, 0, - "Safety", "", "713", 1, 0.35832646674888, 0, - "Safety", "", "718", 1, 0.35832646674888, 0, - "Safety", "", "703", 1, 0.474958539889507, 0, - "Safety", "", "717", 1, 0.474958539889507, 0, - "Safety", "", "701", 1, 0.609834043673459, 0, - "Safety", "", "708", 1, 0.609834043673459, 0, - "Safety", "", "704", 1, 0.759462865379934, 0, - "Safety", "", "714", 1, 0.759462865379934, 0, - "Safety", "", "709", 1, 0.918707405428289, 0, - "Safety", "", "710", 1, 0.918707405428289, 0, - "Safety", "", "707", 1, 1, 0 -) - - -# + 1.1 Test that the AE assessment can return a correctly assessed data frame -# for the poisson test grouped by the study variable when given correct input data -# and the results should be flagged correctly. - -#' @editor Nathan Kosiba -#' @editDate 2022-02-22 -test_that("1.1", { - -# data -------------------------------------------------------------------- - - t1_data <- AE_Assess( - dfInput = dfInput - ) - -# ------------------------------------------------------------------------- - - - - # all expected names exist in output - expect_equal( - names(AE_Assess(dfInput = dfInput)), - c("Assessment", "Label", "SiteID", "N", "PValue", "Flag") - ) - - # all expected variable classes - expect_equal( - map_chr(AE_Assess(dfInput = dfInput), ~class(.)), - c(Assessment = "character", - Label = "character", - SiteID = "character", - N = "integer", - PValue = "numeric", - Flag = "numeric") - ) - - # alternate method of checking classes - expect_type(t1_data$Assessment, "character") - expect_type(t1_data$Label, "character") - expect_type(t1_data$SiteID, "character") - expect_type(t1_data$N, "integer") - expect_type(t1_data$PValue, "double") - expect_type(t1_data$Flag, "double") - - # descriptive stats check - expect_equal( - dfInput %>% - AE_Assess() %>% - summarize( - row_count = n(), - total_n = sum(N), - total_pvalue = sum(PValue), - mean_n = mean(N), - mean_pvalue = mean(PValue) - ), - - expectedOutput_Poisson %>% - summarize( - row_count = n(), - total_n = sum(N), - total_pvalue = sum(PValue), - mean_n = mean(N), - mean_pvalue = mean(PValue) - ) - ) - - # flags match - expect_true( - all(AE_Assess(dfInput = dfInput) %>% select(Flag) == expectedOutput_Poisson %>% select(Flag)) - ) - - # flag values - expect_gte(min(t1_data$Flag), -1) - expect_lte(max(t1_data$Flag), 1) - - -}) - -# + 1.2 Test that the AE assessment can return a correctly assessed data frame -# for the wilcoxon test grouped by the study variable when given correct input data -# and the results should be flagged correctly. - -#' @editor Nathan Kosiba -#' @editDate 2022-02-22 -test_that("1.2",{ - -# data -------------------------------------------------------------------- - - t2_data <- AE_Assess( - dfInput = dfInput, - cMethod = "wilcoxon" - ) - -# ------------------------------------------------------------------------- - - - - # all expected names exist in output - expect_equal( - names(AE_Assess(dfInput = dfInput, cMethod = "wilcoxon")), - c("Assessment", "Label", "SiteID", "N", "PValue", "Flag") - ) - - # all expected variable classes - # matt note: different class for N between poisson and wilcoxon (integer / numeric) - expect_equal( - map_chr(AE_Assess(dfInput = dfInput, cMethod = "wilcoxon"), ~class(.)), - c(Assessment = "character", - Label = "character", - SiteID = "character", - N = "numeric", - PValue = "numeric", - Flag = "numeric") - ) - - # alternate method of checking classes - # matt note: different typeof for N between poisson and wilcoxon (integer / double) - expect_type(t2_data$Assessment, "character") - expect_type(t2_data$Label, "character") - expect_type(t2_data$SiteID, "character") - expect_type(t2_data$N, "double") - expect_type(t2_data$PValue, "double") - expect_type(t2_data$Flag, "double") - - # descriptive stats check - # matt note: not sure why i needed to add as_tibble() here to coerce to tibble - was a data.frame() and failed the check - expect_equal( - dfInput %>% - AE_Assess(cMethod = "wilcoxon") %>% - summarize( - row_count = n(), - total_n = sum(N), - total_pvalue = sum(PValue), - mean_n = mean(N), - mean_pvalue = mean(PValue) - ) %>% - as_tibble(), - - expectedOutput_Wilcoxon %>% - summarize( - row_count = n(), - total_n = sum(N), - total_pvalue = sum(PValue), - mean_n = mean(N), - mean_pvalue = mean(PValue) - ) - ) - - # flags match - expect_true( - all(AE_Assess(dfInput = dfInput, cMethod = "wilcoxon") %>% select(Flag) == expectedOutput_Wilcoxon %>% select(Flag)) - ) - - # flag values - expect_gte(min(t2_data$Flag), -1) - expect_lte(max(t2_data$Flag), 1) - -}) - -# + 1.3 Test that Assessment can return all data in the standard data pipeline -# (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) - -#' @editor Matt Roumaya -#' @editDate 2022-02-18 -test_that("1.3", { - -# data -------------------------------------------------------------------- - - t3_data <- AE_Assess( - dfInput = dfInput, - bDataList = TRUE - ) - -# ------------------------------------------------------------------------- - - - - # check names of data.frames - expect_equal( - names(t3_data), - c("dfInput", "dfTransformed", "dfAnalyzed", "dfFlagged", "dfSummary") - ) - - # check that a list is returned - expect_type( - t3_data, "list" - ) - - # check that all objects returned by bDataList = TRUE are data.frames - expect_true("data.frame" %in% class(t3_data$dfInput)) - expect_true("data.frame" %in% class(t3_data$dfTransformed)) - expect_true("data.frame" %in% class(t3_data$dfAnalyzed)) - expect_true("data.frame" %in% class(t3_data$dfFlagged)) - expect_true("data.frame" %in% class(t3_data$dfSummary)) - - -}) - -# + 1.4 Test that (NA, NaN) in input exposure data throws a warning and -# drops the person(s) from the analysis. - -#' @editor Matt Roumaya -#' @editDate 2022-02-23 -test_that("1.4", { - - -# ------------------------------------------------------------------------- - - # data - # several NA values - dfInputWithNA1 <- dfInput %>% - mutate(Exposure = ifelse(substr(SubjectID,11,11) != 1, Exposure, NA_integer_)) - - # one NA value - dfInputWithNA2 <- dfInput %>% - mutate(Exposure = ifelse(SubjectID == "01-701-1015", NA_integer_, Exposure)) - -# ------------------------------------------------------------------------- - -expect_warning(AE_Assess(dfInputWithNA1)) -expect_warning(AE_Assess(dfInputWithNA2)) - - -}) - - -# + 1.5 Test that (NA, NaN) in input count data throws an error. - -#' @editor Matt Roumaya -#' @editDate 2022-02-23 -test_that("1.5", { - -# data -------------------------------------------------------------------- - - dfInputCountNA <- dfInput %>% - mutate(Count = ifelse(SubjectID == "01-701-1015", NA_integer_, Count)) - -# ------------------------------------------------------------------------- - - expect_error(AE_Assess(dfInputCountNA)) - - -}) - - - diff --git a/vignettes/validation/test_code/Tests_for_AE_Map_Raw.R b/vignettes/validation/test_code/Tests_for_AE_Map_Raw.R deleted file mode 100644 index 35157f531..000000000 --- a/vignettes/validation/test_code/Tests_for_AE_Map_Raw.R +++ /dev/null @@ -1,232 +0,0 @@ - -# Test setup -library(tidyverse) -library(testthat) -library(clindata) -library(gsm) - -# general data ------------------------------------------------------------ - - - -# save for reproducibility - but better hardcoded below -# dfAEMinimal <- clindata::raw_ae %>% select(SubjectID = SUBJID) %>% slice(1:3) -# -# dfRDSLMinimal <- clindata::rawplus_rdsl %>% -# select("SubjectID", "SiteID", "FirstDoseDate", "LastDoseDate", "TimeOnTreatment") %>% -# filter(SubjectID %in% c("0496", "1350")) %>% -# mutate(across(SubjectID:LastDoseDate, ~as.character(.))) %>% -# add_row(SubjectID = "0123", -# SiteID = "X111X", -# FirstDoseDate = "2017-11-13" , -# LastDoseDate = "2022-02-15", -# TimeOnTreatment = 1556) - - -# data -------------------------------------------------------------------- - -dfAE <- clindata::raw_ae -dfRDSL <- clindata::rawplus_rdsl - -dfAEMinimal <- tibble::tribble( - ~SUBJID, - "0496", - "0496", - "1350" - ) - -dfRDSLMinimal <- tibble::tribble( - ~SubjectID, ~SiteID, ~FirstDoseDate, ~LastDoseDate, ~TimeOnTreatment, - "1350", "X108X", "2017-11-13", "2022-02-16", 1557, - "0496", "X055X", "2013-12-31", "2022-02-16", 2970, - "0123", "X111X", "2017-11-13", "2022-02-15", 1556 - ) - - - -expectedOutputMinimal <- tibble::tribble( - ~SubjectID, ~SiteID, ~Count, ~Exposure, ~Rate, - "1350", "X108X", 1L, 1557, 0.000642260757867694, - "0496", "X055X", 2L, 2970, 0.000673400673400673, - "0123", "X111X", 0L, 1556, 0 - ) -# ------------------------------------------------------------------------- - - - - -#' @editor Matt Roumaya -#' @editDate 2022-02-18 -test_that("2.1", { - - -# data -------------------------------------------------------------------- - -t1_data <- AE_Map_Raw(clindata::raw_ae, - clindata::rawplus_rdsl) - -# ------------------------------------------------------------------------- - - - -# AE_Map_Raw() returns a data.frame -expect_true(is.data.frame(t1_data)) - -# AE_Map_Raw() returns correct column names -expect_equal( - names(t1_data), - c("SubjectID", "SiteID", "Count", "Exposure", "Rate") -) - -# AE_Map_Raw() returns correct column types -expect_type(t1_data$SubjectID, "character") -expect_type(t1_data$SiteID, "character") -expect_type(t1_data$Count, "integer") -expect_type(t1_data$Exposure, "double") -expect_type(t1_data$Rate, "double") - -# expected number of rows -expect_equal(nrow(t1_data), 2387) - -# expected number of columns -expect_equal(length(t1_data), 5) - -# expected number of NA values -expect_equal(sum(colSums(is.na(t1_data))), 2178) - -}) - - -#' @editor Matt Roumaya -#' @editDate 2022-02-18 -test_that("2.2", { - - -t2_data <- AE_Map_Raw( - dfAE = dfAEMinimal, - dfRDSL = dfRDSLMinimal - ) - - # check table of expected counts - expect_equal( - table(t2_data$Count), - table(expectedOutputMinimal$Count) - ) - - # standard count - expect_equal( - t2_data %>% filter(SubjectID == "0496") %>% pull(Count), - 2 - ) - - # standard count 2 - expect_equal( - t2_data %>% filter(SubjectID == "1350") %>% pull(Count), - 1 - ) - - # check that 0123 count == 0 - expect_equal( - t2_data %>% filter(SubjectID == "0123") %>% pull(Count), - 0 - ) - - # no negative counts - expect_gte( - AE_Map_Raw( - dfAE = dfAE, - dfRDSL = dfRDSL - ) %>% - filter(Count == min(Count)) %>% - slice(1) %>% - pull(Count), - 0 - ) - - -}) - -#' @editor Matt Roumaya -#' @editDate 2022-02-18 -test_that("2.3", { - - # rate is count / exposure - -# data -------------------------------------------------------------------- - - dfRDSLRateMinimal <- tibble::tribble( - ~SubjectID, ~SiteID, ~firstDoseDate, ~lastDoseDate, ~Exposure, - "0001", "X055X", "2013-12-31", "2022-02-15", 10 - ) - - dfAERateMinimal <- tibble::tribble(~SUBJID, - "0001", - - ) - - expectedOutputRate <-tibble::tribble( - ~SubjectID, ~SiteID, ~Count, ~Exposure, ~Rate, - "0001", "X055X", 1L, 10, 0.1 - ) - - t3_data <- AE_Map_Raw( - dfAE = dfAE, - dfRDSL = dfRDSL - ) - -# ------------------------------------------------------------------------- - - - - expect_equal( - AE_Map_Raw(dfAE = dfAERateMinimal, - dfRDSL = dfRDSLRateMinimal, - strExposureCol = "Exposure"), - expectedOutputRate - ) - - expect_gte( - min(t3_data$Count), - 0 - ) - -}) - -#' @editor Matt Roumaya -#' @editDate 2022-02-18 -test_that("2.4", { - -# data -------------------------------------------------------------------- - dfRDSLMinimalNA <- tibble::tribble( - ~SubjectID, ~SiteID, ~firstDoseDate, ~lastDoseDate, ~Exposure, - NA, "X055X", "2013-12-31", "2022-02-15", NA, - "1350", "X108X", "2017-11-13", "2022-02-15", NA, - "0123", "X111X", "2017-11-13", "2022-02-15", 1556 - ) - - dfAEMinimalNA <- tibble::tribble(~SUBJID, - "0496", - "0496", - "1350" - ) - - t4_data <- AE_Map_Raw( - dfAE = dfAEMinimalNA, - dfRDSL = dfRDSLMinimalNA, - strExposureCol = "Exposure" - ) - -# ------------------------------------------------------------------------- - - - - expect_true(!"0496" %in% t4_data$SubjectID) - expect_equal(t4_data %>% - filter(SubjectID == 1350) %>% - pull(Rate), - NA_integer_) - - }) - - - diff --git a/vignettes/validation/validation.yml b/vignettes/validation/validation.yml deleted file mode 100644 index 17cc21164..000000000 --- a/vignettes/validation/validation.yml +++ /dev/null @@ -1,21 +0,0 @@ -package: gsm -working_dir: vignettes -output_dir: inst -report_rmd_name: qualification.Rmd -report_naming_format: Qualification_Report_{package}_v{version}_{date} -usernames: - nathan.kosiba: - name: Nathan Kosiba - title: Developer - role: Qualification Lead - matt.roumaya: - name: Matt Roumaya - title: Developer - role: Qualification Developer -validation_files: -- Specifications_for_AE_Assess.md -- Specifications_for_AE_Map_Raw.md -- Test_Cases_for_AE_Assess.md -- Test_Cases_for_AE_Map_Raw.md -- Tests_for_AE_Assess.R -- Tests_for_AE_Map_Raw.R From f7349b5cc7a41072ee7cc172105aae650b6650f2 Mon Sep 17 00:00:00 2001 From: Nathan Kosiba Date: Mon, 7 Mar 2022 18:40:43 +0000 Subject: [PATCH 36/60] rename test files --- tests/testthat/{test-test_qual_T1_1.R => test_qual_T1_1.R} | 0 tests/testthat/{test-test_qual_T1_2.R => test_qual_T1_2.R} | 0 tests/testthat/{test-test_qual_T1_3.R => test_qual_T1_3.R} | 0 tests/testthat/{test-test_qual_T1_4.R => test_qual_T1_4.R} | 0 tests/testthat/{test-test_qual_T1_5.R => test_qual_T1_5.R} | 0 tests/testthat/{test-test_qual_T1_6.R => test_qual_T1_6.R} | 0 tests/testthat/{test-test_qual_T1_7.R => test_qual_T1_7.R} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-test_qual_T1_1.R => test_qual_T1_1.R} (100%) rename tests/testthat/{test-test_qual_T1_2.R => test_qual_T1_2.R} (100%) rename tests/testthat/{test-test_qual_T1_3.R => test_qual_T1_3.R} (100%) rename tests/testthat/{test-test_qual_T1_4.R => test_qual_T1_4.R} (100%) rename tests/testthat/{test-test_qual_T1_5.R => test_qual_T1_5.R} (100%) rename tests/testthat/{test-test_qual_T1_6.R => test_qual_T1_6.R} (100%) rename tests/testthat/{test-test_qual_T1_7.R => test_qual_T1_7.R} (100%) diff --git a/tests/testthat/test-test_qual_T1_1.R b/tests/testthat/test_qual_T1_1.R similarity index 100% rename from tests/testthat/test-test_qual_T1_1.R rename to tests/testthat/test_qual_T1_1.R diff --git a/tests/testthat/test-test_qual_T1_2.R b/tests/testthat/test_qual_T1_2.R similarity index 100% rename from tests/testthat/test-test_qual_T1_2.R rename to tests/testthat/test_qual_T1_2.R diff --git a/tests/testthat/test-test_qual_T1_3.R b/tests/testthat/test_qual_T1_3.R similarity index 100% rename from tests/testthat/test-test_qual_T1_3.R rename to tests/testthat/test_qual_T1_3.R diff --git a/tests/testthat/test-test_qual_T1_4.R b/tests/testthat/test_qual_T1_4.R similarity index 100% rename from tests/testthat/test-test_qual_T1_4.R rename to tests/testthat/test_qual_T1_4.R diff --git a/tests/testthat/test-test_qual_T1_5.R b/tests/testthat/test_qual_T1_5.R similarity index 100% rename from tests/testthat/test-test_qual_T1_5.R rename to tests/testthat/test_qual_T1_5.R diff --git a/tests/testthat/test-test_qual_T1_6.R b/tests/testthat/test_qual_T1_6.R similarity index 100% rename from tests/testthat/test-test_qual_T1_6.R rename to tests/testthat/test_qual_T1_6.R diff --git a/tests/testthat/test-test_qual_T1_7.R b/tests/testthat/test_qual_T1_7.R similarity index 100% rename from tests/testthat/test-test_qual_T1_7.R rename to tests/testthat/test_qual_T1_7.R From 6d836260241c7f8b7ffc437895b485f16096f1ef Mon Sep 17 00:00:00 2001 From: Nathan Kosiba Date: Mon, 7 Mar 2022 18:48:50 +0000 Subject: [PATCH 37/60] add double programmed unit tests for AE_Map_Adam & AE_Map_Raw --- tests/testthat/test_AE_Map_Adam.R | 52 +++++++++----- tests/testthat/test_AE_Map_Raw.R | 114 ++++++++++++++++++------------ 2 files changed, 103 insertions(+), 63 deletions(-) diff --git a/tests/testthat/test_AE_Map_Adam.R b/tests/testthat/test_AE_Map_Adam.R index 52d02e8bf..672bb51f3 100644 --- a/tests/testthat/test_AE_Map_Adam.R +++ b/tests/testthat/test_AE_Map_Adam.R @@ -1,13 +1,35 @@ test_that("output created as expected and has correct structure",{ ae_input <- AE_Map_Adam( - safetyData::adam_adsl, + safetyData::adam_adsl, safetyData::adam_adae - ) + ) expect_true(is.data.frame(ae_input)) expect_equal(names(ae_input), c("SubjectID","SiteID","Count","Exposure","Rate")) }) +test_that("all data is mapped and summarized correctly",{ + AE_counts <- safetyData::adam_adae %>% + filter(USUBJID != "") %>% + group_by(USUBJID) %>% + summarize("Count" = n()) %>% + ungroup() %>% + select(USUBJID, Count) + + AE_mapped <- safetyData::adam_adsl %>% + left_join(AE_counts, by = "USUBJID") %>% + mutate(Count = as.integer(replace(Count, is.na(Count), 0))) %>% + mutate(Exposure = as.numeric(TRTEDT - TRTSDT) + 1) %>% + mutate(Rate = Count / Exposure) %>% + rename(SubjectID = USUBJID) %>% + rename(SiteID = SITEID) %>% + select(SubjectID, SiteID, Count, Exposure, Rate) + + expect_identical(AE_Map_Adam(dfADSL = safetyData::adam_adsl, + dfADAE = safetyData::adam_adae), + AE_mapped) +}) + test_that("incorrect inputs throw errors",{ expect_error(AE_Map_Adam(list(), list())) expect_error(AE_Map_Adam( safetyData::adam_adsl, list())) @@ -15,42 +37,40 @@ test_that("incorrect inputs throw errors",{ expect_error(AE_Map_Adam("Hi","Mom")) }) - - test_that("error given if required column not found",{ expect_error( - AE_Map_Adam( - safetyData::adam_adsl %>% rename(ID = USUBJID), + AE_Map_Adam( + safetyData::adam_adsl %>% rename(ID = USUBJID), safetyData::adam_adae ) ) expect_error( - AE_Map_Adam( - safetyData::adam_adsl %>% rename(EndDay = TRTEDT), + AE_Map_Adam( + safetyData::adam_adsl %>% rename(EndDay = TRTEDT), safetyData::adam_adae ) ) - + expect_error( - AE_Map_Adam( - safetyData::adam_adsl %>% select(-TRTSDT), + AE_Map_Adam( + safetyData::adam_adsl %>% select(-TRTSDT), safetyData::adam_adae ) ) - + expect_error( - AE_Map_Adam( - safetyData::adam_adsl , + AE_Map_Adam( + safetyData::adam_adsl , safetyData::adam_adae %>% select(-USUBJID) ) ) # renaming or dropping non-required cols is fine expect_silent( - AE_Map_Adam( - safetyData::adam_adsl %>% rename(Oldness=AGE), + AE_Map_Adam( + safetyData::adam_adsl %>% rename(Oldness=AGE), safetyData::adam_adae %>% select(-RACE) ) ) diff --git a/tests/testthat/test_AE_Map_Raw.R b/tests/testthat/test_AE_Map_Raw.R index a23f0c30c..1aad2db93 100644 --- a/tests/testthat/test_AE_Map_Raw.R +++ b/tests/testthat/test_AE_Map_Raw.R @@ -6,6 +6,26 @@ test_that("output created as expected and has correct structure",{ c("SubjectID","SiteID","Count","Exposure","Rate")) }) +test_that("all data is mapped and summarized correctly",{ + AE_counts <- clindata::raw_ae %>% + filter(SUBJID != "") %>% + group_by(SUBJID) %>% + summarize("Count" = n()) %>% + ungroup() %>% + select(SUBJID, Count) + + AE_mapped <- clindata::rawplus_rdsl %>% + left_join(AE_counts, by = c("SubjectID" = "SUBJID")) %>% + mutate(Count = as.integer(replace(Count, is.na(Count), 0))) %>% + rename(Exposure = TimeOnTreatment) %>% + mutate(Rate = Count / Exposure) %>% + select(SubjectID, SiteID, Count, Exposure, Rate) + + expect_identical(AE_Map_Raw(clindata::raw_ae, + clindata::rawplus_rdsl), + AE_mapped) +}) + test_that("incorrect inputs throw errors",{ expect_error(AE_Map_Raw(list(), list())) expect_error(AE_Map_Raw( clindata::raw_ae, list())) @@ -20,58 +40,58 @@ test_that("invalid strExposureCol throws error",{ test_that("error given if required column not found",{ expect_error( - AE_Map_Raw( - clindata::raw_ae %>% rename(ID = SUBJID), + AE_Map_Raw( + clindata::raw_ae %>% rename(ID = SUBJID), clindata::rawplus_rdsl ) ) - + expect_error( AE_Map_Raw( clindata::raw_ae , clindata::rawplus_rdsl %>% select(-SiteID) ) ) - + expect_error( - AE_Map_Raw( - clindata::raw_ae , + AE_Map_Raw( + clindata::raw_ae , clindata::rawplus_rdsl %>% select(-SubjectID) ) ) - - - + + + expect_error( - AE_Map_Raw( - clindata::raw_ae , + AE_Map_Raw( + clindata::raw_ae , clindata::rawplus_rdsl , strExposureCol="Exposure" ) ) - + expect_error( - AE_Map_Raw( - clindata::raw_ae , + AE_Map_Raw( + clindata::raw_ae , clindata::rawplus_rdsl %>% select(-SiteID) ) ) - - + + expect_silent( - AE_Map_Raw( - clindata::raw_ae %>% select(-PROJECT), - clindata::rawplus_rdsl + AE_Map_Raw( + clindata::raw_ae %>% select(-PROJECT), + clindata::rawplus_rdsl ) ) }) test_that("output is correct given example input",{ - + dfAE <- tibble::tribble(~SUBJID, 1,1,1,1,2,2) - + dfRDSL<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, 1, 1, 10, @@ -79,19 +99,19 @@ test_that("output is correct given example input",{ 3, 1, 30 ) - + dfInput <-tibble::tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, 1, 1, 4, 10, 0.4, 2, 1, 2, NA, NA, - 3, 1, 0, 30, 0 + 3, 1, 0, 30, 0 ) - + expect_equal(dfInput, AE_Map_Raw(dfAE, dfRDSL )) - + dfAE2 <- tibble::tribble(~SUBJID, 1,1,1,1,2,2,4,4) - + dfExposure2<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, 1, 1, 10, @@ -99,8 +119,8 @@ test_that("output is correct given example input",{ 3, 1, 30, 4, 2, 50 ) - - + + dfInput2 <-tibble::tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, 1, 1, 4, 10, 0.4, @@ -108,19 +128,19 @@ test_that("output is correct given example input",{ 3, 1, 0, 30, 0 , 4, 2, 2, 50, .04 ) - - - + + + expect_equal(dfInput2, AE_Map_Raw(dfAE = dfAE2, dfRDSL = dfExposure2)) - - - + + + }) test_that("NA values in input data are handled",{ - + dfAE3 <- tibble::tribble(~SUBJID, 1,1,1,1,2,2,4,4) - + dfExposure3<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, 1, 1, 10, @@ -128,8 +148,8 @@ test_that("NA values in input data are handled",{ 3, NA, 30, 4, 2, 50 ) - - + + dfInput3 <-tibble::tribble( ~SubjectID, ~SiteID, ~Count, ~Exposure,~Rate, 1, 1, 4, 10, 0.4, @@ -137,16 +157,16 @@ test_that("NA values in input data are handled",{ 3, NA, 0, 30, 0 , 4, 2, 2, 50, .04 ) - + expect_equal(dfInput3, AE_Map_Raw(dfAE = dfAE3, dfRDSL = dfExposure3)) - - + + }) test_that("dfAE$SUBJID NA value throws error",{ dfAE4 <- tibble::tribble(~SUBJID, 1,NA,1,1,2,2,4,4) - + dfExposure4<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, 1, 1, 10, @@ -154,14 +174,14 @@ test_that("dfAE$SUBJID NA value throws error",{ 3, 3, 30, 4, 2, 50 ) - - + + expect_error(AE_Map_Raw(dfAE = dfAE4, dfRDSL = dfExposure4)) }) test_that("dfRDSL$SubjectID NA value throws error",{ dfAE4 <- tibble::tribble(~SUBJID, 1,1,1,1,2,2,4,4) - + dfExposure4<-tibble::tribble( ~SubjectID, ~SiteID, ~TimeOnTreatment, NA, 1, 10, @@ -169,7 +189,7 @@ test_that("dfRDSL$SubjectID NA value throws error",{ 3, 2, 30, 4, 2, 50 ) - - + + expect_error(AE_Map_Raw(dfAE = dfAE4, dfRDSL = dfExposure4)) }) From 307a5f66638bb3559c8d4b1cac4327dc13ab8e78 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 19:06:43 +0000 Subject: [PATCH 38/60] update tests --- tests/testthat/test_Analyze_Wilcoxon.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test_Analyze_Wilcoxon.R b/tests/testthat/test_Analyze_Wilcoxon.R index 743ead3c5..8014ff5e4 100644 --- a/tests/testthat/test_Analyze_Wilcoxon.R +++ b/tests/testthat/test_Analyze_Wilcoxon.R @@ -18,7 +18,7 @@ test_that("incorrect inputs throw errors",{ }) test_that("error given if required column not found",{ - expect_error(Analyze_Wilcoxon(ae_input %>% rename(total = TotalCount))) - expect_error(Analyze_Wilcoxon(ae_input %>% select(-Rate))) + expect_error(Analyze_Wilcoxon(ae_prep %>% rename(total = TotalCount))) + expect_error(Analyze_Wilcoxon(ae_prep %>% select(-Rate))) }) From a88bfd311f098f5d45541a99cf7556d02951d05d Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 19:22:50 +0000 Subject: [PATCH 39/60] update docs --- man/Analyze_Poisson.Rd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/man/Analyze_Poisson.Rd b/man/Analyze_Poisson.Rd index 500ef3e3c..552e002aa 100644 --- a/man/Analyze_Poisson.Rd +++ b/man/Analyze_Poisson.Rd @@ -10,7 +10,7 @@ Analyze_Poisson(dfTransformed) \item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}. Must include SubjectID, SiteID, TotalCount and TotalExposure.} } \value{ -input data frame with columns added for "Residuals" and "PredictedCount" +input data.frame with columns added for "Residuals" and "PredictedCount" } \description{ Poisson Analysis - Site Residuals @@ -27,12 +27,13 @@ This function fits a poisson model to site-level data and then calculates residu \section{Data Specification}{ -The input data (\code{ dfTransformed}) for the Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +The input data (\code{dfTransformed}) for Analyze_Poisson is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: \itemize{ -\item \code{SubjectID} - Unique subject ID \item \code{SiteID} - Site ID -\item \code{TotalCount} - Number of Events +\item \code{N} - Number of participants +\item \code{TotalCount} - Number of Adverse Events \item \code{TotalExposure} - Number of days of exposure +\item \code{Rate} - Rate of exposure (TotalCount / TotalExposure) } } From 2ca101f94fc778ce76a5d9cc2881df46642a98db Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 20:17:47 +0000 Subject: [PATCH 40/60] update documentation --- R/IE_Map_Raw.R | 2 +- man/IE_Map_Raw.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 4e90543db..9d9a9e81e 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -18,7 +18,7 @@ #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID #' -#' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. By default, includes required columns SUBJID, IVID, IECAT, IETESTCD, IEORRES. +#' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID #' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' #' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 3ed3f35ec..7181a83da 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -14,7 +14,7 @@ IE_Map_Raw( ) } \arguments{ -\item{dfIE}{ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. By default, includes required columns SUBJID, IVID, IECAT, IETESTCD, IEORRES.} +\item{dfIE}{ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol.} \item{dfRDSL}{Subject-level Raw Data (RDSL) required columns: SubjectID SiteID} From ae5faace17b5d8f5ac26726586ed16bbe04b678e Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 20:20:55 +0000 Subject: [PATCH 41/60] update tests --- tests/testthat/test_Analyze_Poisson.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test_Analyze_Poisson.R b/tests/testthat/test_Analyze_Poisson.R index d51dfa83e..436ca068b 100644 --- a/tests/testthat/test_Analyze_Poisson.R +++ b/tests/testthat/test_Analyze_Poisson.R @@ -18,11 +18,12 @@ test_that("incorrect inputs throw errors",{ test_that("error given if required column not found",{ - expect_error(Analyze_Poisson(ae_input %>% select(-SiteID))) - expect_error(Analyze_Poisson(ae_input %>% select(-N))) - expect_error(Analyze_Poisson(ae_input %>% select(-TotalCount))) - expect_error(Analyze_Poisson(ae_input %>% select(-TotalExposure))) - expect_error(Analyze_Poisson(ae_input %>% select(-Rate))) + ae_prep <- Transform_EventCount( ae_input, strCountCol = 'Count', strExposureCol = "Exposure" ) + expect_error(Analyze_Poisson(ae_prep %>% select(-SiteID))) + expect_error(Analyze_Poisson(ae_prep %>% select(-N))) + expect_error(Analyze_Poisson(ae_prep %>% select(-TotalCount))) + expect_error(Analyze_Poisson(ae_prep %>% select(-TotalExposure))) + expect_error(Analyze_Poisson(ae_prep %>% select(-Rate))) }) test_that("NA values are caught", { From c243ed99d005b08eed2b2ea212c4cd4f72d9b85f Mon Sep 17 00:00:00 2001 From: Nathan Kosiba Date: Mon, 7 Mar 2022 20:24:46 +0000 Subject: [PATCH 42/60] update yaml format --- inst/qualification/specs.yaml | 92 ++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/inst/qualification/specs.yaml b/inst/qualification/specs.yaml index 121e388c5..f27121acf 100644 --- a/inst/qualification/specs.yaml +++ b/inst/qualification/specs.yaml @@ -1,45 +1,47 @@ -S1_1: - Description: Given correct input data an Adverse Event assessment can be done using the poisson method - Risk: High - Impact: High - Tests: - - T1_1 - - T1_2 -S1_2: - Description: Given correct input data an Adverse Event assessment can be done using the wilcoxon method - Risk: High - Impact: High - Tests: - - T1_3 - - T1_4 -S1_3: - Description: Assessments are correctly grouped by the site variable - Risk: Low - Impact: High - Tests: - - T1_1 - - T1_2 - - T1_3 - - T1_4 -S1_4: - Description: Given correct input data an flags will correctly be applied to records thatmeet flagging criteria - Risk: Medium - Impact: High - Tests: - - T1_1 - - T1_2 - - T1_3 - - T1_4 -S1_5: - Description: Assessment can return all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) - Risk: Low - Impact: Medium - Tests: - - T1_5 - - T1_6 -S1_6: - Description: Ensure that missing and invalid data are handled correctly - Risk: Low - Impact: Medium - Tests: - - T1_7 +AE_Assess: + Specifications: + - S1_1: + Description: Given correct input data an Adverse Event assessment can be done using the poisson method + Risk: High + Impact: High + Tests: + - T1_1 + - T1_2 + - S1_2: + Description: Given correct input data an Adverse Event assessment can be done using the wilcoxon method + Risk: High + Impact: High + Tests: + - T1_3 + - T1_4 + - S1_3: + Description: Assessments are correctly grouped by the site variable + Risk: Low + Impact: High + Tests: + - T1_1 + - T1_2 + - T1_3 + - T1_4 + - S1_4: + Description: Given correct input data an flags will correctly be applied to records thatmeet flagging criteria + Risk: Medium + Impact: High + Tests: + - T1_1 + - T1_2 + - T1_3 + - T1_4 + - S1_5: + Description: Assessment can return all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged`, and `dfSummary`) + Risk: Low + Impact: Medium + Tests: + - T1_5 + - T1_6 + - S1_6: + Description: Ensure that missing and invalid data are handled correctly + Risk: Low + Impact: Medium + Tests: + - T1_7 From 90c0f350dbf53fd7aad8e58ce59f9914c4b2287d Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Mon, 7 Mar 2022 22:23:39 +0000 Subject: [PATCH 43/60] update LogExposure --- R/Visualize_Poisson.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R index 8ff8a51b6..88e917fb9 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Poisson.R @@ -22,7 +22,7 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ p <- ggplot( dfFlagged, aes( - x=.data$LogExposure, + x=log(.data$TotalExposure), y=.data$TotalCount, color=as.factor(.data$Flag)) ) + @@ -43,7 +43,7 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ ylab("Site Total Events") + geom_text( data = dfFlagged%>%filter(.data$Flag !=0), - aes( x = .data$LogExposure, y = .data$TotalCount, label = .data$SiteID), + aes( x = log(.data$TotalExposure), y = .data$TotalCount, label = .data$SiteID), vjust = 1.5, col="red", size=3.5 From 5b82865dbbf2e62583a820e7e17ae420bc8ba9ee Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Mon, 7 Mar 2022 16:30:49 -0800 Subject: [PATCH 44/60] made changes per QC --- R/IE_Assess.R | 12 ++++++++++-- man/IE_Assess.Rd | 10 +++++++++- tests/testthat/test_IE_Assess.R | 28 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index b84702733..e5c162670 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -16,10 +16,16 @@ #' - \code{\link{Transform_EventCount}} creates `dfTransformed`. #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. +#' +#' @section Assessment methodology: +#' INCORRECT, CUT AND PASTE - NEED To UPDATE +#' This Assessment finds any sites where one or more subjects which have Inclusion / Exclusion data that is either missing or has inconsistent data recorded for +#' inclusion / exclusion data. N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites +#' With N greater than user specified `nThreshold` will be flagged. #' #' #' @param dfInput input data with one record per person and the following required columns: SubjectID, SiteID, Count, -#' @param nThreshold integer threshold values Flagging, integer values greater than will be flagged. +#' @param nThreshold Any sites where 'N' is greater than nThreshold will be flagged. Default value is 0.5, which flags any site with one or more subjects meeting any of the criteria. #' @param strLabel Assessment label #' @param bDataList Should all assessment datasets be returned as a list? If False (the default), only the summary/finding data frame is returned #' @@ -51,7 +57,9 @@ IE_Assess <- function( dfInput, nThreshold=0.5, strLabel="", bDataList=FALSE){ "dfInput is not a data.frame" = is.data.frame(dfInput), "strLabel is not character" = is.character(strLabel), "bDataList is not logical" = is.logical(bDataList), - "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)) + "One or more of these columns: SubjectID, SiteID, Count, Exposure, and Rate not found in dfInput"=all(c("SubjectID","SiteID", "Count") %in% names(dfInput)), + "nThreshold must be numeric" = is.numeric(nThreshold), + "nThreshold must be length 1" = length(nThreshold) ==1 ) diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 09a7d2106..d5e356f81 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -9,7 +9,7 @@ IE_Assess(dfInput, nThreshold = 0.5, strLabel = "", bDataList = FALSE) \arguments{ \item{dfInput}{input data with one record per person and the following required columns: SubjectID, SiteID, Count,} -\item{nThreshold}{integer threshold values Flagging, integer values greater than will be flagged.} +\item{nThreshold}{Any sites where 'N' is greater than nThreshold will be flagged. Default value is 0.5, which flags any site with one or more subjects meeting any of the criteria.} \item{strLabel}{Assessment label} @@ -42,6 +42,14 @@ The Assessment } } +\section{Assessment methodology}{ + +INCORRECT, CUT AND PASTE - NEED To UPDATE +This Assessment finds any sites where one or more subjects which have Inclusion / Exclusion data that is either missing or has inconsistent data recorded for +inclusion / exclusion data. N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites +With N greater than user specified \code{nThreshold} will be flagged. +} + \examples{ dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, diff --git a/tests/testthat/test_IE_Assess.R b/tests/testthat/test_IE_Assess.R index 6d6cab33b..9725ca7a8 100644 --- a/tests/testthat/test_IE_Assess.R +++ b/tests/testthat/test_IE_Assess.R @@ -22,6 +22,8 @@ test_that("incorrect inputs throw errors",{ expect_error(IE_Assess(ie_input, strLabel=123)) expect_error(IE_Assess(ie_input, bDataList="Yes")) expect_error(IE_Assess(ie_input, nThreshold=FALSE)) + expect_error(IE_Assess(ie_input, nThreshold="A")) + expect_error(IE_Assess(ie_input, nThreshold=c(1,2))) }) @@ -49,12 +51,38 @@ target_ie_summary <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~Scor "Inclusion/Exclusion", "", "X194X", 2L, 17L, 1 ) +target_ie_summary_NA_SiteID <- tibble::tribble( ~Assessment, ~Label, ~SiteID, ~N, ~Score, ~Flag, + "Inclusion/Exclusion", "", "X194X", 1L, 8L, 1, + "Inclusion/Exclusion", "", "X033X", 1L, 9L, 1, + "Inclusion/Exclusion", "", "X159X", 1L, 9L, 1, + "Inclusion/Exclusion", "", NA, 1L, 9L, 1 +) + test_that("output is correct given example input",{ expect_equal(ie_summary,target_ie_summary) }) +test_that("NA in dfInput$SubjectID does not affect resulting dfSummary output for IE_Assess",{ + ie_input_in <- ie_input1; ie_input_in[1:2,"SubjectID"] = NA + ie_summary <- IE_Assess(ie_input_in, bDataList=FALSE) + expect_equal(ie_summary,target_ie_summary) +}) + +test_that("NA in dfInput$SiteID results in NA for SiteID in dfSummary output for IE_Assess",{ + ie_input_in <- ie_input1; ie_input_in[1,"SiteID"] = NA + ie_summary <- IE_Assess(ie_input_in, bDataList=FALSE) + expect_equal(ie_summary,target_ie_summary_NA_SiteID) +}) + +test_that("NA in dfInput$Count results in Error for IE_Assess",{ + ie_input_in <- ie_input1; ie_input_in[1,"Count"] = NA + expect_error(IE_Assess(ie_input_in)) +}) + + + From 02a81f72506cb96a72d591de509378cd57a01084 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Tue, 8 Mar 2022 15:49:39 +0000 Subject: [PATCH 45/60] closes #252 - bugfix for Visualize_Poisson() --- R/Visualize_Poisson.R | 4 ++-- tests/testthat/test-AE_Visualize.R | 3 --- tests/testthat/test-Visualize_Poisson.R | 7 +++++++ 3 files changed, 9 insertions(+), 5 deletions(-) delete mode 100644 tests/testthat/test-AE_Visualize.R create mode 100644 tests/testthat/test-Visualize_Poisson.R diff --git a/R/Visualize_Poisson.R b/R/Visualize_Poisson.R index 8ff8a51b6..88e917fb9 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Poisson.R @@ -22,7 +22,7 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ p <- ggplot( dfFlagged, aes( - x=.data$LogExposure, + x=log(.data$TotalExposure), y=.data$TotalCount, color=as.factor(.data$Flag)) ) + @@ -43,7 +43,7 @@ Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ ylab("Site Total Events") + geom_text( data = dfFlagged%>%filter(.data$Flag !=0), - aes( x = .data$LogExposure, y = .data$TotalCount, label = .data$SiteID), + aes( x = log(.data$TotalExposure), y = .data$TotalCount, label = .data$SiteID), vjust = 1.5, col="red", size=3.5 diff --git a/tests/testthat/test-AE_Visualize.R b/tests/testthat/test-AE_Visualize.R deleted file mode 100644 index 2afe30d56..000000000 --- a/tests/testthat/test-AE_Visualize.R +++ /dev/null @@ -1,3 +0,0 @@ -test_that("placeholder", { - expect_equal(2 * 2, 4) -}) diff --git a/tests/testthat/test-Visualize_Poisson.R b/tests/testthat/test-Visualize_Poisson.R new file mode 100644 index 000000000..d64cea971 --- /dev/null +++ b/tests/testthat/test-Visualize_Poisson.R @@ -0,0 +1,7 @@ +test_that("Output is produced", { + dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) + SafetyAE <- AE_Assess( dfInput , bDataList=TRUE, strMethod = "wilcoxon") + dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) + + expect_silent(Visualize_Poisson(SafetyAE$dfFlagged, dfBounds)) +}) From 292db0c7032ca6114aa8207208fce67e9597767f Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Tue, 8 Mar 2022 19:06:35 +0000 Subject: [PATCH 46/60] fix #224 - add visualization for wilcoxon --- NAMESPACE | 2 +- R/Analyze_Poisson_PredictBounds.R | 1 - R/{Analyze_Poisson.R => Analyze_Scatter.R} | 0 ...isualize_Poisson.R => Visualize_Scatter.R} | 19 ++++++----- man/Analyze_Poisson.Rd | 2 +- man/Visualize_Poisson.Rd | 28 ---------------- man/Visualize_Scatter.Rd | 32 +++++++++++++++++++ tests/testthat/test-Visualize_Poisson.R | 7 ---- tests/testthat/test-Visualize_Scatter.R | 16 ++++++++++ 9 files changed, 61 insertions(+), 46 deletions(-) rename R/{Analyze_Poisson.R => Analyze_Scatter.R} (100%) rename R/{Visualize_Poisson.R => Visualize_Scatter.R} (71%) delete mode 100644 man/Visualize_Poisson.Rd create mode 100644 man/Visualize_Scatter.Rd delete mode 100644 tests/testthat/test-Visualize_Poisson.R create mode 100644 tests/testthat/test-Visualize_Scatter.R diff --git a/NAMESPACE b/NAMESPACE index d1103eab4..91036e247 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,7 +19,7 @@ export(PD_Assess) export(PD_Map_Raw) export(Summarize) export(Transform_EventCount) -export(Visualize_Poisson) +export(Visualize_Scatter) import(dplyr) import(ggplot2) importFrom(broom,augment) diff --git a/R/Analyze_Poisson_PredictBounds.R b/R/Analyze_Poisson_PredictBounds.R index 51faedf12..51cfd558a 100644 --- a/R/Analyze_Poisson_PredictBounds.R +++ b/R/Analyze_Poisson_PredictBounds.R @@ -31,7 +31,6 @@ #' dfBounds <- Analyze_Poisson_PredictBounds(dfTransformed, c(-5,5)) #' #' @export - Analyze_Poisson_PredictBounds <- function( dfTransformed, vThreshold=c(-5,5)){ dfTransformed$LogExposure <- log(dfTransformed$TotalExposure) cModel <- glm( diff --git a/R/Analyze_Poisson.R b/R/Analyze_Scatter.R similarity index 100% rename from R/Analyze_Poisson.R rename to R/Analyze_Scatter.R diff --git a/R/Visualize_Poisson.R b/R/Visualize_Scatter.R similarity index 71% rename from R/Visualize_Poisson.R rename to R/Visualize_Scatter.R index 88e917fb9..b589c9fa7 100644 --- a/R/Visualize_Poisson.R +++ b/R/Visualize_Scatter.R @@ -1,22 +1,25 @@ -#' Site-level visualization of site-level Poisson Model results +#' Site-level visualization of site-level results using a Poisson or Wilcoxon model. #' #' @param dfFlagged analyze_poisson results with flags added. -#' @param dfBounds data.frame giving prediction bounds for range of dfFlagged +#' @param dfBounds data.frame giving prediction bounds for range of dfFlagged. #' @param strUnit exposure time unit. Defaults to "days". #' #' @return site level plot object #' #' @examples -#' dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) -#' dfAnalyzed <- Analyze_Poisson( dfTransformed) -#' dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) +#'dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +#'SafetyAE <- AE_Assess( dfInput , bDataList=TRUE) +#'dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) +#'Visualize_Scatter(SafetyAE$dfFlagged, dfBounds) +#' +#'dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +#'SafetyAE <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") +#'Visualize_Scatter(SafetyAE$dfFlagged) #' - #' @import ggplot2 #' #' @export -Visualize_Poisson <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ +Visualize_Scatter <- function( dfFlagged, dfBounds=NULL, strUnit="days"){ ### Plot of data p <- ggplot( diff --git a/man/Analyze_Poisson.Rd b/man/Analyze_Poisson.Rd index 552e002aa..202571c3a 100644 --- a/man/Analyze_Poisson.Rd +++ b/man/Analyze_Poisson.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Analyze_Poisson.R +% Please edit documentation in R/Analyze_Scatter.R \name{Analyze_Poisson} \alias{Analyze_Poisson} \title{Poisson Analysis - Site Residuals} diff --git a/man/Visualize_Poisson.Rd b/man/Visualize_Poisson.Rd deleted file mode 100644 index 371c2b89b..000000000 --- a/man/Visualize_Poisson.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Visualize_Poisson.R -\name{Visualize_Poisson} -\alias{Visualize_Poisson} -\title{Site-level visualization of site-level Poisson Model results} -\usage{ -Visualize_Poisson(dfFlagged, dfBounds = NULL, strUnit = "days") -} -\arguments{ -\item{dfFlagged}{analyze_poisson results with flags added.} - -\item{dfBounds}{data.frame giving prediction bounds for range of dfFlagged} - -\item{strUnit}{exposure time unit. Defaults to "days".} -} -\value{ -site level plot object -} -\description{ -Site-level visualization of site-level Poisson Model results -} -\examples{ -dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count', strExposureCol = "Exposure" ) -dfAnalyzed <- Analyze_Poisson( dfTransformed) -dfFlagged <- Flag( dfAnalyzed , strColumn = 'Residuals', vThreshold =c(-5,5)) - -} diff --git a/man/Visualize_Scatter.Rd b/man/Visualize_Scatter.Rd new file mode 100644 index 000000000..32444e61e --- /dev/null +++ b/man/Visualize_Scatter.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualize_Scatter.R +\name{Visualize_Scatter} +\alias{Visualize_Scatter} +\title{Site-level visualization of site-level results using a Poisson or Wilcoxon model.} +\usage{ +Visualize_Scatter(dfFlagged, dfBounds = NULL, strUnit = "days") +} +\arguments{ +\item{dfFlagged}{analyze_poisson results with flags added.} + +\item{dfBounds}{data.frame giving prediction bounds for range of dfFlagged.} + +\item{strUnit}{exposure time unit. Defaults to "days".} +} +\value{ +site level plot object +} +\description{ +Site-level visualization of site-level results using a Poisson or Wilcoxon model. +} +\examples{ +dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +SafetyAE <- AE_Assess( dfInput , bDataList=TRUE) +dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) +Visualize_Scatter(SafetyAE$dfFlagged, dfBounds) + +dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) +SafetyAE <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") +Visualize_Scatter(SafetyAE$dfFlagged) + +} diff --git a/tests/testthat/test-Visualize_Poisson.R b/tests/testthat/test-Visualize_Poisson.R deleted file mode 100644 index d64cea971..000000000 --- a/tests/testthat/test-Visualize_Poisson.R +++ /dev/null @@ -1,7 +0,0 @@ -test_that("Output is produced", { - dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) - SafetyAE <- AE_Assess( dfInput , bDataList=TRUE, strMethod = "wilcoxon") - dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) - - expect_silent(Visualize_Poisson(SafetyAE$dfFlagged, dfBounds)) -}) diff --git a/tests/testthat/test-Visualize_Scatter.R b/tests/testthat/test-Visualize_Scatter.R new file mode 100644 index 000000000..772380a7a --- /dev/null +++ b/tests/testthat/test-Visualize_Scatter.R @@ -0,0 +1,16 @@ +test_that("Output is produced", { + + # poisson model + dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) + SafetyAE <- AE_Assess( dfInput , bDataList=TRUE, strMethod = "poisson") + dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) + expect_silent(Visualize_Scatter(SafetyAE$dfFlagged, dfBounds)) + + + # wilcoxon model + dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) + SafetyAE <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") + Visualize_Scatter(SafetyAE$dfFlagged) + expect_silent(Visualize_Scatter(SafetyAE$dfFlagged)) + +}) From fffe90cc9cdcb866b66f280ba9b0667bcb128db2 Mon Sep 17 00:00:00 2001 From: Doug Sanders Date: Tue, 8 Mar 2022 11:14:25 -0800 Subject: [PATCH 47/60] implemented document changes and corrections per comment --- R/Consent_Assess.R | 2 +- R/IE_Assess.R | 4 ++-- man/Consent_Assess.Rd | 2 +- man/IE_Assess.Rd | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/Consent_Assess.R b/R/Consent_Assess.R index bedd5f6f5..2c5a92bb0 100644 --- a/R/Consent_Assess.R +++ b/R/Consent_Assess.R @@ -16,7 +16,7 @@ #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. #' -#' @section Assessment methodology: +#' @section Statistical Assumptions: #' #' This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or #' Consent date later in time than the Randomization Date. 'N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites diff --git a/R/IE_Assess.R b/R/IE_Assess.R index e5c162670..3d8335241 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -17,8 +17,8 @@ #' - \code{\link{Flag}} creates `dfFlagged`. #' - \code{\link{Summarize}} creates `dfSummary`. #' -#' @section Assessment methodology: -#' INCORRECT, CUT AND PASTE - NEED To UPDATE +#' @section Statistical Assumptions: +#' #' This Assessment finds any sites where one or more subjects which have Inclusion / Exclusion data that is either missing or has inconsistent data recorded for #' inclusion / exclusion data. N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites #' With N greater than user specified `nThreshold` will be flagged. diff --git a/man/Consent_Assess.Rd b/man/Consent_Assess.Rd index 6cb01e75d..4efce5733 100644 --- a/man/Consent_Assess.Rd +++ b/man/Consent_Assess.Rd @@ -42,7 +42,7 @@ The Assessment } } -\section{Assessment methodology}{ +\section{Statistical Assumptions}{ This Assessment finds any sites where one or more subjects meets any of the following citeria: No Consent, Missing Consent, Missing Randomization Date, or diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index d5e356f81..639cb3787 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -42,9 +42,9 @@ The Assessment } } -\section{Assessment methodology}{ +\section{Statistical Assumptions}{ + -INCORRECT, CUT AND PASTE - NEED To UPDATE This Assessment finds any sites where one or more subjects which have Inclusion / Exclusion data that is either missing or has inconsistent data recorded for inclusion / exclusion data. N' in the summary represents the number of subjects in a study that meet one or more criteria. Sites With N greater than user specified \code{nThreshold} will be flagged. From ef8e83f3866802dd74c58de1fdb40a013d93b622 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 8 Mar 2022 14:59:46 -0500 Subject: [PATCH 48/60] update example and clear note --- R/Summarize.R | 6 +++--- R/Visualize_Scatter.R | 5 ++--- man/Visualize_Scatter.Rd | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/R/Summarize.R b/R/Summarize.R index 8464b370e..56daad9e5 100644 --- a/R/Summarize.R +++ b/R/Summarize.R @@ -3,10 +3,10 @@ #' Create a concise summary of assessment results that is easy to aggregate across assessments #' #' @details -#' -#' @section Data Specification: -#' +#' #' \code{Summarize} supports the input data (`dfFlagged`) from the \code{Flag} function. +#' +#' @section Data Specification: #' #' (`dfFlagged`) has the following required columns: #' - `SiteID` - Site ID diff --git a/R/Visualize_Scatter.R b/R/Visualize_Scatter.R index b589c9fa7..bac158f61 100644 --- a/R/Visualize_Scatter.R +++ b/R/Visualize_Scatter.R @@ -12,9 +12,8 @@ #'dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) #'Visualize_Scatter(SafetyAE$dfFlagged, dfBounds) #' -#'dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -#'SafetyAE <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") -#'Visualize_Scatter(SafetyAE$dfFlagged) +#'SafetyAE_wilk <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") +#'Visualize_Scatter(SafetyAE_wilk$dfFlagged) #' #' @import ggplot2 #' diff --git a/man/Visualize_Scatter.Rd b/man/Visualize_Scatter.Rd index 32444e61e..630549641 100644 --- a/man/Visualize_Scatter.Rd +++ b/man/Visualize_Scatter.Rd @@ -25,8 +25,7 @@ SafetyAE <- AE_Assess( dfInput , bDataList=TRUE) dfBounds <- Analyze_Poisson_PredictBounds(SafetyAE$dfTransformed, c(-5,5)) Visualize_Scatter(SafetyAE$dfFlagged, dfBounds) -dfInput <- AE_Map_Adam( safetyData::adam_adsl, safetyData::adam_adae ) -SafetyAE <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") -Visualize_Scatter(SafetyAE$dfFlagged) +SafetyAE_wilk <- AE_Assess( dfInput, bDataList = TRUE, strMethod="wilcoxon") +Visualize_Scatter(SafetyAE_wilk$dfFlagged) } From 526f34b4374b9eb251086215359381210bd8ed71 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Tue, 8 Mar 2022 15:00:07 -0500 Subject: [PATCH 49/60] update docs --- man/Summarize.Rd | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/man/Summarize.Rd b/man/Summarize.Rd index 44096def2..8bbfd5d2e 100644 --- a/man/Summarize.Rd +++ b/man/Summarize.Rd @@ -22,13 +22,11 @@ Simplified finding data frame with columns: Assessment, Label, SiteID, N, Pvalue Create a concise summary of assessment results that is easy to aggregate across assessments } \details{ - +\code{Summarize} supports the input data (\code{dfFlagged}) from the \code{Flag} function. } \section{Data Specification}{ -\code{Summarize} supports the input data (\code{dfFlagged}) from the \code{Flag} function. - (\code{dfFlagged}) has the following required columns: \itemize{ \item \code{SiteID} - Site ID From 73caa5e8bd04af7d1204fb13f839607c64ddfc56 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Tue, 8 Mar 2022 22:35:47 +0000 Subject: [PATCH 50/60] first draft for Visualize_Count() --- NAMESPACE | 2 + R/Consent_Map_Raw.R | 46 ++++++------ R/IE_Assess.R | 1 - R/IE_Map_Raw.R | 3 +- R/Visualize_Count.R | 46 ++++++++++++ man/Consent_Map_Raw.Rd | 4 +- man/Visualize_Count.Rd | 26 +++++++ tests/testthat/test-Visualize_Count.R | 3 + tests/testthat/test_IE_Map_Raw.R | 102 +++++++++++++------------- 9 files changed, 154 insertions(+), 79 deletions(-) create mode 100644 R/Visualize_Count.R create mode 100644 man/Visualize_Count.Rd create mode 100644 tests/testthat/test-Visualize_Count.R diff --git a/NAMESPACE b/NAMESPACE index d1103eab4..90ba70b63 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,6 +19,7 @@ export(PD_Assess) export(PD_Map_Raw) export(Summarize) export(Transform_EventCount) +export(Visualize_Count) export(Visualize_Poisson) import(dplyr) import(ggplot2) @@ -37,5 +38,6 @@ importFrom(stats,median) importFrom(stats,offset) importFrom(stats,pnorm) importFrom(stats,poisson) +importFrom(stats,reorder) importFrom(stats,wilcox.test) importFrom(tidyr,unnest) diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index 29966e114..4a4002b00 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -1,11 +1,11 @@ #' Consent Assessment Mapping from Raw Data- Make Input Data -#' +#' #' Convert from raw data format to needed input format for \code{\link{Consent_Assess}} -#' +#' #' @details -#' -#' This function uses raw Consent and RDSL data to create the required input for \code{\link{Consent_Assess}}. -#' +#' +#' This function uses raw Consent and RDSL data to create the required input for \code{\link{Consent_Assess}}. +#' #' @section Data Specification: #' #' @@ -14,7 +14,7 @@ #' - `SUBJID` - Unique subject ID #' - `CONSCAT_STD` - Type of Consent_Coded value #' - `CONSYN` - Did the subject give consent? Yes / No. -#' - `CONSDAT` - If yes, provide date consent signed +#' - `CONSDAT` - If yes, provide date consent signed #' - `dfRDSL` #' - `SubjectID` - Unique subject ID #' - `SiteID` - Site ID @@ -23,20 +23,20 @@ #' @param dfConsent consent data frame with columns: SUBJID, CONSCAT_STD , CONSYN , CONSDAT. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID RandDate. #' @param strConsentReason default = "mainconsent", filters on CONSCAT_STD of dfConsent, if NULL no filtering is done. -#' +#' #' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count. -#' +#' #' @import dplyr -#' +#' #' @examples #' #' input <- Consent_Map_Raw( -#' dfConsent = clindata::raw_consent, -#' dfRDSL = clindata::rawplus_rdsl, +#' dfConsent = clindata::raw_consent, +#' dfRDSL = clindata::rawplus_rdsl, #' strConsentReason = NULL #' ) -#' -#' @export +#' +#' @export Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent"){ stopifnot( @@ -54,30 +54,30 @@ Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent") ) } - + dfRDSLSiteIDNACount <- sum(is.na(dfRDSL[['SiteID']])) if(dfRDSLSiteIDNACount>0){ warning(paste0("Dropped ",dfRDSLSiteIDNACount," record(s) from dfRDSL where SiteID is NA.")) dfRDSL <- dfRDSL %>% filter(!is.na(.data[['SiteID']])) } - - + + dfConsent<- dfConsent %>% select(.data$SUBJID, .data$CONSCAT_STD , .data$CONSYN , .data$CONSDAT)%>% rename(SubjectID = .data$SUBJID) - + missIE <- anti_join( dfConsent, dfRDSL, by="SubjectID") if( nrow(missIE) > 0 ) warning("Not all SubjectID in dfConsent found in dfRDSL") - + dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID, .data$RandDate)%>% inner_join(dfConsent, by='SubjectID') - + if(!is.null(strConsentReason)){ dfInput <- dfInput %>% filter(tolower(.data$CONSCAT_STD) == tolower(strConsentReason)) - stopifnot("supplied strConsentReason not found in data" = nrow(dfInput) != 0 ) + stopifnot("supplied strConsentReason not found in data" = nrow(dfInput) != 0 ) } - + dfInput <- dfInput %>% mutate(flag_noconsent=.data$CONSYN=="No") %>% mutate(flag_missing_consent = is.na(.data$CONSDAT))%>% @@ -85,7 +85,7 @@ Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent") mutate(flag_date_compare = .data$CONSDAT >= .data$RandDate ) %>% mutate(any_flag=.data$flag_noconsent | .data$flag_missing_consent | .data$flag_missing_rand | .data$flag_date_compare) %>% mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) %>% - select(.data$SubjectID, .data$SiteID, .data$Count) + select(.data$SubjectID, .data$SiteID, .data$Count) return(dfInput) -} \ No newline at end of file +} diff --git a/R/IE_Assess.R b/R/IE_Assess.R index b84702733..269edb7e2 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -1,5 +1,4 @@ #' Inclusion/Exclusion Assessment - #' #' @details #' diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 9d9a9e81e..53229552f 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -78,7 +78,6 @@ IE_Map_Raw <- function( )%>% mutate(Count = .data$Invalid + .data$Missing) %>% rename(SubjectID = .data$SUBJID) %>% - select(.data$SubjectID, .data$Count) %>% ungroup() missIE <- anti_join( dfIE_Subj, dfRDSL, by="SubjectID") @@ -88,7 +87,7 @@ IE_Map_Raw <- function( dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID)%>% inner_join(dfIE_Subj, by="SubjectID") %>% - select(.data$SubjectID, .data$SiteID, .data$Count) + select(.data$SubjectID, .data$SiteID, .data$Total, .data$Valid, .data$Invalid, .data$Missing, .data$Count) #Throw warning if a an ID in IE isn't found in RDSL diff --git a/R/Visualize_Count.R b/R/Visualize_Count.R new file mode 100644 index 000000000..48f79b427 --- /dev/null +++ b/R/Visualize_Count.R @@ -0,0 +1,46 @@ +#' Site-level visualization of site-level Inclusion/Exclusion results +#' +#' @param dfInput Map results from IE or Consent assessments. +#' @param strTitle Title of plot. NULL by default. +#' +#' @return site level plot object +#' +#' @examples +#' dfInput <- IE_Map_Raw(clindata::raw_ie_all, +#' clindata::rawplus_rdsl, +#' strCategoryCol = "IECAT_STD", +#' strResultCol = "IEORRES") +#' +#' @import ggplot2 +#' @importFrom stats reorder +#' +#' @export +Visualize_Count <- function(dfInput, strTitle = NULL) { + +dfPlot <- dfInput %>% + group_by(.data$SiteID) %>% + summarize(SiteID = unique(.data$SiteID), + N = sum(.data$Total), + Valid = sum(.data$Valid), + Invalid = sum(.data$Invalid), + Missing = sum(.data$Missing), + Count = sum(.data$Count)) + +p <- ggplot(data = dfPlot, + aes(x = reorder(.data$SiteID, -.data$N)) + ) + + geom_bar(aes(y = .data$N), stat = "identity", color = "black", fill = "white") + + geom_bar(aes(y = .data$Invalid), stat = "identity", fill = "red") + + ggtitle(strTitle) + + labs( + x = "Site ID", + y = "Inclusion/Exclusion Issues" + ) + + theme( + panel.grid.major.x = element_blank(), + axis.text.x = element_text(angle=90, vjust = 0.5), + legend.position="none" + ) + +return(p) +} diff --git a/man/Consent_Map_Raw.Rd b/man/Consent_Map_Raw.Rd index df42be12b..8a7fd9278 100644 --- a/man/Consent_Map_Raw.Rd +++ b/man/Consent_Map_Raw.Rd @@ -46,8 +46,8 @@ The following columns are required: \examples{ input <- Consent_Map_Raw( - dfConsent = clindata::raw_consent, - dfRDSL = clindata::rawplus_rdsl, + dfConsent = clindata::raw_consent, + dfRDSL = clindata::rawplus_rdsl, strConsentReason = NULL ) diff --git a/man/Visualize_Count.Rd b/man/Visualize_Count.Rd new file mode 100644 index 000000000..beca48607 --- /dev/null +++ b/man/Visualize_Count.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualize_Count.R +\name{Visualize_Count} +\alias{Visualize_Count} +\title{Site-level visualization of site-level Inclusion/Exclusion results} +\usage{ +Visualize_Count(dfInput, strTitle = NULL) +} +\arguments{ +\item{dfInput}{Map results from IE or Consent assessments.} + +\item{strTitle}{Title of plot. NULL by default.} +} +\value{ +site level plot object +} +\description{ +Site-level visualization of site-level Inclusion/Exclusion results +} +\examples{ +dfInput <- IE_Map_Raw(clindata::raw_ie_all, + clindata::rawplus_rdsl, + strCategoryCol = "IECAT_STD", + strResultCol = "IEORRES") + +} diff --git a/tests/testthat/test-Visualize_Count.R b/tests/testthat/test-Visualize_Count.R new file mode 100644 index 000000000..8849056e2 --- /dev/null +++ b/tests/testthat/test-Visualize_Count.R @@ -0,0 +1,3 @@ +test_that("multiplication works", { + expect_equal(2 * 2, 4) +}) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 1013e49e9..a1479316f 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -4,9 +4,9 @@ test_that("output created as expected and has correct structure",{ ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_true(is.data.frame(ie_input)) - expect_equal( - names(ie_input), - c("SubjectID","SiteID","Count")) + # expect_equal( + # names(ie_input), + # c("SubjectID","SiteID","Count")) }) test_that("incorrect inputs throw errors",{ @@ -128,54 +128,54 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ ) }) -test_that("output is correct given clindata example input",{ - -dfIE <- clindata::raw_ie_all -dfIE$SUBJID <- as.character(dfIE$SUBJID) - -dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, - "0496", "X055X", - "0539", "X128X", - "1314", "X169X", - "1218", "X126X" ) - - - -dfInput <- tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - "0496", "X055X", 15L, - "0539", "X128X", 15L, - "1314", "X169X", 14L, - "1218", "X126X", 14L -) - -expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) - - - - - -dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, - 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, - 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) - -dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) - -dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, - 1, 1, 2L, - 2, 1, 2L, - 4, 3, 1L ) - -expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) - -}) +# test_that("output is correct given clindata example input",{ +# +# dfIE <- clindata::raw_ie_all +# dfIE$SUBJID <- as.character(dfIE$SUBJID) +# +# dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, +# "0496", "X055X", +# "0539", "X128X", +# "1314", "X169X", +# "1218", "X126X" ) +# +# +# +# dfInput <- tibble::tribble( +# ~SubjectID, ~SiteID, ~Count, +# "0496", "X055X", 15L, +# "0539", "X128X", 15L, +# "1314", "X169X", 14L, +# "1218", "X126X", 14L +# ) +# +# expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) +# +# +# +# +# +# dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, +# 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, +# 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, +# 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, +# 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, +# 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, +# 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, +# 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, +# 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, +# 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) +# +# dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) +# +# dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, +# 1, 1, 2L, +# 2, 1, 2L, +# 4, 3, 1L ) +# +# expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) +# +# }) test_that("NA values are handled correctly", { From 46f836ff346fd5051b77c9576192681235d6c810 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Wed, 9 Mar 2022 09:49:12 -0500 Subject: [PATCH 51/60] refactor visualize_count --- R/Visualize_Count.R | 64 +++++++++++++++++++++++------------------- man/Visualize_Count.Rd | 28 ++++++++++++++---- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/R/Visualize_Count.R b/R/Visualize_Count.R index 48f79b427..24d6724be 100644 --- a/R/Visualize_Count.R +++ b/R/Visualize_Count.R @@ -6,41 +6,47 @@ #' @return site level plot object #' #' @examples -#' dfInput <- IE_Map_Raw(clindata::raw_ie_all, -#' clindata::rawplus_rdsl, -#' strCategoryCol = "IECAT_STD", -#' strResultCol = "IEORRES") +#' ie_input <- IE_Map_Raw( +#' clindata::raw_ie_all , +#' clindata::rawplus_rdsl, +#' strCategoryCol = 'IECAT_STD', +#' strResultCol = 'IEORRES' +#' ) +#' ie_assess <- IE_Assess(ie_input, bDataList=TRUE) +#' Visualize_Count(ie_assess$dfAnalyzed) +#' +#' consent_input <- Consent_Map_Raw( +#' dfConsent = clindata::raw_consent, +#' dfRDSL = clindata::rawplus_rdsl, +#' strConsentReason = NULL +#' ) +#' +#' consent_assess<-Consent_Assess(dfInput, bDataList=TRUE) +#' Visualize_Count(consent_assess$dfAnalyzed) #' #' @import ggplot2 #' @importFrom stats reorder #' #' @export -Visualize_Count <- function(dfInput, strTitle = NULL) { -dfPlot <- dfInput %>% - group_by(.data$SiteID) %>% - summarize(SiteID = unique(.data$SiteID), - N = sum(.data$Total), - Valid = sum(.data$Valid), - Invalid = sum(.data$Invalid), - Missing = sum(.data$Missing), - Count = sum(.data$Count)) +Visualize_Count <- function(dfAnalyzed, strTotalCol="N", strCountCol="TotalCount", strFlagCol="Flag", strTitle="") { -p <- ggplot(data = dfPlot, - aes(x = reorder(.data$SiteID, -.data$N)) - ) + - geom_bar(aes(y = .data$N), stat = "identity", color = "black", fill = "white") + - geom_bar(aes(y = .data$Invalid), stat = "identity", fill = "red") + - ggtitle(strTitle) + - labs( - x = "Site ID", - y = "Inclusion/Exclusion Issues" - ) + - theme( - panel.grid.major.x = element_blank(), - axis.text.x = element_text(angle=90, vjust = 0.5), - legend.position="none" - ) +p <- ggplot( + data = dfAnalyzed, + aes(x = reorder(.data$SiteID, -.data$N)) + ) + + geom_bar(aes(y = .data[[strTotalCol]]), stat = "identity", color = "black", fill = "white") + + geom_bar(aes(y = .data[[strCountCol]]), stat = "identity", fill = "red") + + ggtitle(strTitle) + + labs( + x = "Site ID", + y = "Event Count" + ) + + theme( + panel.grid.major.x = element_blank(), + axis.text.x = element_text(angle=90, vjust = 0.5), + legend.position="none" + ) -return(p) + return(p) } diff --git a/man/Visualize_Count.Rd b/man/Visualize_Count.Rd index beca48607..9dfeed59a 100644 --- a/man/Visualize_Count.Rd +++ b/man/Visualize_Count.Rd @@ -4,7 +4,12 @@ \alias{Visualize_Count} \title{Site-level visualization of site-level Inclusion/Exclusion results} \usage{ -Visualize_Count(dfInput, strTitle = NULL) +Visualize_Count( + dfAnalyzed, + strTotalCol = "N", + strCountCol = "TotalCount", + strFlagCol = "Flag" +) } \arguments{ \item{dfInput}{Map results from IE or Consent assessments.} @@ -18,9 +23,22 @@ site level plot object Site-level visualization of site-level Inclusion/Exclusion results } \examples{ -dfInput <- IE_Map_Raw(clindata::raw_ie_all, - clindata::rawplus_rdsl, - strCategoryCol = "IECAT_STD", - strResultCol = "IEORRES") +ie_input <- IE_Map_Raw( + clindata::raw_ie_all , + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' +) +ie_assess <- IE_Assess(ie_input, bDataList=TRUE) +VisualizeCount(ie_assess$dfAnalyzed) + +consent_input <- Consent_Map_Raw( + dfConsent = clindata::raw_consent, + dfRDSL = clindata::rawplus_rdsl, + strConsentReason = NULL +) + +consent_assess<-Consent_Assess(dfInput, bDataList=TRUE) +VisualizeCount(consent_assess$dfAnalyzed) } From 4e345aa8c8c18f4e4c3546dedc4e4381bf34fe2c Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Wed, 9 Mar 2022 10:04:46 -0500 Subject: [PATCH 52/60] update ie example code. fix #260 --- R/IE_Assess.R | 23 ++++++++++------------- R/IE_Map_Raw.R | 10 ++++++++-- R/Visualize_Count.R | 2 ++ man/IE_Assess.Rd | 23 ++++++++++------------- man/IE_Map_Raw.Rd | 10 ++++++++-- man/Visualize_Count.Rd | 13 ++++++++----- 6 files changed, 46 insertions(+), 35 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index 269edb7e2..05a1581f5 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -25,19 +25,16 @@ #' #' @examples #' -#' dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, -#' "0142", "X194X", 9, -#' "0308", "X159X", 9, -#' "0776", "X194X", 8, -#' "1032", "X033X", 9 -#' ) -#' -#' ie_summary <- IE_Assess(dfInput) -#' -#' ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, -#' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') -#' -#' ie_summary2 <- IE_Assess(ie_input) +#' dfInput <- IE_Map_Raw( +#' clindata::raw_ie_all , +#' clindata::rawplus_rdsl, +#' strCategoryCol = 'IECAT_STD', +#' vCategoryValues= c("EXCL","INCL"), +#' strResultCol = 'IEORRES', +#' vExpectedResultValues=c(0,1) +#') +#' +#' ie_summary <- IE_Assess(ie_input) #' #' #' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 53229552f..9d779778b 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -29,8 +29,14 @@ #' #' @examples #' -#' dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, -#' strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +#' dfInput <- IE_Map_Raw( +#' clindata::raw_ie_all , +#' clindata::rawplus_rdsl, +#' strCategoryCol = 'IECAT_STD', +#' vCategoryValues= c("EXCL","INCL"), +#' strResultCol = 'IEORRES', +#' vExpectedResultValues=c(0,1) +#') #' #' @import dplyr #' diff --git a/R/Visualize_Count.R b/R/Visualize_Count.R index 24d6724be..89d49e52c 100644 --- a/R/Visualize_Count.R +++ b/R/Visualize_Count.R @@ -10,8 +10,10 @@ #' clindata::raw_ie_all , #' clindata::rawplus_rdsl, #' strCategoryCol = 'IECAT_STD', +#' vCategoryResults=c("EXCL","INCL"), #' strResultCol = 'IEORRES' #' ) +#' #' ie_assess <- IE_Assess(ie_input, bDataList=TRUE) #' Visualize_Count(ie_assess$dfAnalyzed) #' diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 09a7d2106..4e73260d2 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -44,19 +44,16 @@ The Assessment \examples{ - dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, - "0142", "X194X", 9, - "0308", "X159X", 9, - "0776", "X194X", 8, - "1032", "X033X", 9 - ) - - ie_summary <- IE_Assess(dfInput) - - ie_input <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') - - ie_summary2 <- IE_Assess(ie_input) +dfInput <- IE_Map_Raw( + clindata::raw_ie_all , + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + vCategoryValues= c("EXCL","INCL"), + strResultCol = 'IEORRES', + vExpectedResultValues=c(0,1) +) + + ie_summary <- IE_Assess(ie_input) } diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 7181a83da..4ead29251 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -56,7 +56,13 @@ The following columns are required: \examples{ -dfInput <- IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES') +dfInput <- IE_Map_Raw( + clindata::raw_ie_all , + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + vCategoryValues= c("EXCL","INCL"), + strResultCol = 'IEORRES', + vExpectedResultValues=c(0,1) +) } diff --git a/man/Visualize_Count.Rd b/man/Visualize_Count.Rd index 9dfeed59a..409def193 100644 --- a/man/Visualize_Count.Rd +++ b/man/Visualize_Count.Rd @@ -8,13 +8,14 @@ Visualize_Count( dfAnalyzed, strTotalCol = "N", strCountCol = "TotalCount", - strFlagCol = "Flag" + strFlagCol = "Flag", + strTitle = "" ) } \arguments{ -\item{dfInput}{Map results from IE or Consent assessments.} - \item{strTitle}{Title of plot. NULL by default.} + +\item{dfInput}{Map results from IE or Consent assessments.} } \value{ site level plot object @@ -27,10 +28,12 @@ ie_input <- IE_Map_Raw( clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', + vCategoryResults=c("EXCL","INCL"), strResultCol = 'IEORRES' ) + ie_assess <- IE_Assess(ie_input, bDataList=TRUE) -VisualizeCount(ie_assess$dfAnalyzed) +Visualize_Count(ie_assess$dfAnalyzed) consent_input <- Consent_Map_Raw( dfConsent = clindata::raw_consent, @@ -39,6 +42,6 @@ consent_input <- Consent_Map_Raw( ) consent_assess<-Consent_Assess(dfInput, bDataList=TRUE) -VisualizeCount(consent_assess$dfAnalyzed) +Visualize_Count(consent_assess$dfAnalyzed) } From e8d6994a55ae099d2359b2a0e15c38b1c4cbebad Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Wed, 9 Mar 2022 15:17:35 +0000 Subject: [PATCH 53/60] closes #226 - qc updates for Analyze_Fisher() --- R/Analyze_Fisher.R | 21 +++++++++++++-------- man/Analyze_Fisher.Rd | 8 +++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/R/Analyze_Fisher.R b/R/Analyze_Fisher.R index 37ceca2a6..72b06abdb 100644 --- a/R/Analyze_Fisher.R +++ b/R/Analyze_Fisher.R @@ -2,7 +2,7 @@ #' #' Creates Analysis results data for count data using the Fisher's exact test #' -#' @details +#' @details #' #' Analyzes count data using the Fisher's exact test #' @@ -12,16 +12,16 @@ #' #' @section Data Specification: #' -#' The input data (` dfTransformed`) for the Analyze_Fisher is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +#' The input data (`dfTransformed`) for Analyze_Fisher is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: #' - `SiteID` - Site ID #' - `N` - Total number of participants at site -#' - `Count` - Total number of participants at site with event of interest +#' - `TotalCount` - Total number of participants at site with event of interest #' #' #' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}} -#' @param strOutcome required, name of column in dfTransformed dataset to perform Fisher test on +#' @param strOutcome required, name of column in dfTransformed dataset to perform Fisher test on. Default is "TotalCount". #' -#' @importFrom stats fisher.test as.formula +#' @importFrom stats fisher.test #' @importFrom purrr map #' @importFrom broom glance #' @importFrom tidyr unnest @@ -33,13 +33,18 @@ #' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) #' dfAnalyzed <- Analyze_Fisher( dfTransformed ) #' +#' @import dplyr +#' #' @export Analyze_Fisher <- function( dfTransformed , strOutcome = "TotalCount") { stopifnot( - is.data.frame(dfTransformed), - all(c("SiteID", "N", strOutcome) %in% names(dfTransformed)) + "dfTransformed is not a data.frame" = is.data.frame(dfTransformed), + "One or more of these columns: SiteID, N, or the value in strOutcome not found in dfTransformed" = all(c("SiteID", "N", strOutcome) %in% names(dfTransformed)), + "NA value(s) found in SiteID" = all(!is.na(dfTransformed[["SiteID"]])), + "strOutcome must be length 1" = length(strOutcome) == 1, + "strOutcome is not character" = is.character(strOutcome) ) fisher_model<- function(site){ @@ -58,7 +63,7 @@ Analyze_Fisher <- function( dfTransformed , strOutcome = "TotalCount") { dfAnalyzed <- dfTransformed %>% mutate(model = map(.data$SiteID, fisher_model)) %>% mutate(summary = map(.data$model, broom::glance)) %>% - unnest(summary) %>% + tidyr::unnest(summary) %>% rename( Estimate = .data$estimate, PValue = .data[['p.value']] diff --git a/man/Analyze_Fisher.Rd b/man/Analyze_Fisher.Rd index 4272435f0..a22b46d79 100644 --- a/man/Analyze_Fisher.Rd +++ b/man/Analyze_Fisher.Rd @@ -9,7 +9,7 @@ Analyze_Fisher(dfTransformed, strOutcome = "TotalCount") \arguments{ \item{dfTransformed}{data.frame in format produced by \code{\link{Transform_EventCount}}} -\item{strOutcome}{required, name of column in dfTransformed dataset to perform Fisher test on} +\item{strOutcome}{required, name of column in dfTransformed dataset to perform Fisher test on. Default is "TotalCount".} } \value{ data.frame with one row per site, columns: SiteID, TotalCount, TotalCount_Other, N, N_Other, Prop, Prop_Other, Estimate, PValue @@ -18,8 +18,6 @@ data.frame with one row per site, columns: SiteID, TotalCount, TotalCount_Other, Creates Analysis results data for count data using the Fisher's exact test } \details{ -@details - Analyzes count data using the Fisher's exact test } \section{Statistical Methods}{ @@ -31,11 +29,11 @@ TODO Coming soon ... \section{Data Specification}{ -The input data (\code{ dfTransformed}) for the Analyze_Fisher is typically created using \code{\link{Transform_EventCount}} and should be one record per Site with columns for: +The input data (\code{dfTransformed}) for Analyze_Fisher is typically created using \code{\link{Transform_EventCount}} and should be one record per site with required columns for: \itemize{ \item \code{SiteID} - Site ID \item \code{N} - Total number of participants at site -\item \code{Count} - Total number of participants at site with event of interest +\item \code{TotalCount} - Total number of participants at site with event of interest } } From f4cb3055237fec568851ca4861a1ed627b897ccf Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Wed, 9 Mar 2022 15:38:24 +0000 Subject: [PATCH 54/60] move import --- R/Analyze_Fisher.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/Analyze_Fisher.R b/R/Analyze_Fisher.R index 72b06abdb..fdaa41aaf 100644 --- a/R/Analyze_Fisher.R +++ b/R/Analyze_Fisher.R @@ -21,6 +21,7 @@ #' @param dfTransformed data.frame in format produced by \code{\link{Transform_EventCount}} #' @param strOutcome required, name of column in dfTransformed dataset to perform Fisher test on. Default is "TotalCount". #' +#' @import dplyr #' @importFrom stats fisher.test #' @importFrom purrr map #' @importFrom broom glance @@ -33,8 +34,6 @@ #' dfTransformed <- Transform_EventCount( dfInput, strCountCol = 'Count' ) #' dfAnalyzed <- Analyze_Fisher( dfTransformed ) #' -#' @import dplyr -#' #' @export Analyze_Fisher <- function( dfTransformed , strOutcome = "TotalCount") { From e78354176fca52197396c24f79aff898a0187ef9 Mon Sep 17 00:00:00 2001 From: Jeremy Wildfire Date: Wed, 9 Mar 2022 10:54:13 -0500 Subject: [PATCH 55/60] minor doc improvements --- R/Consent_Map_Raw.R | 8 ++++---- R/IE_Map_Raw.R | 6 +++--- man/Consent_Map_Raw.Rd | 2 +- man/IE_Map_Raw.Rd | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index 4a4002b00..ca0d83cb6 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -1,4 +1,4 @@ -#' Consent Assessment Mapping from Raw Data- Make Input Data +#' Consent Assessment Mapping from Raw Data #' #' Convert from raw data format to needed input format for \code{\link{Consent_Assess}} #' @@ -37,7 +37,7 @@ #' ) #' #' @export -Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent"){ +Consent_Map_Raw <- function( dfConsent, dfRDSL, strConsentReason = "mainconsent"){ stopifnot( "dfConsent dataset not found"=is.data.frame(dfConsent), @@ -84,8 +84,8 @@ Consent_Map_Raw <- function( dfConsent,dfRDSL, strConsentReason = "mainconsent") mutate(flag_missing_rand = is.na(.data$RandDate))%>% mutate(flag_date_compare = .data$CONSDAT >= .data$RandDate ) %>% mutate(any_flag=.data$flag_noconsent | .data$flag_missing_consent | .data$flag_missing_rand | .data$flag_date_compare) %>% - mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) %>% - select(.data$SubjectID, .data$SiteID, .data$Count) + mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) #%>% + #select(.data$SubjectID, .data$SiteID, .data$Count) return(dfInput) } diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 9d779778b..89c18d767 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -1,10 +1,10 @@ #' Inclusion/Exclusion Assessment Mapping from Raw Data- Make Input Data #' -#' Convert from raw data format to needed input format for Inclusion/Exclusion Assessment +#' Convert from raw data format to needed input format for Inclusion/Exclusion Assessment. #' #' @details #' -#' This function creates the required input for \code{\link{IE_Assess}}. +#' This function creates the required input for \code{\link{IE_Assess}}. #' #' @section Data Specification: #' @@ -25,7 +25,7 @@ #' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". #' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". #' -#' @return Data frame with one record per person data frame with columns: SubjectID, SiteID, Count +#' @return Data frame with one record per participant giving the number of inclusion/exclusion criteria the participant did not meet as expected. Expected columns: SubjectID, SiteID, Count #' #' @examples #' diff --git a/man/Consent_Map_Raw.Rd b/man/Consent_Map_Raw.Rd index 8a7fd9278..e69d1b109 100644 --- a/man/Consent_Map_Raw.Rd +++ b/man/Consent_Map_Raw.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/Consent_Map_Raw.R \name{Consent_Map_Raw} \alias{Consent_Map_Raw} -\title{Consent Assessment Mapping from Raw Data- Make Input Data} +\title{Consent Assessment Mapping from Raw Data} \usage{ Consent_Map_Raw(dfConsent, dfRDSL, strConsentReason = "mainconsent") } diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 4ead29251..23b4f2bbd 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -27,10 +27,10 @@ IE_Map_Raw( \item{vExpectedResultValues}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion".} } \value{ -Data frame with one record per person data frame with columns: SubjectID, SiteID, Count +Data frame with one record per participant giving the number of inclusion/exclusion criteria the participant did not meet as expected. Expected columns: SubjectID, SiteID, Count } \description{ -Convert from raw data format to needed input format for Inclusion/Exclusion Assessment +Convert from raw data format to needed input format for Inclusion/Exclusion Assessment. } \details{ This function creates the required input for \code{\link{IE_Assess}}. From 26e4814ab104df83d9bc3dc6eef70f357d90e507 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Wed, 9 Mar 2022 18:39:30 +0000 Subject: [PATCH 56/60] updates for Visualize_Count() --- R/IE_Assess.R | 6 +- R/IE_Map_Raw.R | 16 ++-- R/Visualize_Count.R | 32 +++++--- man/IE_Assess.Rd | 6 +- man/IE_Map_Raw.Rd | 8 +- man/Visualize_Count.Rd | 20 +++-- tests/testthat/test-Visualize_Count.R | 57 +++++++++++++- tests/testthat/test_Consent_Map_Raw.R | 67 +++++++++------- tests/testthat/test_IE_Map_Raw.R | 105 +++++++++++++------------- 9 files changed, 201 insertions(+), 116 deletions(-) diff --git a/R/IE_Assess.R b/R/IE_Assess.R index 05a1581f5..bccea96b5 100644 --- a/R/IE_Assess.R +++ b/R/IE_Assess.R @@ -26,15 +26,15 @@ #' @examples #' #' dfInput <- IE_Map_Raw( -#' clindata::raw_ie_all , +#' clindata::raw_ie_all , #' clindata::rawplus_rdsl, -#' strCategoryCol = 'IECAT_STD', +#' strCategoryCol = 'IECAT_STD', #' vCategoryValues= c("EXCL","INCL"), #' strResultCol = 'IEORRES', #' vExpectedResultValues=c(0,1) #') #' -#' ie_summary <- IE_Assess(ie_input) +#' ie_summary <- IE_Assess(dfInput) #' #' #' @return If `bDataList` is false (the default), the summary data frame (`dfSummary`) is returned. If `bDataList` is true, a list containing all data in the standard data pipeline (`dfInput`, `dfTransformed`, `dfAnalyzed`, `dfFlagged` and `dfSummary`) is returned. diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 89c18d767..41f25b0a1 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -1,10 +1,10 @@ #' Inclusion/Exclusion Assessment Mapping from Raw Data- Make Input Data #' -#' Convert from raw data format to needed input format for Inclusion/Exclusion Assessment. +#' Convert from raw data format to needed input format for Inclusion/Exclusion Assessment. #' #' @details #' -#' This function creates the required input for \code{\link{IE_Assess}}. +#' This function creates the required input for \code{\link{IE_Assess}}. #' #' @section Data Specification: #' @@ -21,18 +21,18 @@ #' @param dfIE ie dataset with columns SUBJID and values specified in strCategoryCol and strResultCol. #' @param dfRDSL Subject-level Raw Data (RDSL) required columns: SubjectID SiteID #' @param strCategoryCol Name ofcCriteria category column. default = 'IECAT' -#' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). +#' @param vCategoryValues Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). Category values must be in the same order as `vExpectedResultValues`. #' @param strResultCol Name of criteria Result column. Default = "IEORRES_STD". -#' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". +#' @param vExpectedResultValues Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". Values must be in the same order as `vCategoryValues`. #' #' @return Data frame with one record per participant giving the number of inclusion/exclusion criteria the participant did not meet as expected. Expected columns: SubjectID, SiteID, Count #' #' @examples #' #' dfInput <- IE_Map_Raw( -#' clindata::raw_ie_all , +#' clindata::raw_ie_all , #' clindata::rawplus_rdsl, -#' strCategoryCol = 'IECAT_STD', +#' strCategoryCol = 'IECAT_STD', #' vCategoryValues= c("EXCL","INCL"), #' strResultCol = 'IEORRES', #' vExpectedResultValues=c(0,1) @@ -66,9 +66,9 @@ IE_Map_Raw <- function( # filter records where SUBJID is missing and create basic flags dfIE_long <- dfIE %>% - filter(.data$SUBJID !="")%>% + filter(.data$SUBJID !="") %>% select(.data$SUBJID, .data[[strCategoryCol]], .data[[strResultCol]]) %>% - mutate(expected=ifelse(.data[[strCategoryCol]] ==vCategoryValues[1],vExpectedResultValues[1],vExpectedResultValues[2])) %>% + mutate(expected=ifelse(.data[[strCategoryCol]] == vCategoryValues[1], vExpectedResultValues[1],vExpectedResultValues[2])) %>% mutate(valid=.data[[strResultCol]]==.data$expected)%>% mutate(invalid=.data[[strResultCol]]!=.data$expected)%>% mutate(missing=!(.data[[strResultCol]] %in% vExpectedResultValues)) diff --git a/R/Visualize_Count.R b/R/Visualize_Count.R index 89d49e52c..c77e6ad6a 100644 --- a/R/Visualize_Count.R +++ b/R/Visualize_Count.R @@ -1,29 +1,32 @@ #' Site-level visualization of site-level Inclusion/Exclusion results #' -#' @param dfInput Map results from IE or Consent assessments. +#' @param dfAnalyzed Map results from IE or Consent assessments. +#' @param strTotalCol Column containing total of site-level participants. Default is "N" from \code{\link{Transform_EventCount}}. +#' @param strCountCol Column containing total number of site-level occurances. Default is "TotalCount" from \code{\link{Transform_EventCount}}. #' @param strTitle Title of plot. NULL by default. #' #' @return site level plot object #' #' @examples #' ie_input <- IE_Map_Raw( -#' clindata::raw_ie_all , +#' clindata::raw_ie_all , #' clindata::rawplus_rdsl, -#' strCategoryCol = 'IECAT_STD', -#' vCategoryResults=c("EXCL","INCL"), -#' strResultCol = 'IEORRES' -#' ) -#' +#' strCategoryCol = 'IECAT_STD', +#' vCategoryValues= c("EXCL","INCL"), +#' strResultCol = 'IEORRES', +#' vExpectedResultValues=c(0,1) +#') +#' #' ie_assess <- IE_Assess(ie_input, bDataList=TRUE) #' Visualize_Count(ie_assess$dfAnalyzed) -#' +#' #' consent_input <- Consent_Map_Raw( #' dfConsent = clindata::raw_consent, #' dfRDSL = clindata::rawplus_rdsl, #' strConsentReason = NULL #' ) -#' -#' consent_assess<-Consent_Assess(dfInput, bDataList=TRUE) +#' +#' consent_assess <- Consent_Assess(consent_input, bDataList=TRUE) #' Visualize_Count(consent_assess$dfAnalyzed) #' #' @import ggplot2 @@ -31,7 +34,14 @@ #' #' @export -Visualize_Count <- function(dfAnalyzed, strTotalCol="N", strCountCol="TotalCount", strFlagCol="Flag", strTitle="") { +Visualize_Count <- function(dfAnalyzed, strTotalCol="N", strCountCol="TotalCount", strTitle="") { + stopifnot( + "strTotalCol must be character" = is.character(strTotalCol), + "strTotalCol not found in dfAnalyzed" = strTotalCol %in% names(dfAnalyzed), + "strCountCol must be character" = is.character(strCountCol), + "strCountCol not found in dfAnalyzed" = strCountCol %in% names(dfAnalyzed), + "strTitle must be character" = is.character(strTitle) + ) p <- ggplot( data = dfAnalyzed, diff --git a/man/IE_Assess.Rd b/man/IE_Assess.Rd index 4e73260d2..0eaba2077 100644 --- a/man/IE_Assess.Rd +++ b/man/IE_Assess.Rd @@ -45,15 +45,15 @@ The Assessment \examples{ dfInput <- IE_Map_Raw( - clindata::raw_ie_all , + clindata::raw_ie_all , clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', vCategoryValues= c("EXCL","INCL"), strResultCol = 'IEORRES', vExpectedResultValues=c(0,1) ) - ie_summary <- IE_Assess(ie_input) +ie_summary <- IE_Assess(dfInput) } diff --git a/man/IE_Map_Raw.Rd b/man/IE_Map_Raw.Rd index 23b4f2bbd..704e7f59a 100644 --- a/man/IE_Map_Raw.Rd +++ b/man/IE_Map_Raw.Rd @@ -20,11 +20,11 @@ IE_Map_Raw( \item{strCategoryCol}{Name ofcCriteria category column. default = 'IECAT'} -\item{vCategoryValues}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion").} +\item{vCategoryValues}{Category values (of column in dfIE specified by strCategoryCol) Default = c("Exclusion","Inclusion"). Category values must be in the same order as \code{vExpectedResultValues}.} \item{strResultCol}{Name of criteria Result column. Default = "IEORRES_STD".} -\item{vExpectedResultValues}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion".} +\item{vExpectedResultValues}{Vector containing expected values for the inclusion/exclusion criteria stored in dfIE$IEORRES. Defaults to c(0,1) where 0 is expected when dfIE$IECAT == "Exclusion" and 1 is expected when dfIE$IECAT=="Inclusion". Values must be in the same order as \code{vCategoryValues}.} } \value{ Data frame with one record per participant giving the number of inclusion/exclusion criteria the participant did not meet as expected. Expected columns: SubjectID, SiteID, Count @@ -57,9 +57,9 @@ The following columns are required: \examples{ dfInput <- IE_Map_Raw( - clindata::raw_ie_all , + clindata::raw_ie_all , clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', + strCategoryCol = 'IECAT_STD', vCategoryValues= c("EXCL","INCL"), strResultCol = 'IEORRES', vExpectedResultValues=c(0,1) diff --git a/man/Visualize_Count.Rd b/man/Visualize_Count.Rd index 409def193..18790412e 100644 --- a/man/Visualize_Count.Rd +++ b/man/Visualize_Count.Rd @@ -8,14 +8,17 @@ Visualize_Count( dfAnalyzed, strTotalCol = "N", strCountCol = "TotalCount", - strFlagCol = "Flag", strTitle = "" ) } \arguments{ -\item{strTitle}{Title of plot. NULL by default.} +\item{dfAnalyzed}{Map results from IE or Consent assessments.} + +\item{strTotalCol}{Column containing total of site-level participants. Default is "N" from \code{\link{Transform_EventCount}}.} -\item{dfInput}{Map results from IE or Consent assessments.} +\item{strCountCol}{Column containing total number of site-level occurances. Default is "TotalCount" from \code{\link{Transform_EventCount}}.} + +\item{strTitle}{Title of plot. NULL by default.} } \value{ site level plot object @@ -25,11 +28,12 @@ Site-level visualization of site-level Inclusion/Exclusion results } \examples{ ie_input <- IE_Map_Raw( - clindata::raw_ie_all , + clindata::raw_ie_all , clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', - vCategoryResults=c("EXCL","INCL"), - strResultCol = 'IEORRES' + strCategoryCol = 'IECAT_STD', + vCategoryValues= c("EXCL","INCL"), + strResultCol = 'IEORRES', + vExpectedResultValues=c(0,1) ) ie_assess <- IE_Assess(ie_input, bDataList=TRUE) @@ -41,7 +45,7 @@ consent_input <- Consent_Map_Raw( strConsentReason = NULL ) -consent_assess<-Consent_Assess(dfInput, bDataList=TRUE) +consent_assess <- Consent_Assess(consent_input, bDataList=TRUE) Visualize_Count(consent_assess$dfAnalyzed) } diff --git a/tests/testthat/test-Visualize_Count.R b/tests/testthat/test-Visualize_Count.R index 8849056e2..a4ae220fc 100644 --- a/tests/testthat/test-Visualize_Count.R +++ b/tests/testthat/test-Visualize_Count.R @@ -1,3 +1,56 @@ -test_that("multiplication works", { - expect_equal(2 * 2, 4) +suppressWarnings( + +consent_input <- Consent_Map_Raw( + dfConsent = clindata::raw_consent, + dfRDSL = clindata::rawplus_rdsl, + strConsentReason = NULL +) + +) + +suppressWarnings( + +ie_input <- IE_Map_Raw( + clindata::raw_ie_all , + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + vCategoryValues= c("EXCL","INCL"), + strResultCol = 'IEORRES', + vExpectedResultValues=c(0,1) +) + +) + + +test_that("output is produced with consent data", { +consent_assess <- Consent_Assess(consent_input, bDataList=TRUE) + +expect_silent( + Visualize_Count(consent_assess$dfAnalyzed) +) }) + +test_that("output is produced with IE data", { + ie_assess <- IE_Assess(ie_input, bDataList=TRUE) + + expect_silent( + Visualize_Count(ie_assess$dfAnalyzed) + ) +}) + +test_that("incorrect inputs throw errors",{ + consent_assess <- Consent_Assess(consent_input, bDataList=TRUE) + ie_assess <- IE_Assess(ie_input, bDataList=TRUE) + + expect_error(Visualize_Count(list())) + expect_error(Visualize_Count("Hi")) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strTotalCol = "not here")) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strTotalCol = 1)) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strCountCol = "not here")) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strCountCol = 1)) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strFlagCol = "no")) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strFlagCol = 1)) + expect_error(Visualize_Count(consent_assess$dfAnalyzed, strTitle = list())) +}) + + diff --git a/tests/testthat/test_Consent_Map_Raw.R b/tests/testthat/test_Consent_Map_Raw.R index 26d511b09..92d4d7fe5 100644 --- a/tests/testthat/test_Consent_Map_Raw.R +++ b/tests/testthat/test_Consent_Map_Raw.R @@ -21,16 +21,17 @@ dfRDSL_test <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, dfInput_test <- tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - 1, 1, 1, - 1, 1, 1, - 1, 1, 1, - 1, 1, 1, - 2, 2, 1, - 2, 2, 0, - 2, 2, 0, - 3, 2, 1, - 5, 3, 1) + ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, + 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, + 2, 2, "2015-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, FALSE, TRUE, 1, + 2, 2, "2015-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, FALSE, FALSE, 0, + 2, 2, "2015-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, FALSE, FALSE, 0, + 3, 2, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1, + 5, 3, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1 +) test_that("output created as expected and has correct structure",{ @@ -38,7 +39,9 @@ test_that("output created as expected and has correct structure",{ expect_true(is.data.frame(consent_input)) expect_equal( names(consent_input), - c("SubjectID","SiteID","Count")) + c("SubjectID", "SiteID", "RandDate", "CONSCAT_STD", "CONSYN", + "CONSDAT", "flag_noconsent", "flag_missing_consent", "flag_missing_rand", + "flag_date_compare", "any_flag", "Count")) }) test_that("incorrect inputs throw errors",{ @@ -187,28 +190,40 @@ dfRDSL_test2 <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, dfInput_test2 <- tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - 1, 1, 1, - 1, 1, 1) - + ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, + 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 +) test_that("NA's in data are removed and handled correctly",{ dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,2] = NA - expect_equal( tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) + expect_equal( + tibble::tribble( + ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, + 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 + ), + Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2) + ) dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,3] = NA - expect_equal( tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - 1, 1, 1, - 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) + expect_equal( + tibble::tribble( + ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, + 1, 1, "2013-12-25", "MAINCONSENT", NA, "2014-12-25", NA, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 + ), + Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2) + ) dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA - expect_equal( tibble::tribble( - ~SubjectID, ~SiteID, ~Count, - 1, 1, 1, - 1, 1, 1), suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in))) + expect_equal( + tibble::tribble( + ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, + 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, + 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 + ), + suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in)) + ) diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index a1479316f..9b5bf1765 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -4,9 +4,10 @@ test_that("output created as expected and has correct structure",{ ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_true(is.data.frame(ie_input)) - # expect_equal( - # names(ie_input), - # c("SubjectID","SiteID","Count")) + expect_equal( + names(ie_input), + c("SubjectID", "SiteID", "Total", "Valid", "Invalid", "Missing", "Count") + ) }) test_that("incorrect inputs throw errors",{ @@ -128,54 +129,56 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ ) }) -# test_that("output is correct given clindata example input",{ -# -# dfIE <- clindata::raw_ie_all -# dfIE$SUBJID <- as.character(dfIE$SUBJID) -# -# dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, -# "0496", "X055X", -# "0539", "X128X", -# "1314", "X169X", -# "1218", "X126X" ) -# -# -# -# dfInput <- tibble::tribble( -# ~SubjectID, ~SiteID, ~Count, -# "0496", "X055X", 15L, -# "0539", "X128X", 15L, -# "1314", "X169X", 14L, -# "1218", "X126X", 14L -# ) -# -# expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) -# -# -# -# -# -# dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, -# 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, -# 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, -# 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, -# 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, -# 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, -# 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, -# 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, -# 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, -# 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) -# -# dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) -# -# dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, -# 1, 1, 2L, -# 2, 1, 2L, -# 4, 3, 1L ) -# -# expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) -# -# }) +test_that("output is correct given clindata example input",{ + +dfIE <- clindata::raw_ie_all +dfIE$SUBJID <- as.character(dfIE$SUBJID) + +dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, + "0496", "X055X", + "0539", "X128X", + "1314", "X169X", + "1218", "X126X" ) + + + +dfInput <- tibble::tribble( + ~SubjectID, ~SiteID, ~Total, ~Valid, ~Invalid, ~Missing, ~Count, + "0496", "X055X", 24L, 9L, 15L, 0L, 15L, + "0539", "X128X", 24L, 9L, 15L, 0L, 15L, + "1314", "X169X", 23L, 9L, 14L, 0L, 14L, + "1218", "X126X", 23L, 9L, 14L, 0L, 14L +) + +expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) + + + + + +dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, + 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, + 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) + +dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) + +dfInput <- tibble::tribble( + ~SubjectID, ~SiteID, ~Total, ~Valid, ~Invalid, ~Missing, ~Count, + 1, 1, 3L, 1L, 2L, 0L, 2L, + 2, 1, 3L, 1L, 2L, 0L, 2L, + 4, 3, 3L, 2L, 1L, 0L, 1L +) + +expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) + +}) test_that("NA values are handled correctly", { From b98839085ecc0943a9a963ee3efadd6e3a1b536d Mon Sep 17 00:00:00 2001 From: jwildfire Date: Wed, 9 Mar 2022 15:19:47 -0500 Subject: [PATCH 57/60] Update R/Consent_Map_Raw.R --- R/Consent_Map_Raw.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index ca0d83cb6..f6000e72e 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -85,7 +85,7 @@ Consent_Map_Raw <- function( dfConsent, dfRDSL, strConsentReason = "mainconsent" mutate(flag_date_compare = .data$CONSDAT >= .data$RandDate ) %>% mutate(any_flag=.data$flag_noconsent | .data$flag_missing_consent | .data$flag_missing_rand | .data$flag_date_compare) %>% mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) #%>% - #select(.data$SubjectID, .data$SiteID, .data$Count) + select(.data$SubjectID, .data$SiteID, .data$Count) return(dfInput) } From ec9edd2ae10094ca7cb36bde9ef88df6245d60ef Mon Sep 17 00:00:00 2001 From: jwildfire Date: Wed, 9 Mar 2022 15:19:53 -0500 Subject: [PATCH 58/60] Update R/IE_Map_Raw.R --- R/IE_Map_Raw.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/IE_Map_Raw.R b/R/IE_Map_Raw.R index 41f25b0a1..9416b8495 100644 --- a/R/IE_Map_Raw.R +++ b/R/IE_Map_Raw.R @@ -93,7 +93,7 @@ IE_Map_Raw <- function( dfInput <- dfRDSL %>% select(.data$SubjectID, .data$SiteID)%>% inner_join(dfIE_Subj, by="SubjectID") %>% - select(.data$SubjectID, .data$SiteID, .data$Total, .data$Valid, .data$Invalid, .data$Missing, .data$Count) + select(.data$SubjectID, .data$SiteID, .data$Count) #Throw warning if a an ID in IE isn't found in RDSL From 6be0179a67b6123df96730e331be211da44ffec0 Mon Sep 17 00:00:00 2001 From: Matt Roumaya Date: Wed, 9 Mar 2022 20:39:05 +0000 Subject: [PATCH 59/60] revert tests --- R/Consent_Map_Raw.R | 2 +- tests/testthat/test_Consent_Map_Raw.R | 115 +++++++++++--------------- tests/testthat/test_IE_Map_Raw.R | 115 +++++++++++--------------- 3 files changed, 99 insertions(+), 133 deletions(-) diff --git a/R/Consent_Map_Raw.R b/R/Consent_Map_Raw.R index f6000e72e..316b3a51d 100644 --- a/R/Consent_Map_Raw.R +++ b/R/Consent_Map_Raw.R @@ -84,7 +84,7 @@ Consent_Map_Raw <- function( dfConsent, dfRDSL, strConsentReason = "mainconsent" mutate(flag_missing_rand = is.na(.data$RandDate))%>% mutate(flag_date_compare = .data$CONSDAT >= .data$RandDate ) %>% mutate(any_flag=.data$flag_noconsent | .data$flag_missing_consent | .data$flag_missing_rand | .data$flag_date_compare) %>% - mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) #%>% + mutate(Count = as.numeric(.data$any_flag, na.rm = TRUE)) %>% select(.data$SubjectID, .data$SiteID, .data$Count) return(dfInput) diff --git a/tests/testthat/test_Consent_Map_Raw.R b/tests/testthat/test_Consent_Map_Raw.R index 92d4d7fe5..d34ce61a3 100644 --- a/tests/testthat/test_Consent_Map_Raw.R +++ b/tests/testthat/test_Consent_Map_Raw.R @@ -12,41 +12,38 @@ dfConsent_test <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, 5, "MAINCONSENT", "Yes", "2014-12-25" ) dfRDSL_test <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, - 1, 1, "2013-12-25", - 2, 2, "2015-12-25", - 3, 2, "2013-12-25", - 4, 3, "2013-12-25", - 5, 3, "2013-12-25") + 1, 1, "2013-12-25", + 2, 2, "2015-12-25", + 3, 2, "2013-12-25", + 4, 3, "2013-12-25", + 5, 3, "2013-12-25") dfInput_test <- tibble::tribble( - ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, - 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, - 2, 2, "2015-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, FALSE, TRUE, 1, - 2, 2, "2015-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, FALSE, FALSE, 0, - 2, 2, "2015-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, FALSE, FALSE, 0, - 3, 2, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1, - 5, 3, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1 -) + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1, + 1, 1, 1, + 1, 1, 1, + 2, 2, 1, + 2, 2, 0, + 2, 2, 0, + 3, 2, 1, + 5, 3, 1) test_that("output created as expected and has correct structure",{ - consent_input <- Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test) - expect_true(is.data.frame(consent_input)) - expect_equal( - names(consent_input), - c("SubjectID", "SiteID", "RandDate", "CONSCAT_STD", "CONSYN", - "CONSDAT", "flag_noconsent", "flag_missing_consent", "flag_missing_rand", - "flag_date_compare", "any_flag", "Count")) - }) + consent_input <- Consent_Map_Raw(dfConsent = dfConsent_test, dfRDSL = dfRDSL_test, strConsentReason = "mainconsent") + expect_true(is.data.frame(consent_input)) + expect_equal( + names(consent_input), + c("SubjectID","SiteID","Count")) +}) test_that("incorrect inputs throw errors",{ - expect_error(Consent_Map_Raw(list(), list())) - expect_error(Consent_Map_Raw("Hi","Mom")) + expect_error(Consent_Map_Raw(list(), list())) + expect_error(Consent_Map_Raw("Hi","Mom")) }) @@ -66,14 +63,14 @@ test_that("error given if required column not found",{ expect_error( Consent_Map_Raw( dfConsent_test %>% select(-SUBJID), - dfRDSL = dfRDSL_test + dfRDSL = dfRDSL_test ) ) expect_error( Consent_Map_Raw( dfConsent_test %>% select(-INVID) , - dfRDSL = dfRDSL_test + dfRDSL = dfRDSL_test ) ) @@ -145,12 +142,12 @@ test_that("output is correct given clindata example input",{ }) dfConsent_test_NA1 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, - NA, "MAINCONSENT", "Yes", "2014-12-25", - 1, "MAINCONSENT", "No", "2014-12-25" ) + NA, "MAINCONSENT", "Yes", "2014-12-25", + 1, "MAINCONSENT", "No", "2014-12-25" ) dfRDSL_test_NA1<- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, - 1, 1, "2013-12-25", - 2, 2, "2015-12-25") + 1, 1, "2013-12-25", + 2, 2, "2015-12-25") @@ -181,49 +178,37 @@ test_that("Incorrect strConsentReason throws errors",{ dfConsent_test2 <- tibble::tribble(~SUBJID, ~CONSCAT_STD , ~CONSYN , ~CONSDAT, - 1, "MAINCONSENT", "Yes", "2014-12-25", - 1, "MAINCONSENT", "No", "2014-12-25") + 1, "MAINCONSENT", "Yes", "2014-12-25", + 1, "MAINCONSENT", "No", "2014-12-25") dfRDSL_test2 <- tibble::tribble(~SubjectID, ~SiteID, ~RandDate, - 1, 1, "2013-12-25", - 2, 2, "2015-12-25") + 1, 1, "2013-12-25", + 2, 2, "2015-12-25") dfInput_test2 <- tibble::tribble( - ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, - 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 -) + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1) + test_that("NA's in data are removed and handled correctly",{ - dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,2] = NA - expect_equal( - tibble::tribble( - ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, - 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 - ), - Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2) - ) + dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,2] = NA + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) dfConsent_test_in <- dfConsent_test2; dfConsent_test_in[1,3] = NA - expect_equal( - tibble::tribble( - ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, - 1, 1, "2013-12-25", "MAINCONSENT", NA, "2014-12-25", NA, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 - ), - Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2) - ) + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1), Consent_Map_Raw(dfConsent = dfConsent_test_in, dfRDSL = dfRDSL_test2)) dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA - expect_equal( - tibble::tribble( - ~SubjectID, ~SiteID, ~RandDate, ~CONSCAT_STD, ~CONSYN, ~CONSDAT, ~flag_noconsent, ~flag_missing_consent, ~flag_missing_rand, ~flag_date_compare, ~any_flag, ~Count, - 1, 1, "2013-12-25", "MAINCONSENT", "Yes", "2014-12-25", FALSE, FALSE, FALSE, TRUE, TRUE, 1, - 1, 1, "2013-12-25", "MAINCONSENT", "No", "2014-12-25", TRUE, FALSE, FALSE, TRUE, TRUE, 1 - ), - suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in)) - ) + expect_equal( tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + 1, 1, 1, + 1, 1, 1), suppressWarnings(Consent_Map_Raw(dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in))) @@ -233,5 +218,3 @@ test_that("Warning provided for missing (NA) SiteID's in dfRDSL",{ dfRDSL_in <- dfRDSL_test2; dfRDSL_in[2,2] = NA expect_warning(Consent_Map_Raw( dfConsent = dfConsent_test2, dfRDSL = dfRDSL_in )) }) - - diff --git a/tests/testthat/test_IE_Map_Raw.R b/tests/testthat/test_IE_Map_Raw.R index 9b5bf1765..e5006753d 100644 --- a/tests/testthat/test_IE_Map_Raw.R +++ b/tests/testthat/test_IE_Map_Raw.R @@ -1,16 +1,20 @@ - - test_that("output created as expected and has correct structure",{ ie_input <-suppressWarnings(IE_Map_Raw(clindata::raw_ie_all , clindata::rawplus_rdsl, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) - expect_true(is.data.frame(ie_input)) + expect_true(is.data.frame(ie_input)) - expect_equal( - names(ie_input), - c("SubjectID", "SiteID", "Total", "Valid", "Invalid", "Missing", "Count") - ) - }) + expect_equal( + names(ie_input), + c("SubjectID","SiteID","Count")) +}) test_that("incorrect inputs throw errors",{ + expect_error(IE_Map_Raw(list(), list())) + expect_error(IE_Map_Raw("Hi","Mom")) +}) + + +test_that("incorrect inputs throw errors",{ + expect_error(IE_Map_Raw(list(), list())) expect_error(IE_Map_Raw( clindata::raw_ie_all, list(), strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) expect_error(IE_Map_Raw(list())) @@ -73,12 +77,12 @@ test_that("error given if required column not found",{ expect_silent( suppressWarnings( - IE_Map_Raw( - clindata::raw_ie_all %>% select(-PROJECT), - clindata::rawplus_rdsl, - strCategoryCol = 'IECAT_STD', - strResultCol = 'IEORRES' - ) + IE_Map_Raw( + clindata::raw_ie_all %>% select(-PROJECT), + clindata::rawplus_rdsl, + strCategoryCol = 'IECAT_STD', + strResultCol = 'IEORRES' + ) ) ) }) @@ -131,70 +135,49 @@ test_that("icorrect strCategoryCol or strResultCol throw errors",{ test_that("output is correct given clindata example input",{ -dfIE <- clindata::raw_ie_all -dfIE$SUBJID <- as.character(dfIE$SUBJID) - -dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, - "0496", "X055X", - "0539", "X128X", - "1314", "X169X", - "1218", "X126X" ) - - - -dfInput <- tibble::tribble( - ~SubjectID, ~SiteID, ~Total, ~Valid, ~Invalid, ~Missing, ~Count, - "0496", "X055X", 24L, 9L, 15L, 0L, 15L, - "0539", "X128X", 24L, 9L, 15L, 0L, 15L, - "1314", "X169X", 23L, 9L, 14L, 0L, 14L, - "1218", "X126X", 23L, 9L, 14L, 0L, 14L -) - -expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) + dfIE <- clindata::raw_ie_all + dfIE$SUBJID <- as.character(dfIE$SUBJID) + dfRDSL <- tibble::tribble( ~SubjectID, ~SiteID, + "0496", "X055X", + "0539", "X128X", + "1314", "X169X", + "1218", "X126X" ) + dfInput <- tibble::tribble( + ~SubjectID, ~SiteID, ~Count, + "0496", "X055X", 15L, + "0539", "X128X", 15L, + "1314", "X169X", 14L, + "1218", "X126X", 14L + ) -dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, - 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, - 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, - 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) + expect_equal(suppressWarnings(IE_Map_Raw(dfIE = dfIE, dfRDSL=dfRDSL, strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')), dfInput ) -dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) -dfInput <- tibble::tribble( - ~SubjectID, ~SiteID, ~Total, ~Valid, ~Invalid, ~Missing, ~Count, - 1, 1, 3L, 1L, 2L, 0L, 2L, - 2, 1, 3L, 1L, 2L, 0L, 2L, - 4, 3, 3L, 2L, 1L, 0L, 1L -) -expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) -}) -test_that("NA values are handled correctly", { + dfIE_test <- tibble::tribble( ~SUBJID, ~INVID, ~IECAT, ~IETEST, ~ IETESTCD, ~IEORRES, + 1, 1, "Exclusion", "XXX", "Exclusion 3", 0, + 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 1, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Exclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 2, 1, "Inclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Exclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Inclusion", "XXX", "Exclusion 3", 0, + 4, 3, "Inclusion", "XXX", "Exclusion 3", 1) - ieNASUBJID <- clindata::raw_ie_all %>% - mutate(SUBJID = rep(c(NA, "1234"), nrow(clindata::raw_ie_all)/2)) + dfRDSL2 <- data.frame(SubjectID=c(1,2,4), SiteID=c(1,1,3)) - ieNAstrCategoryCol <- clindata::raw_ie_all %>% - mutate(IECAT_STD = rep(c(NA, "INCLUSION"), nrow(clindata::raw_ie_all)/2)) + dfInput <- tibble::tribble( ~SubjectID, ~SiteID, ~Count, + 1, 1, 2L, + 2, 1, 2L, + 4, 3, 1L ) - ieNAstrResultCol <- clindata::raw_ie_all %>% - mutate(IEORRES = rep(c(0, NA), nrow(clindata::raw_ie_all)/2)) + expect_equal(dfInput, IE_Map_Raw(dfIE_test,dfRDSL2, strCategoryCol = 'IECAT', strResultCol = 'IEORRES'), ignore_attr = TRUE) - expect_error(IE_Map_Raw(ieNASUBJID , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) - expect_error(IE_Map_Raw(ieNAstrCategoryCol , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) - expect_error(IE_Map_Raw(ieNAstrResultCol , clindata::rawplus_rdsl,strCategoryCol = 'IECAT_STD', strResultCol = 'IEORRES')) }) - - - From 353d2219296de1ee502b0bbccc8158dd03e6e545 Mon Sep 17 00:00:00 2001 From: jwildfire Date: Mon, 14 Mar 2022 21:39:57 -0400 Subject: [PATCH 60/60] Update version --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 264f8ead3..ccaf44816 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: gsm Title: Gilead Statistical Monitoring -Version: 0.1.0 +Version: 0.2.0 Authors@R: c( person("George", "Wu", email="george.wu@gilead.com", role = c("aut", "cre")), person("Jeremy", "Wildfire", email="jeremy.wildfire@gilead.com", role = c("aut")))