From 444e514a501d03032f64ced41237968ebaef52ca Mon Sep 17 00:00:00 2001 From: dpc10ster Date: Fri, 11 Aug 2023 21:02:56 -0400 Subject: [PATCH] removed SPLIT-PLOT A, C; working on X versions of St functions --- NAMESPACE | 3 +- NEWS.md | 3 +- R/DfFroc2Roc.R | 1 - R/DfReadDataFile.R | 87 +-- R/ORAnalysisFactorial.R | 6 +- R/ORAnalysisFactorialX.R | 592 ++++++++++++++++++ R/ORAnalysisSplitPlot.R | 491 --------------- R/StORSummaryRRFC.R | 6 - R/StSignificanceTesting.R | 51 +- R/StSignificanceTestingCrossedModalities.R | 585 ----------------- R/UtilFigureOfMerit.R | 46 +- R/UtilFigureOfMeritX.R | 126 ++++ R/UtilPseudoValues.R | 4 +- R/UtilVarComponentsOR.R | 3 +- R/dataset2ratings.R | 3 +- R/datasets.R | 45 +- data/datasetFROCSpC.RData | Bin 1826 -> 0 bytes inst/FixDatasets/FixAllDatasets.R | 18 - inst/debugTests/debug-test-UtilOutputReport.R | 7 +- inst/extdata/toyFiles/FROC/1T3Rvs4R.xlsx | Bin 55754 -> 0 bytes inst/extdata/toyFiles/FROC/FrocDataSpC.xlsx | Bin 25278 -> 0 bytes .../toyFiles/FROC/FrocSpCVaryK1K2.xlsx | Bin 25300 -> 0 bytes inst/extdata/toyFiles/FROC/frocSpA.xlsx | Bin 20866 -> 0 bytes inst/extdata/toyFiles/FROC/frocSpC.xlsx | Bin 19448 -> 0 bytes .../toyFiles/FROC/frocSpCDelRowsFP.xlsx | Bin 17558 -> 0 bytes .../toyFiles/FROC/frocSpCZeroWgts.xlsx | Bin 17562 -> 0 bytes man/DfFroc2Roc.Rd | 1 - man/DfReadDataFile.Rd | 4 +- man/RJafroc-package.Rd | 10 +- man/StSignificanceTesting.Rd | 30 +- man/StSignificanceTestingCrossedModalities.Rd | 39 -- man/UtilFigureOfMerit.Rd | 2 - man/UtilFigureOfMeritX.Rd | 77 +++ man/UtilPseudoValues.Rd | 4 +- man/datasetFROCSpC.Rd | 42 -- man/datasetXModality.Rd | 3 +- tests/testthat/test-DfExtractDataset.R | 50 +- tests/testthat/test-DfReadDataFile.R | 126 +--- tests/testthat/test-OldVsNew-OR.R | 2 +- tests/testthat/test-PseudoValues.R | 163 ----- .../test-StSignificanceTestingSplitPlot.R | 75 --- tests/testthat/test-UtilFigureOfMerit.R | 21 - tests/testthat/test-UtilOutputReport.R | 26 +- tests/testthat/test-UtilVarComponents.R | 36 +- 44 files changed, 880 insertions(+), 1908 deletions(-) create mode 100644 R/ORAnalysisFactorialX.R delete mode 100644 R/ORAnalysisSplitPlot.R delete mode 100644 R/StSignificanceTestingCrossedModalities.R create mode 100644 R/UtilFigureOfMeritX.R delete mode 100644 data/datasetFROCSpC.RData delete mode 100644 inst/extdata/toyFiles/FROC/1T3Rvs4R.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/FrocDataSpC.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/FrocSpCVaryK1K2.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/frocSpA.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/frocSpC.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/frocSpCDelRowsFP.xlsx delete mode 100644 inst/extdata/toyFiles/FROC/frocSpCZeroWgts.xlsx delete mode 100644 man/StSignificanceTestingCrossedModalities.Rd create mode 100644 man/UtilFigureOfMeritX.Rd delete mode 100644 man/datasetFROCSpC.Rd delete mode 100644 tests/testthat/test-StSignificanceTestingSplitPlot.R diff --git a/NAMESPACE b/NAMESPACE index e93615f9..9fabd540 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -44,7 +44,6 @@ export(SsPowerTable) export(SsSampleSizeKGivenJ) export(StSignificanceTesting) export(StSignificanceTestingCadVsRad) -export(StSignificanceTestingCrossedModalities) export(Util2Intrinsic) export(Util2Physical) export(UtilAnalyticalAucsRSM) @@ -53,6 +52,7 @@ export(UtilAucCBM) export(UtilAucPROPROC) export(UtilDBM2ORVarCom) export(UtilFigureOfMerit) +export(UtilFigureOfMeritX) export(UtilLesDistr) export(UtilLesWghtsDS) export(UtilLesWghtsLD) @@ -85,7 +85,6 @@ importFrom(numDeriv,hessian) importFrom(numDeriv,jacobian) importFrom(stats,approx) importFrom(stats,cor) -importFrom(stats,cov) importFrom(stats,dbinom) importFrom(stats,dnorm) importFrom(stats,integrate) diff --git a/NEWS.md b/NEWS.md index c0be64eb..474f0bc9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,7 @@ title: "NEWS" * Bug fix, Issue 89, see below * Fixed entry errors in Excel file (check column names and data type) * TODO: `QuickStart`, new chapter on recommended FOMs and those to avoid at all costs +* Removed SPLIT-PLOT-A and SPLIT-PLOT-C analyses: no one is using it and I have no dataset or statistician involvement to validate the implementation. It is still available on previous versions, i.e., versions < 2.1.3. ### Issue 90 @@ -26,7 +27,7 @@ title: "NEWS" * Added a sorting step to both worksheets: order by modality, then reader, then case and then rating. * Also ALWAYS use `TP_Rating` and `FP_Rating` in these sheets; do not use LL_Rating and/or NL_Rating as this will break the code. * Some `goodValues` had to be regenerated. -* TODO: Not sure about the split plot codes; these have never been used and I should consider removing them. +* TODO: Not sure about the split plot codes; these have never been used and I should consider removing them. Done: 8/11/23 ### Changes 05/19/2023 diff --git a/R/DfFroc2Roc.R b/R/DfFroc2Roc.R index 3a5a48a7..43ac3bfa 100644 --- a/R/DfFroc2Roc.R +++ b/R/DfFroc2Roc.R @@ -29,7 +29,6 @@ #' #' @examples #' rocDataSet <- DfFroc2Roc(dataset05) -#' rocSpDataSet <- DfFroc2Roc(datasetFROCSpC) #' #' ## in the following example, because of the smaller number of cases, #' ## it is easy to see the process at work: diff --git a/R/DfReadDataFile.R b/R/DfReadDataFile.R index 17788598..427fab1e 100644 --- a/R/DfReadDataFile.R +++ b/R/DfReadDataFile.R @@ -38,9 +38,7 @@ #' treatment and reader IDs (i.e., names). Otherwise, treatment #' and reader IDs in the original data file will be used. #' -#' @note WARNING: SPLIT-PLOT-A and SPLIT-PLOT-C have not been tested with real datasets. -#' Contact the maintainer if you desire this funtionality. -#' The \code{"MRMC"} format is deprecated. For non-JAFROC formats four file +#' @note The \code{"MRMC"} format is deprecated. For non-JAFROC formats four file #' extensions (\code{.csv}, \code{.txt}, \code{.lrc} and \code{.imrmc}) are possible, #' all of which are restricted to ROC data. Only the \code{iMRMC} format is actively #' supported, i.e, files with extension \code{.imrmc}. Other formats (\code{.csv}, @@ -181,8 +179,8 @@ preCheck4BadEntries <- function(truthTable) { -# SPLIT-PLOT-A: Reader nested within test; Hillis 2014 Table VII part (a) -# SPLIT-PLOT-C: Case nested within reader; Hillis 2014 Table VII part (c) + + checkTruthTable <- function (truthTable, lrocForcedMark) { @@ -192,7 +190,7 @@ checkTruthTable <- function (truthTable, lrocForcedMark) design <- (toupper(truthTable[,6][which(!is.na(truthTable[,6]))]))[2] if (design == "CROSSED") design <- "FCTRL" if (!(type %in% c("FROC", "ROC", "LROC"))) stop("Unsupported data type: must be ROC, FROC or LROC.\n") - if (!(design %in% c("FCTRL", "SPLIT-PLOT-A", "SPLIT-PLOT-C"))) stop("Study design must be FCTRL, SPLIT-PLOT-A or SPLIT-PLOT-C\n") + if (!(design %in% c("FCTRL"))) stop("Study design must be FCTRL.\n") if (type == "LROC") { if (is.na(lrocForcedMark)) stop("For LROC dataset one must set the lrocForcedMark flag to a logical") @@ -227,64 +225,7 @@ checkTruthTable <- function (truthTable, lrocForcedMark) K2 <- length(abnormalCases) K <- (K1 + K2) - if (design == "SPLIT-PLOT-A") { - - # for this design the length is twice what it needs to be - caseIDCol <- as.integer(truthTable$CaseID)[1:(L/2)] - # lesionIDCol <- as.integer(truthTable$LesionID)[1:(L/2)] - weightsCol <- truthTable$Weight[1:(L/2)] - # preserve the strings; DO NOT convert to integers - J <- 0 # find max number of readers, given that his data has 3 readers in one group and 4 in the other group - for (el in 1:length(readerIDCol)) { - if (length(strsplit(readerIDCol[el], split = ",")[[1]]) > J) J <- length(strsplit(readerIDCol[el], split = ",")[[1]]) - } - rdrArr <- array(dim = c(L,J)) - for (l in 1:L) { - val <- strsplit(readerIDCol[l], split = ",|\\s")[[1]] - val <- val[val != ""] - for (i in 1:length(val)) { - rdrArr[l,i] <- val[i] - } - } - # preserve the strings; DO NOT convert to integers - I <- length(strsplit(modalityIDCol[1], split = ",")[[1]]) - trtArr <- array(dim = c(L,I)) - for (l in 1:L) { - if (grep("^\\(.\\)", modalityIDCol[l]) == 1) { # match found to something like (1), i.e., one nested factor - val <- grep("^\\(.\\)", modalityIDCol[l], value = T) - val <- strsplit(val, split = "\\(|\\)")[[1]] - val <- val[val != ""] - for (i in 1:length(val)) { - trtArr[l] <- val[i] - } - } else stop("Was expecting nested notation, using () brackets ...") - } - } else if (design == "SPLIT-PLOT-C") { - - # preserve the strings; DO NOT convert to integers - J <- length(strsplit(readerIDCol[1], split = ",")[[1]]) - rdrArr <- array(dim = c(L,J)) - for (l in 1:L) { - if (grep("^\\(.\\)", readerIDCol[l]) == 1) { # match found to something like (1), i.e., one nested factor - val <- grep("^\\(.\\)", readerIDCol[l], value = T) - val <- strsplit(val, split = "\\(|\\)")[[1]] - val <- val[val != ""] - for (i in 1:length(val)) { - rdrArr[l] <- val[i] - } - } else stop("Was expecting nested notation, using () brackets ...") - # preserve the strings; DO NOT convert to integers - I <- length(strsplit(modalityIDCol[1], split = ",")[[1]]) - trtArr <- array(dim = c(L,I)) - for (l in 1:L) { - val <- strsplit(modalityIDCol[l], split = ",|\\s")[[1]] - val <- val[val != ""] - for (i in 1:length(val)) { - trtArr[l,i] <- val[i] - } - } - } - } else if (design == "FCTRL") { + if (design == "FCTRL") { # preserve the strings; DO NOT convert to integers J <- length(strsplit(readerIDCol[1], split = ",")[[1]]) # bug non-character input error for HUGE dataset rdrArr <- array(dim = c(L,J)) @@ -307,13 +248,8 @@ checkTruthTable <- function (truthTable, lrocForcedMark) } } else stop("incorrect design value") - if (design == "SPLIT-PLOT-A") { - rdrArr1D <- t(unique(rdrArr)) # rdrArr is 2-dimensional; rdrArr1D is a one-dimensional array of all the readers in the study - rdrArr1D <- rdrArr1D[!is.na(rdrArr1D)] # this modification is needed for HYK dataset with 3 readers in one group and 4 in the other - } else { if (any(is.na(rdrArr))) stop("Illegal value in ReaderID column in Truth sheet") rdrArr1D <- as.vector(unique(rdrArr)) # rdrArr is 2-dimensional; rdrArr1D is a one-dimensional array of all the readers in the study - } if (any(is.na(trtArr))) stop("Illegal value in ModalityID column in Truth sheet") trtArr1D <- as.vector(unique(trtArr)) @@ -324,18 +260,7 @@ checkTruthTable <- function (truthTable, lrocForcedMark) for (l in 1:L) { k <- which(unique(truthTableSort$CaseID) == truthTable$CaseID[l]) el <- lesionIDCol[l] + 1 - if (design == "SPLIT-PLOT-A") { - i <- which(unique(trtArr) == trtArr[l]) - for (j1 in 1:length(rdrArr[l,])) { - j <- which(rdrArr1D == rdrArr[l,j1]) - truthTableStr[i, j, k, el] <- 1 - } - } - else if (design == "SPLIT-PLOT-C") { - i <- which(unique(trtArr) == trtArr[l,]) - j <- which(rdrArr1D == rdrArr[l]) - truthTableStr[i, j, k, el] <- 1 - } else if (design == "FCTRL") { + if (design == "FCTRL") { i <- which(unique(trtArr) == trtArr[l,]) j <- which(rdrArr1D == rdrArr[l,]) truthTableStr[i, j, k, el] <- 1 diff --git a/R/ORAnalysisFactorial.R b/R/ORAnalysisFactorial.R index 3e75717f..eb063622 100644 --- a/R/ORAnalysisFactorial.R +++ b/R/ORAnalysisFactorial.R @@ -94,7 +94,6 @@ ORAnalysisFactorial <- function(dataset, FOM, FPFValue, alpha = 0.05, covEstMeth } -# 5/30/20 returning zeroes instead of NAs; simplifies handling of SPLIT-PLOT-C dataseets FOMijk2VarCov <- function(resampleFOMijk, varInflFactor) { I <- dim(resampleFOMijk)[1] @@ -119,8 +118,6 @@ FOMijk2VarCov <- function(resampleFOMijk, varInflFactor) { Var <- 0 count <- 0 - I <- dim(covariances)[1] - J <- dim(covariances)[3] for (i in 1:I) { for (j in 1:J) { Var <- Var + covariances[i, i, j, j] @@ -179,8 +176,7 @@ FOMijk2VarCov <- function(resampleFOMijk, varInflFactor) { Var = Var, Cov1 = Cov1, Cov2 = Cov2, - Cov3 = Cov3, - CovMatrix = covariances + Cov3 = Cov3 )) } diff --git a/R/ORAnalysisFactorialX.R b/R/ORAnalysisFactorialX.R new file mode 100644 index 00000000..3f36aad4 --- /dev/null +++ b/R/ORAnalysisFactorialX.R @@ -0,0 +1,592 @@ +ORAnalysisFactorialX <- function(dsX, avgIndx, FOM, alpha, analysisOption) +{ + + RRRC <- NULL + FRRC <- NULL + RRFC <- NULL + + modalityID1 <- dsX$descriptions$modalityID1 + modalityID2 <- dsX$descriptions$modalityID2 + + I1 <- length(modalityID1) + I2 <- length(modalityID2) + + # `as.matrix` is NOT absolutely necessary as `mean()` function is not used + foms <- UtilFigureOfMeritX(dsX, FOM) + + ret <- UtilVarComponentsORX(dsX, FOM) + + TRanova <- ret$TRanova + VarCom <- ret$VarCom + IndividualTrt <- ret$IndividualTrt + IndividualRdr <- ret$IndividualRdr + + ANOVA <- list() + ANOVA$TRanova <- TRanova + ANOVA$VarCom <- VarCom + ANOVA$IndividualTrt <- IndividualTrt + ANOVA$IndividualRdr <- IndividualRdr + + trtMeans <- rowMeans(foms) + trtMeans <- as.data.frame(trtMeans) + colnames(trtMeans) <- "Estimate" + + trtMeanDiffs <- array(dim = choose(I, 2)) + diffTRName <- array(dim = choose(I, 2)) + ii <- 1 + for (i in 1:I) { + if (i == I) + break + for (ip in (i + 1):I) { + trtMeanDiffs[ii] <- trtMeans[i,1] - trtMeans[ip,1] + diffTRName[ii] <- paste0("trt", modalityID[i], sep = "-", "trt", modalityID[ip]) # !sic + ii <- ii + 1 + } + } + trtMeanDiffs <- data.frame("Estimate" = trtMeanDiffs, + row.names = diffTRName, + stringsAsFactors = FALSE) + + FOMs <- list( + foms = foms, + trtMeans = trtMeans, + trtMeanDiffs = trtMeanDiffs + ) + + if (analysisOption == "RRRC") { + RRRC <- ORSummaryRRRC(dsX, FOMs, ANOVA, alpha, diffTRName) + return(list( + FOMs = FOMs, + ANOVA = ANOVA, + RRRC = RRRC + )) + } + + if (analysisOption == "FRRC") { + FRRC <- ORSummaryFRRC(dsX, FOMs, ANOVA, alpha, diffTRName) + return(list( + FOMs = FOMs, + ANOVA = ANOVA, + FRRC = FRRC + )) + } + + if (analysisOption == "RRFC") { + RRFC <- ORSummaryRRFC(dsX, FOMs, ANOVA, alpha, diffTRName) + return(list( + FOMs = FOMs, + ANOVA = ANOVA, + RRFC = RRFC + )) + } + + if (analysisOption == "ALL") { + RRRC <- ORSummaryRRRC(dsX, FOMs, ANOVA, alpha, diffTRName) + FRRC <- ORSummaryFRRC(dsX, FOMs, ANOVA, alpha, diffTRName) + RRFC <- ORSummaryRRFC(dsX, FOMs, ANOVA, alpha, diffTRName) + return(list( + FOMs = FOMs, + ANOVA = ANOVA, + RRRC = RRRC, + FRRC = FRRC, + RRFC = RRFC + )) + } else stop("Incorrect analysisOption: must be `RRRC`, `FRRC`, `RRFC` or `ALL`") + +} + + +FOMijk2VarCov <- function(resampleFOMijk, varInflFactor) { + + I <- dim(resampleFOMijk)[1] + J <- dim(resampleFOMijk)[2] + K <- dim(resampleFOMijk)[3] + + covariances <- array(dim = c(I, I, J, J)) + + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + covariances[i, ip, j, jp] <- cov(resampleFOMijk[i, j, ], resampleFOMijk[ip, jp, ]) + } + } + } + } + + if (varInflFactor) { + covariances <- covariances * (K - 1)^2/K # see paper by Efron and Stein + } + + Var <- 0 + count <- 0 + for (i in 1:I) { + for (j in 1:J) { + Var <- Var + covariances[i, i, j, j] + count <- count + 1 + } + } + if (count > 0) Var <- Var/count else Var <- 0 + + Cov1 <- 0 + count <- 0 + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + if (ip != i) { + Cov1 <- Cov1 + covariances[i, ip, j, j] + count <- count + 1 + } + } + } + } + if (count > 0) Cov1 <- Cov1/count else Cov1 <- 0 + + Cov2 <- 0 + count <- 0 + for (i in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + if (j != jp) { + Cov2 <- Cov2 + covariances[i, i, j, jp] + count <- count + 1 + } + } + } + } + if (count > 0) Cov2 <- Cov2/count else Cov2 <- 0 + + Cov3 <- 0 + count <- 0 + for (i in 1:I) { + for (ip in 1:I) { + if (i != ip) { + for (j in 1:J) { + for (jp in 1:J) { + if (j != jp) { + Cov3 <- Cov3 + covariances[i, ip, j, jp] + count <- count + 1 + } + } + } + } + } + } + if (count > 0) Cov3 <- Cov3/count else Cov3 <- 0 + + return(list( + Var = Var, + Cov1 = Cov1, + Cov2 = Cov2, + Cov3 = Cov3 + )) + +} + + + +FOMijk2VarCovSpA <- function(resampleFOMijk, varInflFactor) { + + I <- dim(resampleFOMijk)[1] + J <- dim(resampleFOMijk)[2] + K <- dim(resampleFOMijk)[3] + + covariances <- array(dim = c(I, I, J, J)) + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + if (any(is.na(resampleFOMijk[i, j, ])) || any(is.na(resampleFOMijk[ip, jp, ]))) next + covariances[i, ip, j, jp] <- cov(resampleFOMijk[i, j, ], resampleFOMijk[ip, jp, ]) + } + } + } + } + + # See dropbox/RjafrocMaintenance/SpAMethods/Cov2Cov3Str.xlsx for hand calculations + Var_i <- rep(0,I) + count_i <- rep(0,I) + for (i in 1:I) { + rdr_i <- which(!is.na(resampleFOMijk[i,,1])) + for (j in 1:length(rdr_i)) { + if (is.na(covariances[i, i, rdr_i[j], rdr_i[j]])) next + Var_i[i] <- Var_i[i] + covariances[i, i, rdr_i[j], rdr_i[j]] + count_i[i] <- count_i[i] + 1 + } + if (count_i[i] > 0) Var_i[i] <- Var_i[i]/count_i[i] else Var_i[i] <- 0 + } + + Cov2_i <- rep(0,I) + count_i <- rep(0,I) + for (i in 1:I) { + rdr_i <- which(!is.na(resampleFOMijk[i,,1])) + for (j in 1:length(rdr_i)) { + for (jp in 1:length(rdr_i)) { + if (rdr_i[j] != rdr_i[jp]) { + if (is.na(covariances[i, i, rdr_i[j], rdr_i[jp]])) next + Cov2_i[i] <- Cov2_i[i] + covariances[i, i, rdr_i[j], rdr_i[jp]] + count_i[i] <- count_i[i] + 1 + } + } + } + if (count_i[i] > 0) Cov2_i[i] <- Cov2_i[i]/count_i[i] else Cov2_i[i] <- 0 + } + + Cov3_i <- rep(0,I) + count_i <- rep(0,I) + for (i in 1:I) { + for (ip in 1:I) { + rdr_i <- which(!is.na(resampleFOMijk[i,,1])) + rdr_ip <- which(!is.na(resampleFOMijk[ip,,1])) + if (i != ip) { + for (j in 1:length(rdr_i)) { + for (jp in 1:length(rdr_ip)) { + if (rdr_i[j] != rdr_ip[jp]) { + if (is.na(covariances[i, ip, rdr_i[j], rdr_ip[jp]])) next + Cov3_i[i] <- Cov3_i[i] + covariances[i, ip, rdr_i[j], rdr_ip[jp]] + count_i[i] <- count_i[i] + 1 + } + } + } + } + } + if (count_i[i] > 0) Cov3_i[i] <- Cov3_i[i]/count_i[i] else Cov3_i[i] <- 0 + } + + if (varInflFactor) { + Var_i <- Var_i * (K - 1)^2/K # see paper by Efron and Stein + Cov2_i <- Cov2_i * (K - 1)^2/K + Cov3_i <- Cov3_i * (K - 1)^2/K + } + + return(list(Var_i = Var_i, + Cov2_i = Cov2_i, + Cov3_i = Cov3_i + )) + +} + + + +varComponentsJackknifeFactorial <- function(dsX, FOM, FPFValue) { + if (dsX$descriptions$design != "FCTRL") stop("This functions requires a factorial dsX") + + K <- length(dsX$ratings$NL[1,1,,1]) + + ret <- UtilPseudoValues(dsX, FOM, FPFValue) + CovTemp <- FOMijk2VarCov(ret$jkFomValues, varInflFactor = TRUE) + Cov <- list( + Var = CovTemp$Var, + Cov1 = CovTemp$Cov1, + Cov2 = CovTemp$Cov2, + Cov3 = CovTemp$Cov3 + ) + + return(Cov) + +} + + + +#' @importFrom stats runif +varComponentsBootstrapFactorial <- function(dsX, FOM, FPFValue, nBoots, seed) +{ + if (dsX$descriptions$design != "FCTRL") stop("This functions requires a factorial dsX") + + set.seed(seed) ## added 4/28/20, to test reproducibility with RJafrocBook code + NL <- dsX$ratings$NL + LL <- dsX$ratings$LL + perCase <- dsX$lesions$perCase + IDs <- dsX$lesions$IDs + weights <- dsX$lesions$weights + + I <- length(NL[,1,1,1]) + J <- length(NL[1,,1,1]) + K <- length(NL[1,1,,1]) + K2 <- length(LL[1,1,,1]) + K1 <- (K - K2) + maxNL <- length(NL[1,1,1,]) + maxLL <- length(LL[1,1,1,]) + + if (FOM %in% c("MaxNLF", "ExpTrnsfmSp", "HrSp")) { + stop("This needs fixing") + fomBsArray <- array(dim = c(I, J, nBoots)) + for (b in 1:nBoots) { + kBs <- ceiling(runif(K1) * K1) + for (i in 1:I) { + for (j in 1:J) { + NLbs <- NL[i, j, kBs, ] + LLbs <- LL[i, j, , ] + dim(NLbs) <- c(K1, maxNL) + dim(LLbs) <- c(K2, maxLL) + fomBsArray[i, j, b] <- MyFom_ij(NLbs, LLbs, + perCase, IDs, + weights, maxNL, + maxLL, K1, K2, + FOM, FPFValue) + } + } + } + } else if (FOM %in% c("MaxLLF", "HrSe")) { + stop("This needs fixing") + fomBsArray <- array(dim = c(I, J, nBoots)) + for (b in 1:nBoots) { + kBs <- ceiling(runif(K2) * K2) + for (i in 1:I) { + for (j in 1:J) { + NLbs <- NL[i, j, c(1:K1, (kBs + K1)), ] + LLbs <- LL[i, j, kBs, ] + dim(NLbs) <- c(K, maxNL) + dim(LLbs) <- c(K2, maxLL) + lesionIDBs <- IDs[kBs, ] + dim(lesionIDBs) <- c(K2, maxLL) + lesionWeightBs <- weights[kBs, ] + dim(lesionWeightBs) <- c(K2, maxLL) + fomBsArray[i, j, b] <- MyFom_ij(NLbs, LLbs, + perCase[kBs], lesionIDBs, + lesionWeightBs, maxNL, maxLL, + K1, K2, FOM, FPFValue) + } + } + } + } else { # original code had errors; see Fadi RRRC code; Aug 9, 2017 !!dpc!!! + ## however, following code needs checking + ##stop("this code needs checking; contact Dr. Chakraborty with dsX and code that lands here; 8/9/2017") + fomBsArray <- array(dim = c(I, J, nBoots)) + for (b in 1:nBoots) { + k1bs <- ceiling(runif(K1) * K1) + k2bs <- ceiling(runif(K2) * K2) + for (i in 1:I) { + for (j in 1:J) { + NLbs <- NL[i, j, c(k1bs, k2bs + K1), ] + lesionVectorbs <- perCase[k2bs] + LLbs <- LL[i, j, k2bs,1:max(lesionVectorbs)] + dim(NLbs) <- c(K, maxNL) + dim(LLbs) <- c(K2, max(lesionVectorbs)) + lesionIDBs <- IDs[k2bs, ] + dim(lesionIDBs) <- c(K2, maxLL) + lesionWeightBs <- weights[k2bs, ] + dim(lesionWeightBs) <- c(K2, maxLL) + fomBsArray[i, j, b] <- MyFom_ij(NLbs, LLbs, lesionVectorbs, lesionIDBs, + lesionWeightBs, maxNL, maxLL, K1, K2, FOM, FPFValue) + } + } + } + } + + Cov <- FOMijk2VarCov(fomBsArray, varInflFactor = FALSE) + Var <- Cov$Var + Cov1 <- Cov$Cov1 + Cov2 <- Cov$Cov2 + Cov3 <- Cov$Cov3 + + return(list( + Var = Var, + Cov1 = Cov1, + Cov2 = Cov2, + Cov3 = Cov3 + )) + +} + + + +varComponentsDeLongFactorial <- function(dsX, FOM) +{ + if (dsX$descriptions$design != "FCTRL") stop("This functions requires a factorial dsX") + + UNINITIALIZED <- RJafrocEnv$UNINITIALIZED + NL <- dsX$ratings$NL + LL <- dsX$ratings$LL + perCase <- dsX$lesions$perCase + + I <- length(NL[,1,1,1]) + J <- length(NL[1,,1,1]) + K <- length(NL[1,1,,1]) + K2 <- length(LL[1,1,,1]) + K1 <- (K - K2) + maxNL <- length(NL[1,1,1,]) + maxLL <- length(LL[1,1,1,]) + # if ((maxLL != 1) || (maxLL != 1)) stop("dsX error in varComponentsDeLongFactorial") + + fomArray <- UtilFigureOfMerit(dsX, FOM) + + if (!FOM %in% c("Wilcoxon", "HrAuc", "ROI")) + stop("DeLong\"s method can only be used for trapezoidal figures of merit.") + + if (FOM == "ROI") { + kI01 <- which(apply((NL[1, 1, , ] != UNINITIALIZED), 1, any)) + numKI01 <- rowSums((NL[1, 1, , ] != UNINITIALIZED)) + I01 <- length(kI01) + I10 <- K2 + N <- sum((NL[1, 1, , ] != UNINITIALIZED)) + M <- sum(perCase) + V01 <- array(dim = c(I, J, I01, maxNL)) + V10 <- array(dim = c(I, J, I10, maxLL)) + for (i in 1:I) { + for (j in 1:J) { + for (k in 1:I10) { + for (el in 1:perCase[k]) { + V10[i, j, k, el] <- (sum(as.vector(NL[i, j, , ][NL[i, j, , ] != UNINITIALIZED]) < LL[i, j, k, el]) + + 0.5 * sum(as.vector(NL[i, j, , ][NL[i, j, , ] != UNINITIALIZED]) == LL[i, j, k, el]))/N + } + } + for (k in 1:I01) { + for (el in 1:maxNL) { + if (NL[i, j, kI01[k], el] == UNINITIALIZED) + next + V01[i, j, k, el] <- (sum(NL[i, j, kI01[k], el] < as.vector(LL[i, j, , ][LL[i, j, , ] != UNINITIALIZED])) + + 0.5 * sum(NL[i, j, kI01[k], el] == as.vector(LL[i, j, , ][LL[i, j, , ] != UNINITIALIZED])))/M + } + } + } + } + s10 <- array(0, dim = c(I, I, J, J)) + s01 <- array(0, dim = c(I, I, J, J)) + s11 <- array(0, dim = c(I, I, J, J)) + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + for (k in 1:I10) { + s10[i, ip, j, jp] <- (s10[i, ip, j, jp] + + (sum(V10[i, j, k, !is.na(V10[i, j, k, ])]) + - perCase[k] * fomArray[i, j]) + * (sum(V10[ip, jp, k, !is.na(V10[ip, jp, k, ])]) + - perCase[k] * fomArray[ip, jp])) + } + for (k in 1:I01) { + s01[i, ip, j, jp] <- (s01[i, ip, j, jp] + + (sum(V01[i, j, k, !is.na(V01[i, j, k, ])]) + - numKI01[kI01[k]] * fomArray[i, j]) + * (sum(V01[ip, jp, k, !is.na(V01[ip, jp, k, ])]) + - numKI01[kI01[k]] * fomArray[ip, jp])) + } + allAbn <- 0 + for (k in 1:K2) { + if (all(NL[ip, jp, k + K1, ] == UNINITIALIZED)) { + allAbn <- allAbn + 1 + next + } + s11[i, ip, j, jp] <- (s11[i, ip, j, jp] + + (sum(V10[i, j, k, !is.na(V10[i, j, k, ])]) + - perCase[k] * fomArray[i, j]) + * (sum(V01[ip, jp, k + K1 - allAbn, !is.na(V01[ip, jp, k + K1 - allAbn, ])]) + - numKI01[K1 + k] * fomArray[ip, jp])) + } + } + } + } + } + s10 <- s10 * I10/(I10 - 1)/M + s01 <- s01 * I01/(I01 - 1)/N + s11 <- s11 * K/(K - 1) + S <- array(0, dim = c(I, I, J, J)) + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + S[i, ip, j, jp] <- s10[i, ip, j, jp]/M + s01[i, ip, j, jp]/N + s11[i, ip, j, jp]/(M * N) + s11[ip, i, jp, j]/(M * N) + } + } + } + } + } else { + # ROC + V10 <- array(dim = c(I, J, K2)) + V01 <- array(dim = c(I, J, K1)) + for (i in 1:I) { + for (j in 1:J) { + nl <- NL[i, j, 1:K1, ] + ll <- cbind(NL[i, j, (K1 + 1):K, ], LL[i, j, , ]) + dim(nl) <- c(K1, maxNL) + dim(ll) <- c(K2, maxNL + maxLL) + fp <- apply(nl, 1, max) + tp <- apply(ll, 1, max) + for (k in 1:K2) { + V10[i, j, k] <- (sum(fp < tp[k]) + 0.5 * sum(fp == tp[k]))/K1 + } + for (k in 1:K1) { + V01[i, j, k] <- (sum(fp[k] < tp) + 0.5 * sum(fp[k] == tp))/K2 + } + } + } + s10 <- array(dim = c(I, I, J, J)) + s01 <- array(dim = c(I, I, J, J)) + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + s10[i, ip, j, jp] <- sum((V10[i, j, ] - fomArray[i, j]) * (V10[ip, jp, ] - fomArray[ip, jp]))/(K2 - 1) + s01[i, ip, j, jp] <- sum((V01[i, j, ] - fomArray[i, j]) * (V01[ip, jp, ] - fomArray[ip, jp]))/(K1 - 1) + } + } + } + } + S <- s10/K2 + s01/K1 + } + + covariances <- S + Var <- 0 + count <- 0 + for (i in 1:I) { + for (j in 1:J) { + Var <- Var + covariances[i, i, j, j] + count <- count + 1 + } + } + if (count > 0) Var <- Var/count else Var <- 0 + + Cov1 <- 0 + count <- 0 + for (i in 1:I) { + for (ip in 1:I) { + for (j in 1:J) { + if (ip != i) { + Cov1 <- Cov1 + covariances[i, ip, j, j] + count <- count + 1 + } + } + } + } + if (count > 0) Cov1 <- Cov1/count else Cov1 <- 0 + + Cov2 <- 0 + count <- 0 + for (i in 1:I) { + for (j in 1:J) { + for (jp in 1:J) { + if (j != jp) { + Cov2 <- Cov2 + covariances[i, i, j, jp] + count <- count + 1 + } + } + } + } + if (count > 0) Cov2 <- Cov2/count else Cov2 <- 0 + + Cov3 <- 0 + count <- 0 + for (i in 1:I) { + for (ip in 1:I) { + if (i != ip) { + for (j in 1:J) { + for (jp in 1:J) { + if (j != jp) { + Cov3 <- Cov3 + covariances[i, ip, j, jp] + count <- count + 1 + } + } + } + } + } + } + if (count > 0) Cov3 <- Cov3/count else Cov3 <- 0 + + return(list( + Var = Var, + Cov1 = Cov1, + Cov2 = Cov2, + Cov3 = Cov3)) +} + diff --git a/R/ORAnalysisSplitPlot.R b/R/ORAnalysisSplitPlot.R deleted file mode 100644 index 5343c4e2..00000000 --- a/R/ORAnalysisSplitPlot.R +++ /dev/null @@ -1,491 +0,0 @@ -# implement formulae in Hillis 2014 appropriately modified for unequal -# numbers of readers in different treatments -# for split plot A design only -# TBA this code assumes two treatments -ORAnalysisSplitPlotA <- function(dataset, FOM, FPFValue, alpha = 0.05, analysisOption = "ALL") -{ - - if (dataset$descriptions$design != "SPLIT-PLOT-A") stop("This functions requires a SPLIT-PLOT-A dataset") - - I <- dim(dataset$ratings$NL)[1]; if (I != 2) stop(" ORAnalysisSplitPlotA assumes two treatments") - J <- dim(dataset$ratings$NL)[2] - modalityID <- dataset$descriptions$modalityID - - theta_ij <- as.matrix(UtilFigureOfMerit(dataset, FOM, FPFValue)) - - theta_i_dot <- array(dim = I) # average over readers, the indices are i followed by j - J_i <- array(dim = I) # number of readers in treatment i - for (i in 1:I) { - J_i[i] <- length(theta_ij[i,][!is.na(theta_ij[i,])]) - theta_i_dot[i] <- mean(theta_ij[i,][!is.na(theta_ij[i,])]) - } - theta_dot_dot <- mean(theta_i_dot) # average over rdrs and trts - - trtMeanDiffs <- theta_i_dot[1] - theta_i_dot[2] # restricted to two modalities for now - diffTRName <- paste0("trt", modalityID[1], sep = "-", "trt", modalityID[2]) - trtMeanDiffs_df <- data.frame("Estimate" = trtMeanDiffs, - row.names = diffTRName, - stringsAsFactors = FALSE) - - FOMs <- list( - foms = theta_ij, - trtMeans = theta_i_dot, - trtMeanDiffs = trtMeanDiffs_df - ) - - # msT denotes MS(T), in Hillis 2014 p 344 - msT <- 0 - for (i in 1:I) { - # adapted from Hillis 2014, definition of MS(T), just after Eqn. 4 - # move the treatment specific J_i[i] inside the i-summation showed there - msT <- msT + J_i[i]*(mean(theta_i_dot[i]) - theta_dot_dot)^2 - } - msT <- msT/(I - 1) # the common J used to appear here: J*msT/(I - 1) - - # following is needed for CI on avg. FOM, see below - # MS(R)_i = sum_j(theta_dot_j - theta_dot_dot)^2/(J_i-1) - msR_i <- array(0, dim = I) - for (i in 1:I) { - for (j in 1:J_i[i]) { - msR_i[i] <- msR_i[i] + - (mean(theta_ij[,j][!is.na(theta_ij[,j])]) - theta_dot_dot)^2 - # first term on rhs is theta_dot_j - } - msR_i <- msR_i / (J_i[i] - 1 ) - } - - # msR_T_ denotes MS[R(T)], in Hillis 2014 p 344, where R(T) is reader nested within treatment - # adapted from Hillis 2014, definition of MS[R(T)], last line on page 344 - # move the treatment specific J_i[i] inside the i-summation showed there - msR_T_ <- 0 - msR_T_i <- rep(0,I) - for (i in 1:I) { - for (j in 1:J) { - if (is.na(theta_ij[i, j])) next - msR_T_i[i] <- msR_T_i[i] + (theta_ij[i, j] - theta_i_dot[i])^2 / (J_i[i] - 1) - } - } - msR_T_ <- sum(msR_T_i) / I - - trtNames <- NULL - for (i in 1:I) { - trtNames <- c(trtNames, paste0("trt", modalityID[i])) - } - - ret1 <- UtilPseudoValues(dataset, FOM, FPFValue) - ret <- FOMijk2VarCovSpA(ret1$jkFomValues, varInflFactor = TRUE) - Var_i <- ret$Var_i - Cov2_i <- ret$Cov2_i - Cov3_i <- ret$Cov3_i - - ANOVA <- data.frame("msT" = c(msT, NA), - "msR" = msR_i, - "msR_T_" = msR_T_, - "Var_i" = Var_i, - "Cov2_i" = Cov2_i, - "Cov3_i" = Cov3_i, - stringsAsFactors = FALSE) - rownames(ANOVA) <- trtNames - - # now do the F_OR statistic; den = denominator of last equation on page 344 - # minus the MS[R(T)] term - # the contributions of the two reader groups have been separately added - den <- 0 - for (i in 1:I) den <- den + J_i[i] * max(Cov2_i[i]-Cov3_i[i],0) - F_OR <- msT/(msR_T_ + den) # add the the MS[R(T)] term to den - # Note: above expression reduces to equal-reader form - - # now implement the df3 formula on page 345 - # Assumption: degrees of freedom for each treatment can be added - df2 <- 0 - for (i in 1:I) { - # temp = num. of expression on r.h.s. of Eqn. 27, - # separated into contribution from each treatment - temp <- (msR_T_i[i] + J_i[i] * max(Cov2_i[i]-Cov3_i[i],0))^2 - # divide by the denominator and multiply by (J_i[i]-1) - # The I term is not needed, as we are summing contribution from each treatment - temp <- temp /(msR_T_i[i]^2)*(J_i[i]-1) - # cat("df2 for modality = ", temp, "\n") - # Add to df2 - df2 <- df2 + temp - } - # above expression reduces to equal-reader form - # note absence of I-factor on rhs - # because it is effectively "in there" due to the summation over i - - # compute the p-value - pValue <- 1 - pf(F_OR, I - 1, df2) - # F_OR_num_den = array with two elements, the numerator of the expression for - # F_OR followed by the denominator - # DF = degrees of freedom array, numerator followed by denominator - RRRC <- list() - RRRC$FTests <- data.frame(DF = c((I-1),df2), - "F_OR_num_den" = c(msT, msR_T_ + den), - FStat = c(F_OR, NA), - p = c(pValue, NA), - row.names = c("Treatment", "Error"), - stringsAsFactors = FALSE) - - # confidence intervals for difference FOM, trtMeanDiffs, - # as on page 346, first para; note that trtMeanDiffs = theta_1_dot - theta_2_dot - # l_1 = 1; l_2 = - 1 - # Note to myself: Hillis does not state a constraint on the l_i, namely they - # should sum to zero; otherwise one could use l_1 = l_2 = 1/2 and compute the CI - # on the average FOM using the very same method, which is not right - V_hat <- 0 - for (i in 1:I) { - V_hat <- V_hat + - (1 / J_i[i]) * 2 * (msR_T_i[i] + J_i[i] * max(Cov2_i[i]-Cov3_i[i],0)) - } - stdErr <- sqrt(V_hat) - - # again, this is restricted to two modalities - alpha <- 0.05 - CI <- sort(c(trtMeanDiffs - qt(alpha/2, df2) * stdErr, - trtMeanDiffs + qt(alpha/2, df2) * stdErr)) - RRRC$ciDiffTrt <- data.frame(Estimate = trtMeanDiffs, - StdErr = stdErr, - DF = df2, - CILower = CI[1], - CIUpper = CI[2], - row.names = "trt1-trt2", - stringsAsFactors = FALSE) - - # confidence intervals for average FOM, as on page 346, first para - # second method, using only data from each modality - V_hat_i <- array(0, dim = I) - df2_i <- array(dim = I) - stdErr_i <- array(dim = I) - ciAvgRdrEachTrt <- array(dim = c(I,2)) - ci <- data.frame() - for (i in 1:I) { - V_hat_i[i] <- { - V_hat_i[i] + - # this is the formula for V_hat_i[i] in the text area in the middle of page 346 - # after we account for the different number of readers in each treatment - (1 / J_i[i]) * (msR_i[i] + J_i[i] * max(Cov2_i[i],0)) - } - # this is the formula for df2_i[i] in the text area in the middle of page 346 - # after we account for the different number of readers in each treatment - df2_i[i] <- (msR_i[i] + J_i[i] * max(Cov2_i[i],0))^2/(msR_i[i]^2)*(J_i[i]-1) - stdErr_i[i] <- sqrt(V_hat_i[i]) - ciAvgRdrEachTrt[i,] <- sort(c(theta_i_dot[i] - qt(alpha/2, df2_i[i]) * stdErr_i[i], - theta_i_dot[i] + qt(alpha/2, df2_i[i]) * stdErr_i[i])) - rowName <- paste0("trt", modalityID[i]) - ci <- rbind(ci, data.frame(Estimate = theta_i_dot[i], - StdErr = stdErr_i[i], - DF = df2_i[i], - CILower = ciAvgRdrEachTrt[i,1], - CIUpper = ciAvgRdrEachTrt[i,2], - row.names = rowName, - stringsAsFactors = FALSE)) - } - RRRC$ciAvgRdrEachTrt <- ci - - return(list( - FOMs = FOMs, - ANOVA = ANOVA, - RRRC = RRRC - )) - -} - - - -ORAnalysisSplitPlotC <- function(dataset, FOM, FPFValue, alpha = 0.05, analysisOption = "ALL") -{ - - RRRC <- NULL - FRRC <- NULL - RRFC <- NULL - - modalityID <- dataset$descriptions$modalityID - I <- length(modalityID) - - # `as.matrix` is NOT absolutely necessary as `mean()` function is not used - foms <- UtilFigureOfMerit(dataset, FOM, FPFValue) - - ret <- ORVarComponentsSpC(dataset, FOM, FPFValue) - - TRanova <- ret$TRanova - VarCom <- ret$VarCom - IndividualTrt <- ret$IndividualTrt - IndividualRdr <- ret$IndividualRdr - - ANOVA <- list() - ANOVA$TRanova <- TRanova - ANOVA$VarCom <- VarCom - ANOVA$IndividualTrt <- IndividualTrt - ANOVA$IndividualRdr <- IndividualRdr - - trtMeans <- rowMeans(foms) - trtMeans <- as.data.frame(trtMeans) - colnames(trtMeans) <- "Estimate" - - trtMeanDiffs <- array(dim = choose(I, 2)) - diffTrtName <- array(dim = choose(I, 2)) - ii <- 1 - for (i in 1:I) { - if (i == I) - break - for (ip in (i + 1):I) { - trtMeanDiffs[ii] <- trtMeans[i,1] - trtMeans[ip,1] - diffTrtName[ii] <- paste0("trt", modalityID[i], sep = "-", "trt", modalityID[ip]) # !sic - ii <- ii + 1 - } - } - trtMeanDiffs <- data.frame("Estimate" = trtMeanDiffs, - row.names = diffTrtName, - stringsAsFactors = FALSE) - - FOMs <- list( - foms = foms, - trtMeans = trtMeans, - trtMeanDiffs = trtMeanDiffs - ) - - if (analysisOption == "RRRC") { - RRRC <- ORSummaryRRRC(dataset, FOMs, ANOVA, alpha, diffTrtName) - return(list( - FOMs = FOMs, - ANOVA = ANOVA, - RRRC = RRRC - )) - } - - if (analysisOption == "FRRC") { - FRRC <- ORSummaryFRRC(dataset, FOMs, ANOVA, alpha, diffTrtName) - return(list( - FOMs = FOMs, - ANOVA = ANOVA, - FRRC = FRRC - )) - } - - if (analysisOption == "RRFC") { - RRFC <- ORSummaryRRFC(dataset, FOMs, ANOVA, alpha, diffTrtName) - return(list( - FOMs = FOMs, - ANOVA = ANOVA, - RRFC = RRFC - )) - } - - if (analysisOption == "ALL") { - RRRC <- ORSummaryRRRC(dataset, FOMs, ANOVA, alpha, diffTrtName) - FRRC <- ORSummaryFRRC(dataset, FOMs, ANOVA, alpha, diffTrtName) - RRFC <- ORSummaryRRFC(dataset, FOMs, ANOVA, alpha, diffTrtName) - return(list( - FOMs = FOMs, - ANOVA = ANOVA, - RRRC = RRRC, - FRRC = FRRC, - RRFC = RRFC - )) - } else stop("Incorrect analysisOption: must be `RRRC`, `FRRC`, `RRFC` or `ALL`") - -} - - - -ORVarComponentsSpC <- function (dataset, FOM, FPFValue = 0.2) -{ - - if (dataset$descriptions$design != "SPLIT-PLOT-C") stop("This functions requires a SPLIT-PLOT-C dataset") - - I <- dim(dataset$ratings$NL)[1] - J <- dim(dataset$ratings$NL)[2] - - theta_ij <- as.matrix(UtilFigureOfMerit(dataset, FOM, FPFValue)) - - theta_dot_dot <- mean(theta_ij[,]) # this fails if `theta_ij` is a dataframe; true for `mean` and `median` - - if (I > 1) { - msT <- 0 - for (i in 1:I) { - msT <- msT + (mean(theta_ij[i, ]) - theta_dot_dot)^2 - } - msT <- J * msT/(I - 1) - } else msT <- NA - - if (J > 1) { - msR <- 0 - for (j in 1:J) { - msR <- msR + (mean(theta_ij[, j]) - theta_dot_dot)^2 - } - msR <- I * msR/(J - 1) - } else msR <- NA - - if ((I > 1) && (J > 1)) { - msTR <- 0 - for (i in 1:I) { - for (j in 1:J) { - msTR <- msTR + (theta_ij[i, j] - mean(theta_ij[i, ]) - mean(theta_ij[, j]) + theta_dot_dot)^2 - } - } - msTR <- msTR/((J - 1) * (I - 1)) - } else msTR <- NA - - msArray <- c(msT, msR, msTR) - dfArray <- c(I - 1, J - 1, (I - 1) * (J - 1)) - ssArray <- msArray * dfArray - - TRanova <- data.frame("SS" = ssArray, - "DF" = dfArray, - "MS" = msArray, - stringsAsFactors = FALSE) - rownames(TRanova) <- c("T", "R", "TR") - - # single treatment msR_i ############################################################ - if (J > 1) { - msR_i <- array(0, dim = I) - for (i in 1:I) { - for (j in 1:J) { - msR_i[i] <- msR_i[i] + (theta_ij[i, j] - mean(theta_ij[i,]))^2 - } - } - msR_i <- msR_i/(J - 1) - } else msR_i <- NA - - cov2EachTrt <- vector(length = I) - varEachTrt <- vector(length = I) - for (i in 1:I) { - dsi <- DfExtractDataset(dataset, trts = i) - ret <- OrVarCovMatrixSpC(dsi, FOM, FPFValue) - varEachTrt[i] <- ret$Var - cov2EachTrt[i] <- ret$Cov2 - } - - modID <- as.vector(dataset$descriptions$modalityID) - IndividualTrt <- data.frame(DF = rep(J-1, I), - msREachTrt = msR_i, - varEachTrt = varEachTrt, - cov2EachTrt = cov2EachTrt, - row.names = paste0("trt", modID), - stringsAsFactors = FALSE) - # } else IndividualTrt <- NA # these are not defined for split-plot-c datasets - - # single reader msT_j ############################################################### - if (I > 1) { - msT_j <- array(0, dim = J) - for (j in 1:J) { - for (i in 1:I) { - msT_j[j] <- msT_j[j] + (mean(theta_ij[i, j]) - mean(theta_ij[,j]))^2 - } - msT_j[j] <- msT_j[j]/(I - 1) - } - } else msT_j <- NA - - varEachRdr <- vector(length = J) - cov1EachRdr <- vector(length = J) - for (j in 1:J) { - dsj <- DfExtractDataset(dataset, rdrs = j) - ret <- OrVarCovMatrixSpC(dsj, FOM, FPFValue) - varEachRdr[j] <- ret$Var - cov1EachRdr[j] <- ret$Cov1 - } - - rdrID <- as.vector(dataset$descriptions$readerID) - if (I > 1) { - IndividualRdr <- data.frame(DF = rep(I-1, J), - msTEachRdr = msT_j, - varEachRdr = varEachRdr, - cov1EachRdr = cov1EachRdr, - row.names = paste0("rdr", rdrID), - stringsAsFactors = FALSE) - } else IndividualRdr <- NA - ##################################################################################### - ret <- OrVarCovMatrixSpC(dataset, FOM, FPFValue) - Var <- ret$Var - Cov1 <- ret$Cov1 - Cov2 <- ret$Cov2 - Cov3 <- ret$Cov3 - - if (I > 1) { - # Following equation is in marginal means paper, page 333 - # and in Hillis 2011 Eqn 9 - VarTR <- msTR - Var + Cov1 + max(Cov2 - Cov3, 0) - # NOTE on discrepancy between Var(R) and Var(TR) values reported by - # OR-DBM MRMC 2.51 Build 20181028 and my code for Franken dataset - # Their code does not implement the max() constraint while mine does - # my code reports VarTR = -0.00068389146 while their code reports - # VarTR = -0.00071276; This is shown explicitly next: - # msTR - Var + Cov1 + max(Cov2 - Cov3, 0) = -0.00068389146 - # msTR - Var + Cov1 + Cov2 - Cov3 = -0.00071276 - # This also affects the VarR values calculated next (see next block of comments) - # Cov1, Cov2, Cov3 and Var are the same between both codes - } else VarTR <- NA - - # See Hillis 2006 Table 1 2nd eauation - VarR <- (msR - VarTR - Var + Cov2 - (I-1)*(Cov1 - Cov3))/I - # Their code reports: VarR = 0.00003766 - # my code reports: VarR = 2.3319942e-05 - # This is shown explicitly next: - # (msR - Var - (I - 1) * Cov1 + Cov2 + (I - 1) * Cov3 - (-0.00071276))/I = 3.7754211e-05 - # (msR - Var - (I - 1) * Cov1 + Cov2 + (I - 1) * Cov3 - VarTR)/I = 2.3319942e-05 - VarCom <- data.frame(Estimates = c(VarR, VarTR, Cov1, Cov2, Cov3, Var), - Rhos = c(NA, NA, Cov1/Var, Cov2/Var, Cov3/Var, NA), - row.names = c("VarR", "VarTR", "Cov1", "Cov2", "Cov3", "Var"), - stringsAsFactors = FALSE) - return(list( - TRanova = TRanova, - VarCom = VarCom, - IndividualTrt = IndividualTrt, - IndividualRdr = IndividualRdr - )) - -} - - - -# select and retrieve covariance estimates according to value of `covEstMethod` -# works only for split plot C datasets -OrVarCovMatrixSpC <- function(dataset, FOM, FPFValue) -{ - if (dataset$descriptions$design != "SPLIT-PLOT-C") stop("This functions requires a split plot C dataset") - - ret <- varComponentsJackknifeSpC(dataset, FOM, FPFValue) - - return(ret) - -} - - - -varComponentsJackknifeSpC <- function(dataset, FOM, FPFValue) { - if (dataset$descriptions$design != "SPLIT-PLOT-C") stop("This functions requires a factorial dataset") - - I <- length(dataset$ratings$NL[,1,1,1]) - J <- length(dataset$ratings$NL[1,,1,1]) - - ret <- UtilPseudoValues(dataset, FOM, FPFValue) - Var <- array(dim = J) - Cov1 <- array(dim = J) - caseTransitions <- ret$caseTransitions - for (j in 1:J) { - jkFOMs <- ret$jkFomValues[,j,(caseTransitions[j]+1):(caseTransitions[j+1]), drop = FALSE] - kj <- length(jkFOMs)/I - dim(jkFOMs) <- c(I,1,kj) - x <- FOMijk2VarCov(jkFOMs, varInflFactor = FALSE) - # not sure which way to go: was doing this until 2/18/20 - # Var[j] <- x$Var * (K-1)^2/K - # Cov1[j] <- x$Cov1 * (K-1)^2/K - # following seems more reasonable as reader j only interprets kj cases - # updated file ~Dropbox/RJafrocChecks/StfrocSp.xlsx - Var[j] <- x$Var * (kj-1)^2/kj - Cov1[j] <- x$Cov1 * (kj-1)^2/kj - } - Cov <- list( - Var = mean(Var), - Cov1 = mean(Cov1), - Cov2 = 0, - Cov3 = 0 - ) - - return(Cov) - -} - - - - diff --git a/R/StORSummaryRRFC.R b/R/StORSummaryRRFC.R index 619ce869..fe09afab 100644 --- a/R/StORSummaryRRFC.R +++ b/R/StORSummaryRRFC.R @@ -15,12 +15,6 @@ ORSummaryRRFC <- function(dataset, FOMStats, ANOVA, alpha, diffTRName) { trtMeans <- FOMStats$trtMeans trtMeanDiffs <- FOMStats$trtMeanDiffs - # since IndividualTrt["Cov2","VarCom"] and IndividualTrt["Cov3","VarCom"] are zeroes for split-plot-c, FTests will be - # identical to FTestsRRRC; other values below may differ - # not sure about what is going one here; I am proceeding on assumption that - # the only difference is setting IndividualTrt["Cov2","VarCom"] = IndividualTrt["Cov3","VarCom"] = 0, and reusing code from crossed - # analysis - # (Results apply to the population of readers but only for the cases used in # this study) # diff --git a/R/StSignificanceTesting.R b/R/StSignificanceTesting.R index 57cb2ac0..0b47e976 100644 --- a/R/StSignificanceTesting.R +++ b/R/StSignificanceTesting.R @@ -1,4 +1,4 @@ -#' Performs DBM or OR significance testing for factorial or split-plot A,C datasets +#' Performs DBM or OR significance testing for factorial datasets #' #' @description Performs Dorfman-Berbaum-Metz (DBM) or Obuchowski-Rockette (OR) #' significance testing, for specified dataset; @@ -11,7 +11,7 @@ #' #' @param dataset The dataset to be analyzed, see \code{\link{RJafroc-package}}. #' Must have two or more treatments and two or more readers. The dataset design -#' can be "FCTRL", "SPLIT-PLOT-A" or "SPLIT-PLOT-C". +#' can be "FCTRL" or "FCTRL-X-MOD". #' #' @param FOM The figure of merit, see \code{\link{UtilFigureOfMerit}} #' @@ -22,10 +22,8 @@ #' treatment effects are zero; the default is 0.05 #' #' @param method The significance testing method to be used: -#' \code{"DBM"} (the default), representing the -#' Dorfman-Berbaum-Metz method or \code{"OR"}, representing the -#' Obuchowski-Rockette method. -#' and the Obuchowski-Rockette significance testing methods, respectively. +#' \code{"DBM"} representing the Dorfman-Berbaum-Metz method or \code{"OR"}, +#' the default, representing the Obuchowski-Rockette method. #' #' @param covEstMethod The covariance matrix estimation method #' in \code{ORH} analysis (for \code{method = "DBM"} the jackknife is always used). @@ -40,13 +38,15 @@ #' #' @param analysisOption Determines which factors are regarded as random vs. fixed: #' \itemize{ -#' \item \code{"RRRC"} = random-reader random case, +#' \item \code{"RRRC"} = random-reader random case, the default, #' \item \code{"FRRC"} = fixed-reader random case, #' \item \code{"RRFC"} = random-reader fixed case, -#' \item \code{"ALL"} = outputs results of \code{"RRRC"}, \code{"FRRC"} -#' and \code{"RRFC"} analyses - this is the default. +#' \item \code{"ALL"} = all allowed options. #' } #' +#' @param avgIndx For cross-modality analysis the modality-index to be averaged over. The +#' default is "NULL", i.e., not cross-modality analysis. +#' #' @return \strong{For \code{method = "DBM"} the returned list contains 4 dataframes:} #' @return \item{FOMs}{Contains \code{foms}, \code{trtMeans} and \code{trtMeanDiffs}: #' see return of \code{\link{UtilFigureOfMerit}}} @@ -73,17 +73,10 @@ #' @examples #' StSignificanceTesting(dataset02,FOM = "Wilcoxon", method = "DBM") #' StSignificanceTesting(dataset02,FOM = "Wilcoxon", method = "OR") -#' ## following is split-plot-c analysis using a simulated split-plot-c dataset -#' StSignificanceTesting(datasetFROCSpC, FOM = "wAFROC", method = "OR") #' #' \donttest{ #' StSignificanceTesting(dataset05, FOM = "wAFROC") #' StSignificanceTesting(dataset05, FOM = "HrAuc", method = "DBM") -#' StSignificanceTesting(dataset05, FOM = "SongA1", method = "DBM") -#' StSignificanceTesting(dataset05, FOM = "SongA2", method = "DBM") -#' StSignificanceTesting(dataset05, FOM = "wAFROC1", method = "DBM") -#' StSignificanceTesting(dataset05, FOM = "AFROC1", method = "DBM") -#' StSignificanceTesting(dataset05, FOM = "AFROC", method = "DBM") #' } #' #' @@ -108,11 +101,12 @@ #' #' #' @export -StSignificanceTesting <- function(dataset, FOM, FPFValue = 0.2, alpha = 0.05, method = "DBM", - covEstMethod = "jackknife", nBoots = 200, analysisOption = "ALL") +StSignificanceTesting <- function(dataset, FOM, FPFValue = 0.2, alpha = 0.05, method = "OR", + covEstMethod = "jackknife", nBoots = 200, + analysisOption = "ALL", avgIndx = NULL) { - - + + checkParameters(dataset, FOM, FPFValue, alpha, method, covEstMethod, nBoots, analysisOption) if (method == "DBM"){ @@ -125,15 +119,13 @@ StSignificanceTesting <- function(dataset, FOM, FPFValue = 0.2, alpha = 0.05, me return(ORAnalysisFactorial(dataset, FOM, FPFValue, alpha, covEstMethod, nBoots, analysisOption)) - } else if (dataset$descriptions$design == "SPLIT-PLOT-A") { + } else if (dataset$descriptions$design == "FCTRL-X-MOD") { - return(ORAnalysisSplitPlotA(dataset, FOM, FPFValue, alpha, analysisOption)) + if (is.null(avgIndx)) stop("For cross modality analysis avgIndx must be an integer.") - } else if (dataset$descriptions$design == "SPLIT-PLOT-C") { + return(ORAnalysisFactorialX(dataset, avgIndx, FOM, alpha, analysisOption)) - return(ORAnalysisSplitPlotC(dataset, FOM, FPFValue, alpha, analysisOption)) - - } else stop("Invalid study design: must be FCTRL, SPLIT-PLOT-A or SPLIT-PLOT-C") + } else stop("Invalid study design: must be FCTRL") } else { errMsg <- sprintf("%s is not a valid analysis method.", method) stop(errMsg) @@ -190,11 +182,6 @@ checkParameters <- function(dataset, FOM, FPFValue, alpha, method, } } else stop("Incorrect `method` argument: must be `DBM` or `OR`") - if (((dataset$descriptions$design == "SPLIT-PLOT-C") || (dataset$descriptions$design == "SPLIT-PLOT-A")) && method == "DBM") - stop("Must use method = ORH for SPLIT-PLOT-A or SPLIT-PLOT-C dataset") - - if (((dataset$descriptions$design == "SPLIT-PLOT-C") || (dataset$descriptions$design == "SPLIT-PLOT-A")) && method == "OR" && covEstMethod != "jackknife") - stop("Must use covEstMethod = jackknife for SPLIT-PLOT-A or SPLIT-PLOT-C dataset") - + } diff --git a/R/StSignificanceTestingCrossedModalities.R b/R/StSignificanceTestingCrossedModalities.R deleted file mode 100644 index 96addd3f..00000000 --- a/R/StSignificanceTestingCrossedModalities.R +++ /dev/null @@ -1,585 +0,0 @@ -#' Perform significance testing using crossed treatments analysis -#' -#' @description Performs ORH analysis for specified crossed treatments dataset -#' averaged over specified treatment factor -#' -#' -#' @param ds The crossed treatments dataset -#' @param avgIndx The index of the treatment to be averaged over -#' @param FOM See \code{\link{StSignificanceTesting}} -#' @param alpha See \code{\link{StSignificanceTesting}} -#' @param analysisOption See \code{\link{StSignificanceTesting}} -#' -#' @return A list containing the same objects as \code{\link{StSignificanceTesting}}. -#' -#' @examples -#' \donttest{ -#' ## read the built in dataset -#' retCrossed2 <- StSignificanceTestingCrossedModalities(datasetXModality, 1) -#' } -#' -#' @export -StSignificanceTestingCrossedModalities <- function(ds, avgIndx, FOM = "wAFROC", - alpha = 0.05, analysisOption = "ALL"){ - - if (ds$descriptions$design != "FCTRL-X-MOD") stop("Dataset is not factorial crossed modality") - - cat(sprintf("Averaging over modality index = %d\n\n", avgIndx)) - - options(stringsAsFactors = FALSE) - NL <- ds$ratings$NL - LL <- ds$ratings$LL - perCase <- ds$lesions$perCase - IDs <- ds$lesions$IDs - weights <- ds$lesions$weights - maxNL <- dim(NL)[5] - maxLL <- dim(LL)[5] - dataType <- ds$descriptions$type - if(avgIndx == 1){ - modalityID <- ds$descriptions$modalityID2 - }else{ - modalityID <- ds$descriptions$modalityID1 - } - readerID <- ds$descriptions$readerID - I <- length(modalityID) - J <- length(readerID) - K <- dim(NL)[4] - K2 <- dim(LL)[4] - K1 <- K - K2 - - if (!analysisOption %in% c("RRRC", "FRRC", "RRFC", "ALL")){ - errMsg <- sprintf("%s is not an available analysisOption.", analysisOption) - stop(errMsg) - } - - if (I < 2) { - stop("The analysis requires at least 2 treatments") - } - - ret <- EstimateVarCovCrossed(NL, LL, perCase, IDs, weights, maxNL, maxLL, FOM, avgIndx) - Var <- ret$Var - Cov1 <- ret$Cov1 - Cov2 <- ret$Cov2 - Cov3 <- ret$Cov3 - fomArray <- ret$fomArray # sic! 4/29/20 - trMeans <- rowMeans(fomArray) - fomMean <- mean(fomArray) - - msT <- 0 - for (i in 1:I) { - msT <- msT + (mean(fomArray[i, ]) - fomMean)^2 - } - msT <- J * msT/(I - 1) - - msR <- 0 - for (j in 1:J) { - msR <- msR + (mean(fomArray[, j]) - fomMean)^2 - } - msR <- I * msR/(J - 1) - - msTR <- 0 - for (i in 1:I) { - for (j in 1:J) { - msTR <- msTR + (fomArray[i, j] - mean(fomArray[i, ]) - mean(fomArray[, j]) + fomMean)^2 - } - } - msTR <- msTR/((J - 1) * (I - 1)) - - # TBA need citations here - varTR <- msTR - Var + Cov1 + max(Cov2 - Cov3, 0) - varR <- (msR - Var - (I - 1) * Cov1 + Cov2 + (I - 1) * Cov3 - varTR)/I - varCovArray <- c(varR, varTR, Cov1, Cov2, Cov3, Var) - nameArray <- c("Var(R)", "Var(T*R)", "COV1", "COV2", "COV3", "Var(Error)") - varComp <- data.frame(varCov = varCovArray, - row.names = nameArray, - stringsAsFactors = FALSE) - - varSingle <- vector(length = I) - cov2Single <- vector(length = I) - for (i in 1:I) { - if (avgIndx == 1){ - nl <- NL[ , i, , , ] - ll <- LL[ , i, , , ] - dim(nl) <- c(length(ds$descriptions$modalityID1), 1, J, K, maxNL) - dim(ll) <- c(length(ds$descriptions$modalityID1), 1, J, K2, max(perCase)) - }else{ - nl <- NL[ i, , , , ] - ll <- LL[ i, , , , ] - dim(nl) <- c(1, length(ds$descriptions$modalityID2), J, K, maxNL) - dim(ll) <- c(1, length(ds$descriptions$modalityID2), J, K2, max(perCase)) - } - - - ret <- EstimateVarCovCrossed(nl, ll, perCase, IDs, weights, maxNL, maxLL, FOM, avgIndx) - varSingle[i] <- ret$Var - if (J > 1) { - cov2Single[i] <- ret$Cov2 - } else { - cov2Single[i] <- 0 - } - } - - varEchRder <- vector(length = J) - cov1EchRder <- vector(length = J) - for (j in 1:J) { - nl <- NL[ , , j, , ] - ll <- LL[ , , j, , ] - dim(nl) <- c(length(ds$descriptions$modalityID1), length(ds$descriptions$modalityID2), 1, K, maxNL) - dim(ll) <- c(length(ds$descriptions$modalityID1), length(ds$descriptions$modalityID2), 1, K2, max(perCase)) - ret <- EstimateVarCovCrossed(nl, ll, perCase, IDs, weights, maxNL, maxLL, FOM, avgIndx) - varEchRder[j] <- ret$Var - cov1EchRder[j] <- ret$Cov1 - } - - msRSingle <- array(0, dim = c(I)) - for (i in 1:I) { - msRSingle[i] <- sum((fomArray[i, ] - trMeans[i])^2)/(J - 1) - } - - diffTRMeans <- array(dim = choose(I, 2)) - diffTRName <- array(dim = choose(I, 2)) - ii <- 1 - for (i in 1:I) { - if (i == I) - break - for (ip in (i + 1):I) { - diffTRMeans[ii] <- trMeans[i] - trMeans[ip] - diffTRName[ii] <- paste(modalityID[i], modalityID[ip], sep = "-") - ii <- ii + 1 - } - } - - msNum <- msT - - # ************ RRRC **************** - if (analysisOption %in% c("RRRC", "ALL")) { - if (J > 1) { - msDenRRRC <- msTR + max(J * (Cov2 - Cov3), 0) - fRRRC <- msNum/msDenRRRC - ddfRRRC <- msDenRRRC^2/(msTR^2/((I - 1) * (J - 1))) - pRRRC <- 1 - pf(fRRRC, I - 1, ddfRRRC) - stdErrRRRC <- sqrt(2 * msDenRRRC/J) - tStat <- vector() - tPr <- vector() - CIRRRC <- array(dim = c(length(diffTRMeans), 2)) - for (i in 1:length(diffTRMeans)) { - tStat[i] <- diffTRMeans[i]/stdErrRRRC - tPr[i] <- 2 * pt(abs(tStat[i]), ddfRRRC, lower.tail = FALSE) - ci <- sort(c(diffTRMeans[i] - qt(alpha/2, ddfRRRC) * stdErrRRRC, - diffTRMeans[i] + qt(alpha/2, ddfRRRC) * stdErrRRRC)) - if (length(ci) == 0){ - CIRRRC[i, ] <- c(NA, NA) - }else{ - CIRRRC[i, ] <- ci - } - } - # This code was failing on oldrelease R v3.5.3 under test context("StSignificanceTestingCrossedModalities") - # The outputs for ciDiffTrtRRRC were not equal for goodvalues and currentvalues - # forcing original order to be kept - - for (i in (1:length(diffTRName))) { - diffTRName[i] <- paste0(paste0("Row",i,"_"),diffTRName[i]) - } - - attributes(diffTRName) <- NULL #statement #1a - attributes(diffTRMeans) <- NULL #statement #1b - - ciDiffTrtRRRC <- data.frame(Treatment = diffTRName, - Estimate = diffTRMeans, - StdErr = rep(stdErrRRRC, choose(I, 2)), - DF = rep(ddfRRRC, choose(I, 2)), - t = tStat, - PrGTt = tPr, - CILower = CIRRRC[,1], - CIUpper = CIRRRC[,2], - stringsAsFactors = FALSE) - - # print(attributes(ciDiffTrtRRRC)) - # print(attributes(ciDiffTrtRRRC$Treatment)) - # print(attributes(ciDiffTrtRRRC$Estimate)) - # print(class(ciDiffTrtRRRC$Treatment)) - ################################################################################ - # this whole issue could be a git problem of not updating a regenerated new good value - # I had to do two commits followed by push: one with file deleted and one with file regenerated. - # Then all travis releases worked; - # if statements #1,ab IS commented - # $names - # [1] "Treatment" "Estimate" "StdErr" "DF" "t" "PrGTt" "CILower" "CIUpper" - # - # $class - # [1] "data.frame" - # - # $row.names - # [1] 1 2 3 4 5 6 - # - # NULL - # NULL - # [1] "character" - - # if statements #1,ab is NOT commented - # $names - # [1] "Treatment" "Estimate" "StdErr" "DF" "t" "PrGTt" "CILower" "CIUpper" - # - # $class - # [1] "data.frame" - # - # $row.names - # [1] 1 2 3 4 5 6 - # - # $levels - # [1] "Row1_20-40" "Row2_20-60" "Row3_20-80" "Row4_40-60" "Row5_40-80" "Row6_60-80" - # - # $class - # [1] "factor" - # - # NULL - # [1] "factor" - ################################################################################ - - dfSingleRRRC <- array(dim = I) - msDenSingleRRRC <- array(dim = I) - stdErrSingleRRRC <- array(dim = I) - CISingleRRRC <- array(dim = c(I, 2)) - for (i in 1:I) { - msDenSingleRRRC[i] <- msRSingle[i] + max(J * cov2Single[i], 0) - dfSingleRRRC[i] <- msDenSingleRRRC[i]^2/msRSingle[i]^2 * (J - 1) - stdErrSingleRRRC[i] <- sqrt(msDenSingleRRRC[i]/J) - ci <- sort(c(trMeans[i] - qt(alpha/2, dfSingleRRRC[i]) * stdErrSingleRRRC[i], trMeans[i] + qt(alpha/2, dfSingleRRRC[i]) * stdErrSingleRRRC[i])) - if (length(ci) == 0){ - CISingleRRRC[i, ] <- c(NA, NA) - }else{ - CISingleRRRC[i, ] <- ci - } - - } - ciAvgRdrEachTrtRRRC <- data.frame(Treatment = modalityID, - Area = trMeans, - StdErr = as.vector(stdErrSingleRRRC), - DF = as.vector(dfSingleRRRC), - CILower = CISingleRRRC[,1], - CIUpper = CISingleRRRC[,2], - stringsAsFactors = FALSE) - - } else { - fRRRC <- NA - ddfRRRC <- NA - pRRRC <- NA - ciDiffTrtRRRC <- NA - ciAvgRdrEachTrtRRRC <- NA - } - if (analysisOption == "RRRC"){ - return(list(fomArray = fomArray, - msT = msT, - msTR = msTR, - varComp = varComp, - fRRRC = fRRRC, - ddfRRRC = ddfRRRC, - pRRRC = pRRRC, - ciDiffTrtRRRC = ciDiffTrtRRRC, - ciAvgRdrEachTrtRRRC = ciAvgRdrEachTrtRRRC) - ) - } - } - - # ************ FRRC **************** - if (analysisOption %in% c("FRRC", "ALL")) { - if (J > 1) { - msDenFRRC <- Var - Cov1 + (J - 1) * (Cov2 - Cov3) - } else { - msDenFRRC <- Var - Cov1 - } - fFRRC <- msNum/msDenFRRC - ddfFRRC <- Inf - pFRRC <- 1 - pf(fFRRC, I - 1, ddfFRRC) - stdErrFRRC <- sqrt(2 * msDenFRRC/J) - tStat <- vector() - tPr <- vector() - CIFRRC <- array(dim = c(length(diffTRMeans), 2)) - for (i in 1:length(diffTRMeans)) { - tStat[i] <- diffTRMeans[i]/stdErrFRRC - tPr[i] <- 2 * pt(abs(tStat[i]), ddfFRRC, lower.tail = FALSE) - CIFRRC[i, ] <- sort(c(diffTRMeans[i] - qt(alpha/2, ddfFRRC) * stdErrFRRC, - diffTRMeans[i] + qt(alpha/2, ddfFRRC) * stdErrFRRC)) - } - # for (i in (1:length(diffTRName))) { - # diffTRName[i] <- paste0(paste0("Row",i,"-"),diffTRName[i]) - # } - ciDiffTrtFRRC <- data.frame(Treatment = diffTRName, - Estimate = diffTRMeans, - StdErr = rep(stdErrFRRC, choose(I, 2)), - DF = rep(ddfFRRC, choose(I, 2)), - t = tStat, - PrGTt = tPr, - CILower = CIFRRC[,1], - CIUpper = CIFRRC[,2], - stringsAsFactors = FALSE) - - # colnames(ciDiffTrtFRRC) <- c("Treatment", "Estimate", "StdErr", "DF", "t", "PrGTt", "CILower", "CIUpper") - - dfSingleFRRC <- array(dim = I) - msDenSingleFRRC <- array(dim = I) - stdErrSingleFRRC <- array(dim = I) - CISingleFRRC <- array(dim = c(I, 2)) - for (i in 1:I) { - msDenSingleFRRC[i] <- varSingle[i] + (J - 1) * cov2Single[i] - dfSingleFRRC[i] <- Inf - stdErrSingleFRRC[i] <- sqrt(msDenSingleFRRC[i]/J) - CISingleFRRC[i, ] <- sort(c(trMeans[i] - qt(alpha/2, dfSingleFRRC[i]) * stdErrSingleFRRC[i], trMeans[i] + qt(alpha/2, dfSingleFRRC[i]) * stdErrSingleFRRC[i])) - } - ciAvgRdrEachTrtFRRC <- data.frame(Treatment = modalityID, - Area = trMeans, - StdErr = as.vector(stdErrSingleFRRC), - DF = as.vector(dfSingleFRRC), - CILower = CISingleFRRC[,1], - CIUpper = CISingleFRRC[,2], - row.names = NULL, - stringsAsFactors = FALSE) - - #colnames(ciAvgRdrEachTrtFRRC) <- c("Treatment", "Area", "StdErr", "DF", "CILower", "CIUpper") - - diffTRMeansFRRC <- array(dim = c(J, choose(I, 2))) - for (j in 1:J) { - ii <- 1 - for (i in 1:I) { - if (i == I) - break - for (ip in (i + 1):I) { - diffTRMeansFRRC[j, ii] <- fomArray[i, j] - fomArray[ip, j] - ii <- ii + 1 - } - } - } - - diffTRMeansFRRC <- as.vector(t(diffTRMeansFRRC)) - stdErrFRRC <- sqrt(2 * (varEchRder - cov1EchRder)) - stdErrFRRC <- rep(stdErrFRRC, choose(I, 2)) - dim(stdErrFRRC) <- c(J, choose(I, 2)) - stdErrFRRC <- as.vector(t(stdErrFRRC)) - readerNames <- rep(readerID, choose(I, 2)) - dim(readerNames) <- c(J, choose(I, 2)) - readerNames <- as.vector(t(readerNames)) - trNames <- rep(diffTRName, J) - dfReaderFRRC <- rep(Inf, length(stdErrFRRC)) - CIReaderFRRC <- array(dim = c(length(stdErrFRRC), 2)) - tStat <- vector() - tPr <- vector() - for (n in 1:length(stdErrFRRC)) { - tStat[n] <- diffTRMeansFRRC[n]/stdErrFRRC[n] - tPr[n] <- 2 * pt(abs(tStat[n]), dfReaderFRRC[n], lower.tail = FALSE) - CIReaderFRRC[n, ] <- sort(c(diffTRMeansFRRC[n] - qt(alpha/2, dfReaderFRRC[n]) * stdErrFRRC[n], diffTRMeansFRRC[n] + qt(alpha/2, dfReaderFRRC[n]) * stdErrFRRC[n])) - } - ciDiffTrtEachRdr <- data.frame(Reader = readerNames, - Treatment = trNames, - Estimate = diffTRMeansFRRC, - StdErr = as.vector(stdErrFRRC), - DF = as.vector(dfReaderFRRC), - t = tStat, - PrGTt = tPr, - CILower = CIReaderFRRC[,1], - CIUpper = CIReaderFRRC[,2], - stringsAsFactors = FALSE) - # 5/4/20 removing all this as I better understand data.frame() - - #colnames(ciDiffTrtEachRdr) <- c("Reader", "Treatment", "Estimate", "StdErr", "DF", "t", "PrGTt", "CILower", "CIUpper") - - varCovEachRdr <- data.frame(readerID, - varEchRder, - cov1EchRder, - stringsAsFactors = FALSE) - colnames(varCovEachRdr) <- c("Reader", "Var", "Cov1") - if (analysisOption == "FRRC"){ - return(list(fomArray = fomArray, msT = msT, msTR = msTR, varComp = varComp, - fFRRC = fFRRC, ddfFRRC = ddfFRRC, pFRRC = pFRRC, ciDiffTrtFRRC = ciDiffTrtFRRC, ciAvgRdrEachTrtFRRC = ciAvgRdrEachTrtFRRC, ciDiffTrtEachRdr = ciDiffTrtEachRdr, varCovEachRdr = varCovEachRdr - )) - } - } - - # ************ RRFC **************** - if (analysisOption %in% c("RRFC", "ALL")) { - if (J > 1) { - msDenRRFC <- msTR - fRRFC <- msNum/msDenRRFC - ddfRRFC <- ((I - 1) * (J - 1)) - pRRFC <- 1 - pf(fRRFC, I - 1, ddfRRFC) - stdErrRRFC <- sqrt(2 * msDenRRFC/J) - tStat <- vector() - tPr <- vector() - CIRRFC <- array(dim = c(length(diffTRMeans), 2)) - for (i in 1:length(diffTRMeans)) { - tStat[i] <- diffTRMeans[i]/stdErrRRFC - tPr[i] <- 2 * pt(abs(tStat[i]), ddfRRFC, lower.tail = FALSE) - CIRRFC[i, ] <- sort(c(diffTRMeans[i] - qt(alpha/2, ddfRRFC) * stdErrRRFC, - diffTRMeans[i] + qt(alpha/2, ddfRRFC) * stdErrRRFC)) - } - - # for (i in (1:length(diffTRName))) { - # diffTRName[i] <- paste0(paste0("Row",i,"-"),diffTRName[i]) - # } - ciDiffTrtRRFC <- data.frame(Treatment = diffTRName, - Estimate = diffTRMeans, - StdErr = rep(stdErrRRFC, choose(I, 2)), - DF = rep(ddfRRFC, choose(I, 2)), - t = tStat, - PrGTt = tPr, - CILower = CIRRFC[,1], - CIUpper = CIRRFC[,2], - stringsAsFactors = FALSE) - # 5/4/20 removing all this as I better understand data.frame() - - #colnames(ciDiffTrtRRFC) <- c("Treatment", "Estimate", "StdErr", "DF", "t", "PrGTt", "CILower", "CIUpper") - - dfSingleRRFC <- array(dim = I) - msDenSingleRRFC <- array(dim = I) - stdErrSingleRRFC <- array(dim = I) - CISingleRRFC <- array(dim = c(I, 2)) - for (i in 1:I) { - msDenSingleRRFC[i] <- msRSingle[i] - dfSingleRRFC[i] <- (J - 1) - stdErrSingleRRFC[i] <- sqrt(msDenSingleRRFC[i]/J) - CISingleRRFC[i, ] <- sort(c(trMeans[i] - qt(alpha/2, dfSingleRRFC[i]) * stdErrSingleRRFC[i], trMeans[i] + qt(alpha/2, dfSingleRRFC[i]) * stdErrSingleRRFC[i])) - } - ciAvgRdrEachTrtRRFC <- data.frame(Treatment = modalityID, - Area = trMeans, - StdErr = as.vector(stdErrSingleRRFC), - DF = as.vector(dfSingleRRFC), - CILower = CISingleRRFC[,1], - CIUpper = CISingleRRFC[,2], - row.names = NULL, - stringsAsFactors = FALSE) - - #colnames(ciAvgRdrEachTrtRRFC) <- c("Treatment", "Area", "StdErr", "DF", "CILower", "CIUpper") - } else { - fRRFC <- NA - ddfRRFC <- NA - pRRFC <- NA - ciDiffTrtRRFC <- NA - ciAvgRdrEachTrtRRFC <- NA - } - if (analysisOption == "RRFC"){ - return(list(fomArray = fomArray, msT = msT, msTR = msTR, varComp = varComp, - fRRFC = fRRFC, ddfRRFC = ddfRRFC, pRRFC = pRRFC, ciDiffTrtRRFC = ciDiffTrtRRFC, ciAvgRdrEachTrtRRFC = ciAvgRdrEachTrtRRFC)) - } - } - - return(list( - fomArray = fomArray, - msT = msT, - msTR = msTR, - varComp = varComp, - fRRRC = fRRRC, - ddfRRRC = ddfRRRC, - pRRRC = pRRRC, - ciDiffTrtRRRC = ciDiffTrtRRRC, - ciAvgRdrEachTrtRRRC = ciAvgRdrEachTrtRRRC, - fFRRC = fFRRC, - ddfFRRC = ddfFRRC, - pFRRC = pFRRC, - ciDiffTrtFRRC = ciDiffTrtFRRC, - ciAvgRdrEachTrtFRRC = ciAvgRdrEachTrtFRRC, - ciDiffTrtEachRdr = ciDiffTrtEachRdr, - varCovEachRdr = varCovEachRdr, - fRRFC = fRRFC, - ddfRRFC = ddfRRFC, - pRRFC = pRRFC, - ciDiffTrtRRFC = ciDiffTrtRRFC, - ciAvgRdrEachTrtRRFC = ciAvgRdrEachTrtRRFC)) -} - - -#' @importFrom stats cov -#' -EstimateVarCovCrossed <- function(NL, LL, perCase, IDs, weights, maxNL, maxLL, FOM, avgIndx) { - UNINITIALIZED <- RJafrocEnv$UNINITIALIZED - I1 <- dim(NL)[1] - I2 <- dim(NL)[2] - J <- dim(NL)[3] - K <- dim(NL)[4] - K2 <- dim(LL)[4] - - K1 <- K - K2 - if (FOM %in% c("MaxNLF", "ExpTrnsfmSp", "HrSp")) { - jkFOMArray <- array(dim = c(I1, I2, J, K1)) - for (i1 in 1:I1) { - for (i2 in 1:I2) { - for (j in 1:J) { - for (k in 1:K1) { - nl <- NL[i1, i2, j, -k, ] - ll <- LL[i1, i2, j, , ] - dim(nl) <- c(K - 1, maxNL) - dim(ll) <- c(K2, max(perCase)) - jkFOMArray[i1, i2, j, k] <- MyFom_ij(nl, ll, perCase, IDs, weights, maxNL, maxLL, K1 - 1, K2, FOM) - } - } - } - } - } else if (FOM %in% c("MaxLLF", "HrSe")) { - jkFOMArray <- array(dim = c(I1, I2, J, K2)) - for (i1 in 1:I1) { - for (i2 in 1:I2) { - for (j in 1:J) { - for (k in 1:K2) { - nl <- NL[i1, i2, j, -(k + K1), ] - ll <- LL[i1, i2, j, -k, ] - dim(nl) <- c(K - 1, maxNL) - dim(ll) <- c(K2 - 1, max(perCase)) - lesionIDJk <- IDs[-k, ] - dim(lesionIDJk) <- c(K2 -1, max(perCase)) - lesionWeightJk <- weights[-k, ] - dim(lesionWeightJk) <- c(K2 -1, max(perCase)) - jkFOMArray[i1, i2, j, k] <- MyFom_ij(nl, ll, perCase[-k], lesionIDJk, lesionWeightJk, maxNL, maxLL, K1, K2 - 1, FOM) - } - } - } - } - } else { - jkFOMArray <- array(dim = c(I1, I2, J, K)) - for (i1 in 1:I1) { - for (i2 in 1:I2) { - for (j in 1:J) { - for (k in 1:K) { - if (k <= K1) { - nl <- NL[i1, i2, j, -k, ] - ll <- LL[i1, i2, j, , ] - dim(nl) <- c(K - 1, maxNL) - dim(ll) <- c(K2, max(perCase)) - jkFOMArray[i1, i2, j, k] <- MyFom_ij(nl, ll, perCase, IDs, weights, maxNL, maxLL, K1 - 1, K2, FOM) - } else { - nl <- NL[i1, i2, j, -k, ] - ll <- LL[i1, i2, j, -(k - K1), ] - dim(nl) <- c(K - 1, maxNL) - dim(ll) <- c(K2 - 1, max(perCase)) - lesionIDJk <- IDs[-(k - K1), ] - dim(lesionIDJk) <- c(K2 -1, max(perCase)) - lesionWeightJk <- weights[-(k - K1), ] - dim(lesionWeightJk) <- c(K2 -1, max(perCase)) - jkFOMArray[i1, i2, j, k] <- MyFom_ij(nl, ll, perCase[-(k - K1)], lesionIDJk, lesionWeightJk, maxNL, maxLL, K1, K2 - 1, FOM) - } - } - } - } - } - } - - K <- length(jkFOMArray[1, 1, 1, ]) - if (avgIndx == 1){ - jkFOMArray <- apply(jkFOMArray, c(2, 3, 4), mean) - fomArray <- apply(jkFOMArray, c(1, 2), mean) - }else{ - jkFOMArray <- apply(jkFOMArray, c(1, 3, 4), mean) - fomArray <- apply(jkFOMArray, c(1, 2), mean) - } - - Cov <- FOMijk2VarCov(jkFOMArray, varInflFactor = TRUE) - Var <- Cov$Var - Cov1 <- Cov$Cov1 - Cov2 <- Cov$Cov2 - Cov3 <- Cov$Cov3 - - return(list( - Var = Var, - Cov1 = Cov1, - Cov2 = Cov2, - Cov3 = Cov3, - fomArray = fomArray - )) -} diff --git a/R/UtilFigureOfMerit.R b/R/UtilFigureOfMerit.R index 6a10941d..c62b39ad 100644 --- a/R/UtilFigureOfMerit.R +++ b/R/UtilFigureOfMerit.R @@ -15,8 +15,6 @@ #' @details The allowed FOMs depend on the \code{dataType} field of the #' \code{dataset} object. #' -#' \strong{For \code{dataset$descriptions$design = "SPLIT-PLOT-C"}, end-point based -#' FOMs (e.g., "MaxLLF") are not allowed}. #' \strong{For \code{dataset$descriptions$type = "ROC"} only \code{FOM = "Wilcoxon"} is allowed}. #' \strong{For \code{dataset$descriptions$type = "FROC"} the following FOMs are allowed}: #' \itemize{ @@ -90,7 +88,6 @@ #' @importFrom dplyr between #' @export -# v.1.3.1.9000: added SPLIT-PLOT-C capability UtilFigureOfMerit <- function(dataset, FOM = "wAFROC", FPFValue = 0.2) { # dpc dataType <- dataset$descriptions$type @@ -158,49 +155,13 @@ UtilFigureOfMerit <- function(dataset, FOM = "wAFROC", FPFValue = 0.2) { # dpc fomArray <- array(dim = c(I, J)) for (i in 1:I) { for (j in 1:J) { - if (design == "SPLIT-PLOT-A") { - if (all(is.na(t[i,j,,1]))) next # if t[] for all normal cases for selected i,j are NAs, skip - if (all(is.na(t[i,j,,2]))) next # if t[] for all abnormal cases for selected i,j are NAs, skip - k1_ij_sub <- !is.na(t[i,j,,1]) | !is.na(t[i,j,,2]) # see comments for SPLIT-PLOT-C - k2_ij_sub <- !is.na(t[i,j,,2])[(K1+1):K] # ditto: - nl_ij <- NL[i, j, k1_ij_sub, ] - perCase_ij <- dataset$lesions$perCase[k2_ij_sub] - maxLL_ij <- max(perCase_ij) - ll_ij <- LL[i, j, k2_ij_sub, 1:maxLL_ij] - k1ij <- sum(!is.na(t[i,j,,1])) - k2ij <- sum(!is.na(t[i,j,,2])) - lID_ij <- dataset$lesions$IDs[k2_ij_sub,1:maxLL_ij, drop = FALSE] - lW_ij <- dataset$lesions$weights[k2_ij_sub,1:maxLL_ij, drop = FALSE] - dim(nl_ij) <- c(k1ij+k2ij, maxNL) - dim(ll_ij) <- c(k2ij, maxLL_ij) - fomArray[i, j] <- MyFom_ij(nl_ij, ll_ij, perCase_ij, lID_ij, lW_ij, maxNL, maxLL_ij, k1ij, k2ij, FOM, FPFValue) - next - } else if (design == "SPLIT-PLOT-C") { - if (all(is.na(t[i,j,,1]))) next # if t[] for all normal cases for selected i,j are NAs, skip - if (all(is.na(t[i,j,,2]))) next # if t[] for all abnormal cases for selected i,j are NAs, skip - # k1 refers to normal case k-indices - # k2 refers to abnormal case k-indices - k1_ij_sub <- !is.na(t[i,j,,1]) | !is.na(t[i,j,,2]) # k1-indices of all cases meeting the i,j criteria - k2_ij_sub <- !is.na(t[i,j,,2])[(K1+1):K] # k2-indices of all cases meeting the i,j criteria - nl_ij <- NL[i, j, k1_ij_sub, ] # NL ratings for all cases meeting the i,j criteria - perCase_ij <- dataset$lesions$perCase[k2_ij_sub] # perCase indices for all abnormal cases meeting the i,j criteria - maxLL_ij <- max(perCase_ij) - ll_ij <- LL[i, j, k2_ij_sub, 1:maxLL_ij] - k1ij <- sum(!is.na(t[i,j,,1])) - k2ij <- sum(!is.na(t[i,j,,2])) - lID_ij <- dataset$lesions$IDs[k2_ij_sub,1:maxLL_ij, drop = FALSE] - lW_jj <- dataset$lesions$weights[k2_ij_sub,1:maxLL_ij, drop = FALSE] - dim(nl_ij) <- c(k1ij+k2ij, maxNL) - dim(ll_ij) <- c(k2ij, maxLL_ij) - fomArray[i, j] <- MyFom_ij(nl_ij, ll_ij, perCase_ij, lID_ij, lW_jj, maxNL, maxLL_ij, k1ij, k2ij, FOM, FPFValue) - next - } else if (design == "FCTRL"){ + if (design == "FCTRL"){ nl_ij <- NL[i, j, , ] ll_ij <- LL[i, j, , ] dim(nl_ij) <- c(K, maxNL) dim(ll_ij) <- c(K2, maxLL) fomArray[i, j] <- MyFom_ij(nl_ij, ll_ij, dataset$lesions$perCase, dataset$lesions$IDs, dataset$lesions$weights, maxNL, maxLL, K1, K2, FOM, FPFValue) - } else stop("Incorrect design, must be SPLIT-PLOT-A, SPLIT-PLOT-C or FCTRL") + } else stop("Incorrect design, must beFCTRL") } } @@ -209,7 +170,6 @@ UtilFigureOfMerit <- function(dataset, FOM = "wAFROC", FPFValue = 0.2) { # dpc rownames(fomArray) <- paste("trt", sep = "", modalityID) colnames(fomArray) <- paste("rdr", sep = "", readerID) return(as.data.frame(fomArray)) - #return(data.matrix(as.data.frame(fomArray))) causes tests to fail -} + } diff --git a/R/UtilFigureOfMeritX.R b/R/UtilFigureOfMeritX.R new file mode 100644 index 00000000..22cad85e --- /dev/null +++ b/R/UtilFigureOfMeritX.R @@ -0,0 +1,126 @@ +#' Calculate empirical figures of merit for cross-modality dataset +#' +#' @description Calculate the specified empirical figure of merit +#' for each treatment-reader combination in the cross-modality dataset +#' +#' @param dsX The cross-modality dataset to be analyzed +#' +#' @param FOM The figure of merit; the default is \code{"wAFROC"} +#' +#' @return A \code{c(I1, I2, J)} data frame, where the row names are \code{modalityID}'s of the +#' treatments and column names are the \code{readerID}'s of the readers. +#' +#' @details The allowed FOMs depend on the \code{dataType} field of the +#' \code{dataset} object. +#' +#' \strong{For \code{dataset$descriptions$type = "ROC"} only \code{FOM = "Wilcoxon"} is allowed}. +#' \strong{For \code{dataset$descriptions$type = "FROC"} the following FOMs are allowed}: +#' \itemize{ +#' \item \code{FOM = "AFROC1"} (use only if zero normal cases) +#' \item \code{FOM = "AFROC"} +#' \item \code{FOM = "wAFROC1"} (use only if zero normal cases) +#' \item \code{FOM = "wAFROC"} (the default) +#' \item \code{FOM = "HrAuc"} +#' \item \code{FOM = "SongA1"} +#' \item \code{FOM = "SongA2"} +#' \item \code{FOM = "HrSe"} (an example of an end-point based FOM) +#' \item \code{FOM = "HrSp"} (another example) +#' \item \code{FOM = "MaxLLF"} (do:) +#' \item \code{FOM = "MaxNLF"} (do:) +#' \item \code{FOM = "MaxNLFAllCases"} (do:) +#' \item \code{FOM = "ExpTrnsfmSp"} +#' } +#' \code{"MaxLLF"}, \code{"MaxNLF"} and \code{"MaxNLFAllCases"} +#' correspond to ordinate, and abscissa, respectively, of the highest point +#' on the FROC operating characteristic obtained by counting all the marks. +#' The \code{"ExpTrnsfmSp"} FOM is described in the paper by Popescu. +#' Given the large number of FOMs possible with FROC data, it is appropriate +#' to make a recommendation: \strong{it is recommended that one use the wAFROC FOM +#' whenever possible. If the dataset has no non-diseased cases one should use the +#' the wAFROC1 FOM}. +#' +#' +#' +#' @examples +#' +#' ##UtilFigureOfMeritX(datasetXModality, FOM = "wAFROC") +#' +#' +#' @references +#' Chakraborty DP (2017) \emph{Observer Performance Methods for Diagnostic Imaging - Foundations, +#' Modeling, and Applications with R-Based Examples}, CRC Press, Boca Raton, FL. +#' \url{https://www.routledge.com/Observer-Performance-Methods-for-Diagnostic-Imaging-Foundations-Modeling/Chakraborty/p/book/9781482214840} +#' +#' Chakraborty DP, Berbaum KS (2004) Observer studies involving detection and localization: modeling, analysis, and validation, +#' Medical Physics, 31(8), 1--18. +#' +#' Song T, Bandos AI, Rockette HE, Gur D (2008) On comparing methods for discriminating between actually negative and actually positive subjects +#' with FROC type data, Medical Physics 35 1547--1558. +#' +#' Popescu LM (2011) Nonparametric signal detectability evaluation using an exponential transformation of the FROC curve, +#' Medical Physics, 38(10), 5690. +#' +#' Obuchowski NA, Lieber ML, Powell KA (2000) Data Analysis for Detection and Localization of Multiple Abnormalities +#' with Application to Mammography, Acad Radiol, 7:7 553--554. +#' +#' Swensson RG (1996) Unified measurement of observer performance in detecting and localizing target objects on images, +#' Med Phys 23:10, 1709--1725. + +#' @importFrom dplyr between +#' @export + +UtilFigureOfMeritX <- function(dsX, FOM = "wAFROC") { + + dataType <- dsX$descriptions$type + if ((dataType == "ROC") && !(FOM %in% c("Wilcoxon"))) { + errMsg <- paste0("Must use Wilcoxon figure of merit with ROC data.") + stop(errMsg) + } + + if (dataType %in% c("ROI", "LROC")) { + stop("ROI or LROC cross-modality analysis is not supported.\n") + } + + if ((dataType %in% c("FROC")) && (FOM == "Wilcoxon")) + stop("Cannot use `Wilcoxon` FOM with `FROC` data.") + + NL <- dsX$ratings$NL + LL <- dsX$ratings$LL + + I1 <- dim(NL)[1] + I2 <- dim(NL)[2] + J <- dim(NL)[3] + K <- dim(NL)[4] + K2 <- dim(LL)[4] + K1 <- K - K2 + maxNL <- dim(NL)[5] + maxLL <- dim(LL)[5] + + if ((K1 == 0) && !(FOM %in% c("AFROC1", "wAFROC1"))) { + errMsg <- paste0("Only AFROC1 or wAFROC1 FOMs are allowed for datasets with zero non-diseased cases.") + stop(errMsg) + } + + fomArray <- array(dim = c(I1, I2, J)) + if (((dataType == "FROC") && + (FOM %in% c("HrAuc", "AFROC", "wAFROC", "AFROC1", "wAFROC1"))) || + ((dataType == "ROC") && (FOM %in% c("Wilcoxon")))) { + # FOM = AFROC1, wAFROC1 not yet tested 8/7/23 + for (i1 in 1:I1) { + for (i2 in 1:I2) { + for (j in 1:J) { + fomArray[i1, i2,j] <- MyFom_ij(NL[i1, i2, j, , ], LL[i1, i2, j, , ], perCase, IDs, weights, maxNL, maxLL, K1, K2, FOM) + } + } + } + } else stop("FOM is not consistent with data type\n") + + modalityID1 <- dsX$descriptions$modalityID1 + modalityID2 <- dsX$descriptions$modalityID2 + readerID <- dsX$descriptions$readerID + rownames(fomArray) <- paste("trt", sep = "", c(modalityID1, modalityID2)) + colnames(fomArray) <- paste("rdr", sep = "", readerID) + return(as.data.frame(fomArray)) +} + + diff --git a/R/UtilPseudoValues.R b/R/UtilPseudoValues.R index 0193d44c..f2a88f64 100644 --- a/R/UtilPseudoValues.R +++ b/R/UtilPseudoValues.R @@ -1,10 +1,10 @@ #' Pseudovalues for given dataset and FOM #' #' Returns \strong{centered} jackknife pseudovalues AND jackknife FOM values, -#' for factorial OR split-plot-a OR split-plot-c study designs +#' for factorial study designs #' #' @param dataset The dataset to be analyzed, see \code{\link{RJafroc-package}}; -#' must be factorial, or split-plot-a or split-plot-c. +#' must be factorial. #' @param FOM The figure of merit to be used in the calculation. #' The default is \code{"FOM_wAFROC"}. See \code{\link{UtilFigureOfMerit}}. #' @param FPFValue Only needed for \code{LROC} data \strong{and} FOM = "PCL" or "ALROC"; diff --git a/R/UtilVarComponentsOR.R b/R/UtilVarComponentsOR.R index 989de3ac..c89469f9 100644 --- a/R/UtilVarComponentsOR.R +++ b/R/UtilVarComponentsOR.R @@ -116,8 +116,7 @@ UtilVarComponentsOR <- function (dataset, FOM, FPFValue = 0.2, cov2EachTrt = cov2EachTrt, row.names = paste0("trt", modID), stringsAsFactors = FALSE) - # } else IndividualTrt <- NA # these are not defined for split-plot-c datasets - + # single reader msT_j ############################################################### if (I > 1) { msT_j <- array(0, dim = J) diff --git a/R/dataset2ratings.R b/R/dataset2ratings.R index 0cba9e96..235166d6 100644 --- a/R/dataset2ratings.R +++ b/R/dataset2ratings.R @@ -4,13 +4,12 @@ # third is the incorrect localizations array dataset2ratings <- function (dataset, FOM){ - # OldFormat dataset or NewFormat FCTRL or SPLIT-PLOT-C dataset with implemented FOM dataType <- dataset$descriptions$type if (dataType != "LROC") { K2 <- length(dataset$ratings$LL[1,1,,1]) } else if (dataType == "LROC") { K2 <- length(dataset$ratings$LL[1,1,,1]) - } else stop("Incorrect data type") # should never get here + } else stop("dataset2ratings: Incorrect data type") # should never get here if (dataType == "ROC") { zjk1 <- drop(dataset$ratings$NL) # must retain the full length K of the array diff --git a/R/datasets.R b/R/datasets.R index 01c369aa..4c397510 100644 --- a/R/datasets.R +++ b/R/datasets.R @@ -842,8 +842,7 @@ #' This is a crossed treatment dataset, see book Section 18.5. There are two treatment factors. #' The first treatment factor \code{modalityID1} can be "F" or "I", which represent two CT reconstruction #' algorithms. The second treatment factor \code{modalityID2} can be "20" "40" "60" "80", which -#' represent the mAs values of the image acquisition. The factors are fully crossed. The function -#' \code{\link{StSignificanceTestingCrossedModalities}} analyzes such datasets. +#' represent the mAs values of the image acquisition. The factors are fully crossed. #' #' @format A list with 3 elements: \code{$ratings}, \code{$lesions} and \code{$descriptions}; \code{$ratings} #' contain 3 elements, \code{$NL}, \code{$LL} and \code{$LL_IL} as sub-lists; \code{$lesions} @@ -919,48 +918,6 @@ #' #' #' -#' -#' -#' Simulated FROC SPLIT-PLOT-C dataset -#' -#' Simulated from FED Excel dataset by successively ignoring readers 3:4, c(1,3:4), -#' c(1:2,4), etc. -#' created simulated split plot Excel dataset from Fed dataset: -#' confirmed it is read without error -#' -#' -#' @format A list with 3 elements: \code{$ratings}, \code{$lesions} and \code{$descriptions}; \code{$ratings} -#' contain 3 elements, \code{$NL}, \code{$LL} and \code{$LL_IL} as sub-lists; \code{$lesions} -#' contain 3 elements, \code{$perCase}, \code{$IDs} and \code{$weights} as sub-lists; \code{$descriptions} -#' contain 7 elements, \code{$fileName}, \code{$type}, \code{$name}, -#' \code{$truthTableStr}, \code{$design}, \code{$modalityID} and \code{$readerID} as sub-lists; -#' \itemize{ -#' \item{\code{rating$NL}}{, num [1:2, 1:4, 1:200, 1:7], ratings of non-lesion localizations, NLs} -#' \item{\code{rating$LL}}{, num [1:2, 1:4, 1:100, 1:3], ratings of lesion localizations, LLs} -#' \item{\code{rating$LL_IL}}{NA, this placeholder is used only for LROC data} -#' \item{\code{lesions$perCase}}{, int [1:100], number of lesions per diseased case} -#' \item{\code{lesions$IDs}}{, num [1:100, 1:3] , numeric labels of lesions on diseased cases} -#' \item{\code{lesions$weights}}{, num [1:100, 1:3], weights (or clinical importances) of lesions} -#' \item{\code{descriptions$fileName}}{, chr, "datasetFROCSpC", base name of dataset in `data` folder} -#' \item{\code{descriptions$type}}{, chr "FROC", the data type} -#' \item{\code{descriptions$name}}{, chr "SIM-FROC-SPLIT-PLOT-C", the name of the dataset} -#' \item{\code{descriptions$truthTableStr}}{, NA, truth table structure} -#' \item{\code{descriptions$design}}{, chr "FCTRL-X-MOD", study design, factorial dataset} -#' \item{\code{descriptions$modalityID}}{, chr [1:2] "4" "5", treatment label(s)} -#' \item{\code{descriptions$readerID}}{, chr [1:4] "1" "3" "4" "5", reader labels} -#' } -#' -#' @keywords datasets -#' -#' @examples -#' str(datasetFROCSpC) -#' -"datasetFROCSpC" -#' -#' -#' -#' -#' #' Simulated ROI dataset #' #' TBA Simulated ROI dataset: assumed are 4 ROIs per case, 5 readers, 50 non-dieased and 40 diseased cases. diff --git a/data/datasetFROCSpC.RData b/data/datasetFROCSpC.RData deleted file mode 100644 index 3055c42a3505daf254f60813221d8f72ce14b819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1826 zcmZ`&YfzJC7VhY{v`ZDcv$ZP}vfJuLku_C;lv^?*vXoJqvJoL%WCbx=Ac&MpfFzw^ z5kVmW%2i2Owzxte6Cz0yAm1v5$OaNLgpdn~7(yVJAc?tt`I3#Tb+)s!&%8g*dEWOq z=bbs{fn9t1tsk+~uqYyECIfw5F#b_*h|7EXk#!b-fwb?*ma*EeKk)tCrJ-xX*yWbs zVeX-)#qXxY-N2edNKHZJEgaiBb*Kk~{k1PsO_8jK`&aIxe$_@jwkB|Fj~M@g^7m1) z+oHn&WdEb9SB&sGv!o{VyBJ<%CBv-SS$@YQOkJ&>Q5t%d%E}J;17*-<+tWPc--LMa zf)6{^z6hv2h!dWyneb<(st)~UIlG=L3!ttqJ+}GM`=S({ zM6Hl$V4yR&VplRHLn>j=MSrQMtwQP><_nU@f0OZlI0+Vu?sECX+R6#yZp8*manp@I zJ1idn?Zd;cd?4sz9WI4HD0E4}8n7Gui9#7m!_c4a-d+4%AMUCEX^8$;Xt=ic40atC zMj}fH%vqxqTfbF<7!b%kxRlQ`a*RBKWL`v02k+?zN1z46TvB|RO+B=tjTKeR6)Q)K z&q&t!4Nsl48P|p^j_D^nkM<8)Xemr71#zFH#Y-SqT4^4t#5HF@74>Z%Z(2@b&R&mf zQEgmF$29IqIN0GN-JN3%d-5UW(^T})iS*-CMHZk?QMvq_m*6*zhUWZm-zgek#ev81vlor0@0Fes6p<=X%vPtaMy*xJ0=d*ptvJUEkWYCt(Oh5_t;s z-#5KyhKKg-@G?K0$@ZBSYRZkD(>HwhT*!1MH|S0NCJ;vLn-1?t^n0y;!#C|g6LxhZ z`usm$?0=Nr?8*Mq%ZKL)wpDw+aQ+;L_tmc{!d6Qqv6U|0an?+iF>#-+C+D)JZz(vX zs3B-|&77zDR)<^}h=iK82dpD3=!1_G)akn=JKKTV095DTu3#iqfwR9s?H(P7q8t+f z^7S=Q8VBm*AF)=Z&chUBbRvr7epIR7WG_(rK#B|+?1xTC6Hi9C89LgkQ((S>KrVpq&f<-B^|#S0KHM8c z?(Q{MbYrEcV=Dq{?6B*v-3_NK@BqI?1HStcE5xdEtZLYYfIEEmQkoOe|G=lcnt|*DmV&O%V?L%)+R$Qv>!dls-eOyg?TE7?vHKH= zZmAaSxjKmcK~mUGb-DJJc;Fy8r>#^5dH;hTdG`vMZz0pZem&2rno!@1^1u+zSO7?K zmj1@OP!tpzlzk@zFG1{~2Gh3zy}+&ayH*5pOsmLGE6R(B2;>E3EF+y_xaf2VPl+fn zw6eRNZ%~+Qv?5i<%o3!<9mu7Yt^HOY0c|ts8SL*XpEHcxMFv%VyX&xAz9DG;vx$38 z=(>Ky*Q|PJk7XB$%>?F`1X(XixJ)Oi57;LPf+o0^v@smiNcjY${^E>!=HNF-%BQd{ zQW46(D3?US?s0xoVWCS}eLfAA=@v+Byfp{WmFqRXLTtIF${(SPGO_n2#OC<->G4 zE#P?!un*=q`;}{DWHZkGLZ~l)?;v6)n|ehP9Yx-BYK;$M#)my)Q~K&+AYuW`!Vi&k zPbF^ElCU3Yt%(|8=1!^4jQr8Ao3l_BlZak8LLI%5j}fnsxmSI^d|9j2CWpNav|8-) z|9XUz?t@i;>YhgeFOmhwfuJ7?Nv5S^&>Ym*>IJ=}AT`GH3jOU~^Z%D)FYn&bJ7~0N z=m-cADmLd3f8^%K!;zq^qp=q3SfkBnh|#%(tOq0 z($gI^rb!)} zu-VX_5KzRiJbO?Nz-ZTbAMyg2=<4bIKPt_)oVQTJqJh9m+ zex?$$)v)cD20q#tgFuo|{z3IZGbr_4-6g`IVGUG_I{juT#&nWQNmW6i1xp1wK3=oN Sm7OiKQKCYZ+_|+|-ue%dTpU{f diff --git a/inst/FixDatasets/FixAllDatasets.R b/inst/FixDatasets/FixAllDatasets.R index 0e1d431e..e0173a96 100644 --- a/inst/FixDatasets/FixAllDatasets.R +++ b/inst/FixDatasets/FixAllDatasets.R @@ -173,24 +173,6 @@ for (i in 1:length(df[,1])) { design = df[i,3], modalityID = x$modalityID, readerID = x$readerID) - } else if (i == 22) { - # simulated FROC split plot - ratings <- list(NL = x$NL, - LL = x$LL, - LL_IL = NA) - - lesions <- list(perCase = x$lesionVector, - IDs = x$lesionID, - weights = x$lesionWeight) - - descriptions <- list(binned = df[i,5], - fileName = df[i,1], - type = df[i,2], - name = df[i,4], - truthTableStr = x$descriptions$truthTableStr, # this is really needed here - design = df[i,3], - modalityID = x$modalityID, - readerID = x$readerID) } else if (i == 23) { # simulated ROI ratings <- list(NL = x$NL, diff --git a/inst/debugTests/debug-test-UtilOutputReport.R b/inst/debugTests/debug-test-UtilOutputReport.R index 96b9761b..2a169d6a 100644 --- a/inst/debugTests/debug-test-UtilOutputReport.R +++ b/inst/debugTests/debug-test-UtilOutputReport.R @@ -7,14 +7,13 @@ fomStr <- c("Wilcoxon", "wAFROC") for (f in 1:length(fomStr)) { for (d in 1:length(datasetStr)) { for (m in 1:length(methodStr)) { + cat("f = ", f, ", d = ", d, ", m = ", m, "\n") FOM <- fomStr[f] method <- methodStr[m] dataset <- get(datasetStr[d]) - if (dataset$descriptions$type == "ROC" && - (FOM != "Wilcoxon")) + if (dataset$descriptions$type == "ROC" && (FOM != "Wilcoxon")) next - if (dataset$descriptions$type == "FROC" && - (FOM != "wAFROC")) + if (dataset$descriptions$type == "FROC" && (FOM != "wAFROC")) next fn <- paste0( diff --git a/inst/extdata/toyFiles/FROC/1T3Rvs4R.xlsx b/inst/extdata/toyFiles/FROC/1T3Rvs4R.xlsx deleted file mode 100644 index 1fd92c557691fc4c40b752163085532c04e52a30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55754 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 diff --git a/inst/extdata/toyFiles/FROC/FrocDataSpC.xlsx b/inst/extdata/toyFiles/FROC/FrocDataSpC.xlsx deleted file mode 100644 index 11d4d09b60873efd984da0120265620320a70eb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25278 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 F{U7)T*!che diff --git a/inst/extdata/toyFiles/FROC/FrocSpCVaryK1K2.xlsx b/inst/extdata/toyFiles/FROC/FrocSpCVaryK1K2.xlsx deleted file mode 100644 index d883b78dd1f83bb0a5c5dbe8002ee1687cf59598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25300 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 diff --git a/inst/extdata/toyFiles/FROC/frocSpC.xlsx b/inst/extdata/toyFiles/FROC/frocSpC.xlsx deleted file mode 100644 index 90fc7346b8d11133e9447080b0b1ad5411bfdce9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19448 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 E0h6>_)&Kwi diff --git a/inst/extdata/toyFiles/FROC/frocSpCDelRowsFP.xlsx b/inst/extdata/toyFiles/FROC/frocSpCDelRowsFP.xlsx deleted file mode 100644 index b7abf324ba73eb3f8d9ad828b4d9fb71429f6aa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17558 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 diff --git a/man/DfFroc2Roc.Rd b/man/DfFroc2Roc.Rd index 2a0f2d43..049953b1 100644 --- a/man/DfFroc2Roc.Rd +++ b/man/DfFroc2Roc.Rd @@ -38,7 +38,6 @@ any marked case}, is assigned to it. The dataset structure is shown below: } \examples{ rocDataSet <- DfFroc2Roc(dataset05) -rocSpDataSet <- DfFroc2Roc(datasetFROCSpC) ## in the following example, because of the smaller number of cases, ## it is easy to see the process at work: diff --git a/man/DfReadDataFile.Rd b/man/DfReadDataFile.Rd index 16e9c207..23f100df 100644 --- a/man/DfReadDataFile.Rd +++ b/man/DfReadDataFile.Rd @@ -56,9 +56,7 @@ Read a disk file and create a ROC, FROC or LROC dataset object from it. } \note{ -WARNING: SPLIT-PLOT-A and SPLIT-PLOT-C have not been tested with real datasets. - Contact the maintainer if you desire this funtionality. - The \code{"MRMC"} format is deprecated. For non-JAFROC formats four file +The \code{"MRMC"} format is deprecated. For non-JAFROC formats four file extensions (\code{.csv}, \code{.txt}, \code{.lrc} and \code{.imrmc}) are possible, all of which are restricted to ROC data. Only the \code{iMRMC} format is actively supported, i.e, files with extension \code{.imrmc}. Other formats (\code{.csv}, diff --git a/man/RJafroc-package.Rd b/man/RJafroc-package.Rd index 80b4e3de..39298bda 100644 --- a/man/RJafroc-package.Rd +++ b/man/RJafroc-package.Rd @@ -307,12 +307,10 @@ interpretations occurred or NAs otherwise. For abnormal cases elements \code{c(I, J, L, 2:(maxLL+1))} are filled with 1s if the corresponding interpretations occurred or NAs otherwise. This object is necessary for analyzing - more complex designs, e.g., split-plot, as described next. + more complex designs. - \item \code{descriptions$design}: a \code{character} variable: "\code{FCTRL}", - "\code{SPLIT-PLOT-A}" or "\code{SPLIT-PLOT-A}", corresponding to factorial, - split-plot-A or split-plot-C designs. The A and C refer to subparts of Table VII - in a Hillis 2014 publication. + \item \code{descriptions$design}: a \code{character} variable: "\code{FCTRL}", + corresponding to factorial design. \item \code{descriptions$modalityID}: a \code{character} vector of length \eqn{I}, which labels/names the modalities in the dataset. For non-JAFROC data file formats, @@ -430,8 +428,6 @@ DBM or OR. \item \code{\link{StSignificanceTestingCadVsRad}}: Perform significance testing, CAD vs. radiologists. - \item \code{\link{StSignificanceTestingCrossedModalities}}: Perform - significance testing using crossed modalities analysis. } } diff --git a/man/StSignificanceTesting.Rd b/man/StSignificanceTesting.Rd index 6b6cdc56..f31ad2d0 100644 --- a/man/StSignificanceTesting.Rd +++ b/man/StSignificanceTesting.Rd @@ -2,23 +2,24 @@ % Please edit documentation in R/StSignificanceTesting.R \name{StSignificanceTesting} \alias{StSignificanceTesting} -\title{Performs DBM or OR significance testing for factorial or split-plot A,C datasets} +\title{Performs DBM or OR significance testing for factorial datasets} \usage{ StSignificanceTesting( dataset, FOM, FPFValue = 0.2, alpha = 0.05, - method = "DBM", + method = "OR", covEstMethod = "jackknife", nBoots = 200, - analysisOption = "ALL" + analysisOption = "ALL", + avgIndx = NULL ) } \arguments{ \item{dataset}{The dataset to be analyzed, see \code{\link{RJafroc-package}}. Must have two or more treatments and two or more readers. The dataset design -can be "FCTRL", "SPLIT-PLOT-A" or "SPLIT-PLOT-C".} +can be "FCTRL" or "FCTRL-X-MOD".} \item{FOM}{The figure of merit, see \code{\link{UtilFigureOfMerit}}} @@ -29,10 +30,8 @@ where to evaluate a partial curve based figure of merit. The default is 0.2.} treatment effects are zero; the default is 0.05} \item{method}{The significance testing method to be used: -\code{"DBM"} (the default), representing the -Dorfman-Berbaum-Metz method or \code{"OR"}, representing the -Obuchowski-Rockette method. -and the Obuchowski-Rockette significance testing methods, respectively.} +\code{"DBM"} representing the Dorfman-Berbaum-Metz method or \code{"OR"}, +the default, representing the Obuchowski-Rockette method.} \item{covEstMethod}{The covariance matrix estimation method in \code{ORH} analysis (for \code{method = "DBM"} the jackknife is always used). @@ -48,12 +47,14 @@ and the Obuchowski-Rockette significance testing methods, respectively.} \item{analysisOption}{Determines which factors are regarded as random vs. fixed: \itemize{ - \item \code{"RRRC"} = random-reader random case, + \item \code{"RRRC"} = random-reader random case, the default, \item \code{"FRRC"} = fixed-reader random case, \item \code{"RRFC"} = random-reader fixed case, - \item \code{"ALL"} = outputs results of \code{"RRRC"}, \code{"FRRC"} - and \code{"RRFC"} analyses - this is the default. + \item \code{"ALL"} = all allowed options. }} + +\item{avgIndx}{For cross-modality analysis the modality-index to be averaged over. The +default is "NULL", i.e., not cross-modality analysis.} } \value{ \strong{For \code{method = "DBM"} the returned list contains 4 dataframes:} @@ -101,17 +102,10 @@ Performs Dorfman-Berbaum-Metz (DBM) or Obuchowski-Rockette (OR) \examples{ StSignificanceTesting(dataset02,FOM = "Wilcoxon", method = "DBM") StSignificanceTesting(dataset02,FOM = "Wilcoxon", method = "OR") -## following is split-plot-c analysis using a simulated split-plot-c dataset -StSignificanceTesting(datasetFROCSpC, FOM = "wAFROC", method = "OR") \donttest{ StSignificanceTesting(dataset05, FOM = "wAFROC") StSignificanceTesting(dataset05, FOM = "HrAuc", method = "DBM") -StSignificanceTesting(dataset05, FOM = "SongA1", method = "DBM") -StSignificanceTesting(dataset05, FOM = "SongA2", method = "DBM") -StSignificanceTesting(dataset05, FOM = "wAFROC1", method = "DBM") -StSignificanceTesting(dataset05, FOM = "AFROC1", method = "DBM") -StSignificanceTesting(dataset05, FOM = "AFROC", method = "DBM") } diff --git a/man/StSignificanceTestingCrossedModalities.Rd b/man/StSignificanceTestingCrossedModalities.Rd deleted file mode 100644 index e12f0afe..00000000 --- a/man/StSignificanceTestingCrossedModalities.Rd +++ /dev/null @@ -1,39 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/StSignificanceTestingCrossedModalities.R -\name{StSignificanceTestingCrossedModalities} -\alias{StSignificanceTestingCrossedModalities} -\title{Perform significance testing using crossed treatments analysis} -\usage{ -StSignificanceTestingCrossedModalities( - ds, - avgIndx, - FOM = "wAFROC", - alpha = 0.05, - analysisOption = "ALL" -) -} -\arguments{ -\item{ds}{The crossed treatments dataset} - -\item{avgIndx}{The index of the treatment to be averaged over} - -\item{FOM}{See \code{\link{StSignificanceTesting}}} - -\item{alpha}{See \code{\link{StSignificanceTesting}}} - -\item{analysisOption}{See \code{\link{StSignificanceTesting}}} -} -\value{ -A list containing the same objects as \code{\link{StSignificanceTesting}}. -} -\description{ -Performs ORH analysis for specified crossed treatments dataset - averaged over specified treatment factor -} -\examples{ -\donttest{ -## read the built in dataset -retCrossed2 <- StSignificanceTestingCrossedModalities(datasetXModality, 1) -} - -} diff --git a/man/UtilFigureOfMerit.Rd b/man/UtilFigureOfMerit.Rd index f4f26156..085e8014 100644 --- a/man/UtilFigureOfMerit.Rd +++ b/man/UtilFigureOfMerit.Rd @@ -27,8 +27,6 @@ Calculate the specified empirical figure of merit The allowed FOMs depend on the \code{dataType} field of the \code{dataset} object. - \strong{For \code{dataset$descriptions$design = "SPLIT-PLOT-C"}, end-point based - FOMs (e.g., "MaxLLF") are not allowed}. \strong{For \code{dataset$descriptions$type = "ROC"} only \code{FOM = "Wilcoxon"} is allowed}. \strong{For \code{dataset$descriptions$type = "FROC"} the following FOMs are allowed}: \itemize{ diff --git a/man/UtilFigureOfMeritX.Rd b/man/UtilFigureOfMeritX.Rd new file mode 100644 index 00000000..3b62db8e --- /dev/null +++ b/man/UtilFigureOfMeritX.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/UtilFigureOfMeritX.R +\name{UtilFigureOfMeritX} +\alias{UtilFigureOfMeritX} +\title{Calculate empirical figures of merit for cross-modality dataset} +\usage{ +UtilFigureOfMeritX(dsX, FOM = "wAFROC") +} +\arguments{ +\item{dsX}{The cross-modality dataset to be analyzed} + +\item{FOM}{The figure of merit; the default is \code{"wAFROC"}} +} +\value{ +A \code{c(I1, I2, J)} data frame, where the row names are \code{modalityID}'s of the + treatments and column names are the \code{readerID}'s of the readers. +} +\description{ +Calculate the specified empirical figure of merit + for each treatment-reader combination in the cross-modality dataset +} +\details{ +The allowed FOMs depend on the \code{dataType} field of the + \code{dataset} object. + + \strong{For \code{dataset$descriptions$type = "ROC"} only \code{FOM = "Wilcoxon"} is allowed}. + \strong{For \code{dataset$descriptions$type = "FROC"} the following FOMs are allowed}: + \itemize{ + \item \code{FOM = "AFROC1"} (use only if zero normal cases) + \item \code{FOM = "AFROC"} + \item \code{FOM = "wAFROC1"} (use only if zero normal cases) + \item \code{FOM = "wAFROC"} (the default) + \item \code{FOM = "HrAuc"} + \item \code{FOM = "SongA1"} + \item \code{FOM = "SongA2"} + \item \code{FOM = "HrSe"} (an example of an end-point based FOM) + \item \code{FOM = "HrSp"} (another example) + \item \code{FOM = "MaxLLF"} (do:) + \item \code{FOM = "MaxNLF"} (do:) + \item \code{FOM = "MaxNLFAllCases"} (do:) + \item \code{FOM = "ExpTrnsfmSp"} + } + \code{"MaxLLF"}, \code{"MaxNLF"} and \code{"MaxNLFAllCases"} + correspond to ordinate, and abscissa, respectively, of the highest point + on the FROC operating characteristic obtained by counting all the marks. + The \code{"ExpTrnsfmSp"} FOM is described in the paper by Popescu. + Given the large number of FOMs possible with FROC data, it is appropriate + to make a recommendation: \strong{it is recommended that one use the wAFROC FOM + whenever possible. If the dataset has no non-diseased cases one should use the + the wAFROC1 FOM}. +} +\examples{ + +##UtilFigureOfMeritX(datasetXModality, FOM = "wAFROC") + + +} +\references{ +Chakraborty DP (2017) \emph{Observer Performance Methods for Diagnostic Imaging - Foundations, +Modeling, and Applications with R-Based Examples}, CRC Press, Boca Raton, FL. +\url{https://www.routledge.com/Observer-Performance-Methods-for-Diagnostic-Imaging-Foundations-Modeling/Chakraborty/p/book/9781482214840} + +Chakraborty DP, Berbaum KS (2004) Observer studies involving detection and localization: modeling, analysis, and validation, +Medical Physics, 31(8), 1--18. + +Song T, Bandos AI, Rockette HE, Gur D (2008) On comparing methods for discriminating between actually negative and actually positive subjects +with FROC type data, Medical Physics 35 1547--1558. + +Popescu LM (2011) Nonparametric signal detectability evaluation using an exponential transformation of the FROC curve, +Medical Physics, 38(10), 5690. + +Obuchowski NA, Lieber ML, Powell KA (2000) Data Analysis for Detection and Localization of Multiple Abnormalities +with Application to Mammography, Acad Radiol, 7:7 553--554. + +Swensson RG (1996) Unified measurement of observer performance in detecting and localizing target objects on images, +Med Phys 23:10, 1709--1725. +} diff --git a/man/UtilPseudoValues.Rd b/man/UtilPseudoValues.Rd index f6adbd22..2c611eb2 100644 --- a/man/UtilPseudoValues.Rd +++ b/man/UtilPseudoValues.Rd @@ -8,7 +8,7 @@ UtilPseudoValues(dataset, FOM, FPFValue = 0.2) } \arguments{ \item{dataset}{The dataset to be analyzed, see \code{\link{RJafroc-package}}; -must be factorial, or split-plot-a or split-plot-c.} +must be factorial.} \item{FOM}{The figure of merit to be used in the calculation. The default is \code{"FOM_wAFROC"}. See \code{\link{UtilFigureOfMerit}}.} @@ -23,7 +23,7 @@ A list containing two arrays containing the pseudovalues } \description{ Returns \strong{centered} jackknife pseudovalues AND jackknife FOM values, - for factorial OR split-plot-a OR split-plot-c study designs + for factorial study designs } \note{ Each returned array has dimension \code{c(I,J,K)}, where \code{K} depends on the diff --git a/man/datasetFROCSpC.Rd b/man/datasetFROCSpC.Rd deleted file mode 100644 index d046e2dc..00000000 --- a/man/datasetFROCSpC.Rd +++ /dev/null @@ -1,42 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/datasets.R -\docType{data} -\name{datasetFROCSpC} -\alias{datasetFROCSpC} -\title{Simulated FROC SPLIT-PLOT-C dataset} -\format{ -A list with 3 elements: \code{$ratings}, \code{$lesions} and \code{$descriptions}; \code{$ratings} - contain 3 elements, \code{$NL}, \code{$LL} and \code{$LL_IL} as sub-lists; \code{$lesions} - contain 3 elements, \code{$perCase}, \code{$IDs} and \code{$weights} as sub-lists; \code{$descriptions} - contain 7 elements, \code{$fileName}, \code{$type}, \code{$name}, - \code{$truthTableStr}, \code{$design}, \code{$modalityID} and \code{$readerID} as sub-lists; -\itemize{ -\item{\code{rating$NL}}{, num [1:2, 1:4, 1:200, 1:7], ratings of non-lesion localizations, NLs} -\item{\code{rating$LL}}{, num [1:2, 1:4, 1:100, 1:3], ratings of lesion localizations, LLs} -\item{\code{rating$LL_IL}}{NA, this placeholder is used only for LROC data} -\item{\code{lesions$perCase}}{, int [1:100], number of lesions per diseased case} -\item{\code{lesions$IDs}}{, num [1:100, 1:3] , numeric labels of lesions on diseased cases} -\item{\code{lesions$weights}}{, num [1:100, 1:3], weights (or clinical importances) of lesions} -\item{\code{descriptions$fileName}}{, chr, "datasetFROCSpC", base name of dataset in `data` folder} -\item{\code{descriptions$type}}{, chr "FROC", the data type} -\item{\code{descriptions$name}}{, chr "SIM-FROC-SPLIT-PLOT-C", the name of the dataset} -\item{\code{descriptions$truthTableStr}}{, NA, truth table structure} -\item{\code{descriptions$design}}{, chr "FCTRL-X-MOD", study design, factorial dataset} -\item{\code{descriptions$modalityID}}{, chr [1:2] "4" "5", treatment label(s)} -\item{\code{descriptions$readerID}}{, chr [1:4] "1" "3" "4" "5", reader labels} -} -} -\usage{ -datasetFROCSpC -} -\description{ -Simulated from FED Excel dataset by successively ignoring readers 3:4, c(1,3:4), -c(1:2,4), etc. -created simulated split plot Excel dataset from Fed dataset: -confirmed it is read without error -} -\examples{ -str(datasetFROCSpC) - -} -\keyword{datasets} diff --git a/man/datasetXModality.Rd b/man/datasetXModality.Rd index 64f10eba..7ad4d206 100644 --- a/man/datasetXModality.Rd +++ b/man/datasetXModality.Rd @@ -33,8 +33,7 @@ datasetXModality This is a crossed treatment dataset, see book Section 18.5. There are two treatment factors. The first treatment factor \code{modalityID1} can be "F" or "I", which represent two CT reconstruction algorithms. The second treatment factor \code{modalityID2} can be "20" "40" "60" "80", which -represent the mAs values of the image acquisition. The factors are fully crossed. The function -\code{\link{StSignificanceTestingCrossedModalities}} analyzes such datasets. +represent the mAs values of the image acquisition. The factors are fully crossed. } \examples{ str(datasetXModality) diff --git a/tests/testthat/test-DfExtractDataset.R b/tests/testthat/test-DfExtractDataset.R index 67138493..0521b6ea 100644 --- a/tests/testthat/test-DfExtractDataset.R +++ b/tests/testthat/test-DfExtractDataset.R @@ -1,4 +1,4 @@ -contextStr <- "DfExtractDataset: toy crossed and split plot datasets" +contextStr <- "DfExtractDataset: toy factorial dataset" context(contextStr) test_that(contextStr, { @@ -19,53 +19,5 @@ test_that(contextStr, { x2 <- DfExtractDataset(ds, rdrs = c(1, 3)) expect_equal(x1, x2) - # SPLIT-PLOT-A - # ############################################################################ - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfExtractDataset/frocSpA", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- DfExtractDataset(ds, rdrs = c(1, 2, 3)) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- DfExtractDataset(ds, rdrs = c(1, 2, 3)) - expect_equal(x1, x2) - - # these need to be updated to reflect changes in frocSpA.xlsx - # t <- x1$descriptions$truthTableStr - # for (j in 1:2) expect_equal(which(!is.na(t[1,j,,1])), 1:5) - # expect_equal(which(!is.na(t[2,3,,1])), 1:5) - # for (j in 1:2) expect_equal(which(!is.na(t[1,j,,2])), 6:10) - # expect_equal(which(!is.na(t[2,3,,2])), 6:10) - - # SPLIT-PLOT-C - # ############################################################################ - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfExtractDataset/frocSpC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- DfExtractDataset(ds, rdrs = c(1, 3)) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- DfExtractDataset(ds, rdrs = c(1, 3)) - expect_equal(x1, x2) - - t <- x1$descriptions$truthTableStr - for (i in 1:2) expect_equal(which(!is.na(t[i,1,,1])), 1:3) - for (i in 1:2) expect_equal(which(!is.na(t[i,2,,1])), 7:9) - - for (i in 1:2) expect_equal(which(!is.na(t[i,1,,2])), 10:14) - for (i in 1:2) expect_equal(which(!is.na(t[i,2,,2])), 20:24) - }) diff --git a/tests/testthat/test-DfReadDataFile.R b/tests/testthat/test-DfReadDataFile.R index 8449adca..6aaf37e3 100644 --- a/tests/testthat/test-DfReadDataFile.R +++ b/tests/testthat/test-DfReadDataFile.R @@ -246,20 +246,6 @@ test_that(contextStr, { temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) expect_equal(temp, ds) - fileName <- system.file( - "extdata", "/toyFiles/FROC/FrocSpCVaryK1K2.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/FrocSpCVaryK1K2", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - fileName <- system.file( "extdata", "/toyFiles/FROC/frocCrStrRdrsTrts.xlsx", package = "RJafroc", mustWork = TRUE) @@ -278,7 +264,7 @@ test_that(contextStr, { -contextStr <- "DfReadDataFile: toy ROC SpA, SpC and crossed" +contextStr <- "DfReadDataFile: toy ROC factorial" context(contextStr) test_that(contextStr, { @@ -311,37 +297,9 @@ test_that(contextStr, { temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) expect_equal(temp, ds) - fileName <- system.file( - "extdata", "/toyFiles/ROC/rocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/rocSpC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - - fileName <- system.file( - "extdata", "/toyFiles/ROC/rocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/rocSpA", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - }) -contextStr <- "DfReadDataFile: toy FROC SpA, SpC and crossed" +contextStr <- "DfReadDataFile: toy FROC factorial" context(contextStr) test_that(contextStr, { @@ -354,7 +312,6 @@ test_that(contextStr, { temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) saveRDS(temp, file = fn) } - ds <- readRDS(fn) temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) expect_equal(temp, ds) @@ -362,42 +319,12 @@ test_that(contextStr, { # this checks a data file that uses strings for both readers and treatments, i.e., rocCrStrRdrsTrts.xlsx fileName <- system.file( "extdata", "/toyFiles/FROC/frocCrStrRdrsTrts.xlsx", package = "RJafroc", mustWork = TRUE) - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/frocCrStrRdrsTrts", ".rds") if (!file.exists(fn)) { warning(paste0("File not found - generating new ",fn)) temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) saveRDS(temp, file = fn) } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/frocSpC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/frocSpA", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - ds <- readRDS(fn) temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) expect_equal(temp, ds) @@ -415,58 +342,9 @@ test_that(contextStr, { expect_error(DfReadDataFile(y, newExcelFileFormat = TRUE)) - fileName <- system.file( - "extdata", "/toyFiles/FROC/1T3Rvs4R.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/1T3Rvs4R", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - expect_equal(DfReadDataFile(fileName, newExcelFileFormat = TRUE), ds) }) -contextStr <- "DfReadDataFile real FROC split-plot A dataset" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/1T3Rvs4R.xlsx", package = "RJafroc", mustWork = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/1T3Rvs4R", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - saveRDS(temp, file = fn) - } - - ds <- readRDS(fn) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - expect_equal(temp, ds) - - # calculate pseudovalues for split plot A - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/DfReadDataFile/UtilPseudoValues_frocSpA", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(temp, FOM = "wAFROC") - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(temp, FOM = "wAFROC") - expect_equal(x1, x2) - - -}) - contextStr <- "DfReadDataFile LROC dataset, 1 forced mark per case" context(contextStr) diff --git a/tests/testthat/test-OldVsNew-OR.R b/tests/testthat/test-OldVsNew-OR.R index 9b7b36f2..8ec9191c 100644 --- a/tests/testthat/test-OldVsNew-OR.R +++ b/tests/testthat/test-OldVsNew-OR.R @@ -1,5 +1,5 @@ ## ~/GitHub/RJafroc/tests/testthat/test-StSignificanceTesting.R was deleted as comparing to last good values is unnecessary as this code compares to ~/GitHub/RJafroc/R/StOldCode.R -contextStr <- "SigTest DBM: compare to OldCode in version 0.0.1, also tests PseudoValue functions" +contextStr <- "SigTest OR: compare to OldCode in version 0.0.1, also tests PseudoValue functions" context(contextStr) dropRowColumnNames <- function (df) { diff --git a/tests/testthat/test-PseudoValues.R b/tests/testthat/test-PseudoValues.R index 8a1eddb1..161384b6 100644 --- a/tests/testthat/test-PseudoValues.R +++ b/tests/testthat/test-PseudoValues.R @@ -42,63 +42,8 @@ test_that(contextStr, { }) -contextStr <- "UtilPseudoValues: FROC SpC wAFROC" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpC", "wAFROC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "wAFROC", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "wAFROC", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - # if (any(is.na(x1$jkFomValues[,1,1:3]))) stop("failed this test: NAs present") - # if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - # if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - # if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - -}) - -contextStr <- "UtilPseudoValues: FROC SpA wAFROC" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpA", "wAFROC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "wAFROC", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "wAFROC", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - if (all(is.na(x1$jkFomValues[1,1:2,1:5]))) stop("failed this test: NAs present") - if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - - -}) - contextStr <- "UtilPseudoValues: FROC FCTRL MaxLLF" @@ -124,63 +69,9 @@ test_that(contextStr, { -contextStr <- "UtilPseudoValues: FROC SpC MaxLLF" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpC", "MaxLLF", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "MaxLLF", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "MaxLLF", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - # if (any(is.na(x1$jkFomValues[,1,1:3]))) stop("failed this test: NAs present") - # if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - # if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - # if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - -}) -contextStr <- "UtilPseudoValues: FROC SpA MaxLLF" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpA", "MaxLLF", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "MaxLLF", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "MaxLLF", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - if (all(is.na(x1$jkFomValues[1,1:2,1:5]))) stop("failed this test: NAs present") - if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - - -}) - @@ -207,59 +98,5 @@ test_that(contextStr, { -contextStr <- "UtilPseudoValues: FROC SpC MaxNLF" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpC", "MaxNLF", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "MaxNLF", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "MaxNLF", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - # if (any(is.na(x1$jkFomValues[,1,1:3]))) stop("failed this test: NAs present") - # if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - # if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - # if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - -}) - -contextStr <- "UtilPseudoValues: FROC SpA MaxNLF" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - ds <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/UtilPseudoValues/frocSpA", "MaxNLF", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- UtilPseudoValues(ds, FOM = "MaxNLF", FPFValue = 0.2) - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- UtilPseudoValues(ds, FOM = "MaxNLF", FPFValue = 0.2) - expect_equal(x1, x2) - - # examine the jkFomValues - if (all(is.na(x1$jkFomValues[1,1:2,1:5]))) stop("failed this test: NAs present") - if (!all(is.na(x1$jkFomValues[2,1:2,1:5]))) stop("failed this test: not all NAs") - if (!all(is.na(x1$jkFomValues[1,3:5,1:5]))) stop("failed this test: not all NAs present") - if (all(is.na(x1$jkFomValues[2,3:5,1:5]))) stop("failed this test: NAs present") - - -}) diff --git a/tests/testthat/test-StSignificanceTestingSplitPlot.R b/tests/testthat/test-StSignificanceTestingSplitPlot.R deleted file mode 100644 index bf40d096..00000000 --- a/tests/testthat/test-StSignificanceTestingSplitPlot.R +++ /dev/null @@ -1,75 +0,0 @@ -contextStr <- "StSignificanceTesting: frocSpC wAFROC" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/SigTest/frocSpC-wAFROC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - - expect_equal(x1,x2) - -}) - - - - -contextStr <- "StSignificanceTesting: frocSpA-wAFROC" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/SigTest/frocSpA-wAFROC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - - expect_equal(x1,x2) - -}) - - - - -contextStr <- "StSignificanceTesting: 1T3Rvs4R FROC SpA-wAFROC" -context(contextStr) -test_that(contextStr, { - - fileName <- system.file( - "extdata", "/toyFiles/FROC/1T3Rvs4R.xlsx", package = "RJafroc", mustWork = TRUE) - - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - - fn <- paste0(test_path(), "/goodValues361/SigTest/1T3Rvs4R-SpA-wAFROC", ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - x1 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - saveRDS(x1, file = fn) - } - - x1 <- readRDS(fn) - x2 <- StSignificanceTesting(temp, FOM = "wAFROC", method = "OR") - - expect_equal(x1,x2) - -}) - diff --git a/tests/testthat/test-UtilFigureOfMerit.R b/tests/testthat/test-UtilFigureOfMerit.R index f9b23050..95bde837 100644 --- a/tests/testthat/test-UtilFigureOfMerit.R +++ b/tests/testthat/test-UtilFigureOfMerit.R @@ -1,24 +1,3 @@ -context("UtilFigureOfMerit FROC SPLIT-PLOT-C dataset, FOM = wAFROC") -test_that("FROC SPLIT-PLOT-C dataset, FOM = wAFROC", { - - dataset <- datasetFROCSpC - FOM = "wAFROC" - - fn <- paste0(test_path(), "/goodValues361/FOM/datasetFROCSpC-", FOM, ".rds") - if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) - ret <- UtilFigureOfMerit(dataset, FOM = FOM) - saveRDS(ret, file = fn) - } - - ret1 <- readRDS(fn) - ret2 <- UtilFigureOfMerit(dataset, FOM = FOM) - - expect_equal(ret1, ret2) - -}) - - context("UtilFigureOfMerit ROC dataset dataset02: FOM = Wilcoxon") test_that("ROC dataset dataset02: FOM = Wilcoxon", { diff --git a/tests/testthat/test-UtilOutputReport.R b/tests/testthat/test-UtilOutputReport.R index 99d63a24..de5ca9d4 100644 --- a/tests/testthat/test-UtilOutputReport.R +++ b/tests/testthat/test-UtilOutputReport.R @@ -1,23 +1,38 @@ # 7/11/20: this does not test the actual output produced by UtilOutputReport -# It just tests that the signficance testing routines run without errors +# It just tests that the significance testing routines run without errors # See next test commented out that represents failed attempt at comparing actual outputs for text files only contextStr <- "UtilOutputReport: datasets02, 03 and 04" context(contextStr) test_that(contextStr, { + methodStr <- c("DBM", "OR") datasetStr <- c("dataset04", "dataset02", "dataset03") fomStr <- c("Wilcoxon", "wAFROC") + for (f in 1:length(fomStr)) { for (d in 1:length(datasetStr)) { for (m in 1:length(methodStr)) { + #cat("f = ", f, ", d = ", d, ", m = ", m, "\n") FOM <- fomStr[f] method <- methodStr[m] dataset <- get(datasetStr[d]) - if (dataset$descriptions$type == "ROC" && (FOM != "Wilcoxon")) next - if (dataset$descriptions$type == "FROC" && (FOM != "wAFROC")) next - fn <- paste0(test_path(), "/goodValues361/UtilOutputReport/", datasetStr[d], "-", methodStr[m], "-", fomStr[f], "rds") + if (dataset$descriptions$type == "ROC" && (FOM != "Wilcoxon")) + next + if (dataset$descriptions$type == "FROC" && (FOM != "wAFROC")) + next + fn <- + paste0( + test_path(), + "/goodValues361/UtilOutputReport/", + datasetStr[d], + "-", + methodStr[m], + "-", + fomStr[f], + "rds" + ) if (!file.exists(fn)) { - warning(paste0("File not found - generating new ",fn)) + warning(paste0("File not found - generating new ", fn)) x <- UtilOutputReport(dataset, FOM = FOM, method = method) saveRDS(x, fn) } @@ -27,6 +42,7 @@ test_that(contextStr, { } } } + }) # 7/11/20: following code passes when run using Run Tests but fails when run using diff --git a/tests/testthat/test-UtilVarComponents.R b/tests/testthat/test-UtilVarComponents.R index e14cf108..3d83a54e 100644 --- a/tests/testthat/test-UtilVarComponents.R +++ b/tests/testthat/test-UtilVarComponents.R @@ -175,7 +175,7 @@ test_that(contextStr, { -contextStr <- "UtilVarCompOR: toy crossed and split plot datasets" +contextStr <- "UtilVarCompOR: toy crossed datasets" context(contextStr) test_that(contextStr, { @@ -196,40 +196,6 @@ test_that(contextStr, { x2 <- UtilVarComponentsOR(temp, FOM = "wAFROC") expect_equal(x1, x2) - # SPLIT-PLOT-A - # ############################################################################ - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpA.xlsx", package = "RJafroc", mustWork = TRUE) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - # - # fn <- paste0(test_path(), "/goodValues361/UtilVarComponents/frocSpA", ".rds") - # if (!file.exists(fn)) { - # warning(paste0("File not found - generating new ",fn)) - # x1 <- UtilVarComponentsOR(temp, FOM = "wAFROC") - # saveRDS(x1, file = fn) - # } - # - # x1 <- readRDS(fn) - # x2 <- UtilVarComponentsOR(temp, FOM = "wAFROC") - # expect_equal(x1, x2) - - # SPLIT-PLOT-C - # ############################################################################ - fileName <- system.file( - "extdata", "/toyFiles/FROC/frocSpC.xlsx", package = "RJafroc", mustWork = TRUE) - temp <- DfReadDataFile(fileName, newExcelFileFormat = TRUE) - # - # fn <- paste0(test_path(), "/goodValues361/UtilVarComponents/frocSpC", ".rds") - # if (!file.exists(fn)) { - # warning(paste0("File not found - generating new ",fn)) - # x1 <- UtilVarComponentsOR(temp, FOM = "wAFROC") - # saveRDS(x1, file = fn) - # } - # - # x1 <- readRDS(fn) - # x2 <- UtilVarComponentsOR(temp, FOM = "wAFROC") - # expect_equal(x1, x2) - })