R/DfFroc2Roc.R

#' Convert an FROC dataset to an ROC dataset
#' 
#' @description Convert an FROC dataset to a highest rating inferred ROC dataset
#'  
#' 
#' @param dataset The FROC dataset to be converted, \code{\link{RJafroc-package}}.
#' 
#' @return An ROC dataset with \strong{finite} ratings in NL[,,1:K1,1] and LL[,,1:K2,1]. 
#' 
#' @details The first member of the ROC dataset is \code{NL}, whose 3rd dimension has
#' length \code{(K1 + K2)}, the total number of cases. Ratings of cases \code{(K1 + 1)} 
#' through \code{(K1 + K2)} are \code{-Inf}. \strong{This is because in an ROC dataset 
#' FPs are only possible on non-diseased cases.}The second member of the list is \code{LL}. 
#' Its 3rd dimension has length K2, the number of diseased cases.  \strong{This is 
#' because TPs are only possible on diseased cases}. For each case the  
#' inferred ROC rating is the highest of all FROC ratings on that case. If a case has 
#' no marks, a \strong{finite ROC rating, guaranteed to be smaller than the rating on 
#' any marked case}, is assigned to it. The dataset structure is shown below:
#' \itemize{
#' \item{\code{NL}}{ Ratings array [1:I, 1:J, 1:(K1+K2), 1], of false positives, FPs}
#' \item{\code{LL}}{ Ratings array [1:I, 1:J, 1:K2, 1], of true positives, TPs}
#' \item{\code{perCase}}{ array [1:K2], number of lesions per diseased case}
#' \item{\code{IDs}}{ array [1:K2, 1], labels of lesions on diseased cases}
#' \item{\code{weights}}{ array [1:K2, 1], weights (or clinical importances) of lesions}
#' \item{\code{dataType}}{ "ROC", the data type}
#' \item{\code{modalityID}}{ [1:I] inherited modality labels}
#' \item{\code{readerID}}{ [1:J] inherited reader labels}
#' } 
#'
#' @examples
#' rocDataSet <- DfFroc2Roc(dataset05)
#' 
#' ## in the following example, because of the smaller number of cases, 
#' ## it is easy to see the process at work:
#' 
#' set.seed(1);K1 <- 3;K2 <- 5
#' mu <- 1;nu <- 0.5;lambda <- 2;zeta1 <- 0
#' lambda_i <- Util2Intrinsic(mu,lambda,nu)$lambda_i
#' nu_i <- Util2Intrinsic(mu,lambda,nu)$nu_i
#' Lmax <- 2;Lk2 <- floor(runif(K2, 1, Lmax + 1))
#' frocDataRaw <- SimulateFrocDataset(mu, lambda_i, nu_i, zeta1, I = 1, J = 1, 
#' K1, K2, perCase = Lk2)
#' hrData <- DfFroc2Roc(frocDataRaw)
#' 
#' ## print("frocDataRaw$ratings$NL[1,1,,] = ")
#' ## print("hrData$ratings$NL[1,1,1:K1,] = ")
#' ## print("frocDataRaw$ratings$LL[1,1,,] = ")
#' ## print("hrData$ratings$LL[1,1,,] = ")
#' 
#' ## following is the output
#' 
#' ## [1] "frocDataRaw$ratings$NL[1,1,,] = "
#' ## [,1]      [,2]      [,3] [,4]
#' ## [1,] 2.4046534 0.7635935      -Inf -Inf
#' ## [2,]      -Inf      -Inf      -Inf -Inf
#' ## [3,] 0.2522234      -Inf      -Inf -Inf
#' ## [4,] 0.4356833      -Inf      -Inf -Inf
#' ## [5,]      -Inf      -Inf      -Inf -Inf
#' ## [6,]      -Inf      -Inf      -Inf -Inf
#' ## [7,]      -Inf      -Inf      -Inf -Inf
#' ## [8,] 0.8041895 0.3773956 0.1333364 -Inf
#' 
#' ## > ## print("hrData$ratings$NL[1,1,1:K1,] = ")
#' ## [1] "hrData$ratings$NL[1,1,1:K1,] = "
#' ## [1] 2.4046534      -Inf 0.2522234
#' ## > ## print("frocDataRaw$ratings$LL[1,1,,] = ")
#' ## [1] "frocDataRaw$ratings$LL[1,1,,] = "
#' ## [,1] [,2]
#' ## [1,]      -Inf -Inf
#' ## [2,] 1.5036080 -Inf
#' ## [3,] 0.8442045 -Inf
#' ## [4,] 1.0467262 -Inf
#' ## [5,]      -Inf -Inf
#' ## > ## print("hrData$ratings$LL[1,1,,] = ")
#' ## [1] "hrData$ratings$LL[1,1,,] = "
#' ## [1] 0.4356833 1.5036080 0.8442045 1.0467262 0.8041895
#' ## Note that rating of the first and the last diseased case came from NL marks
#' 
#' 
#' @export

DfFroc2Roc <- function (dataset) {
  
  if (dataset$descriptions$type != "FROC") stop("This function requires an FROC dataset.")
  
  UNINITIALIZED <- RJafrocEnv$UNINITIALIZED
  
  NL <- dataset$ratings$NL
  LL <- dataset$ratings$LL
  
  I <- length(dataset$ratings$NL[,1,1,1])
  J <- length(dataset$ratings$NL[1,,1,1])
  K <- length(dataset$ratings$NL[1,1,,1])
  K2 <- length(dataset$ratings$LL[1,1,,1])
  K1 <- K - K2 
  
  # apply max() over the location index
  NL <- apply(NL, c(1, 2, 3), max)# this gets max NL ratings over location index on all cases
  LL <- apply(LL, c(1, 2, 3), max)# this gets max LL ratings over location index on diseased cases
  
  # add the fourth "unnecessary" dimension
  dim(NL) <- c(dim(NL), 1)
  
  # get max over location index for diseased cases, counting both NLs and LLs
  LLTmp <- array(dim = c(I, J, K2, 2))      # last index is 2, not maxLL, 1 for NLs on diseased cases and 
  # 2 for LLs
  LLTmp[ , , , 1] <- NL[ , , (K1 + 1):K, 1] # this contains the max NL on diseased cases
  LLTmp[ , , , 2] <- LL                     # this contains the max LL on diseased cases
  LL <- apply(LLTmp, c(1, 2, 3), max)       # this contains the max(max LL or max NL on diseased case), 
  # whichever is higher
  # add the fourth "unnecessary" dimension
  dim(LL) <- c(dim(LL), 1)
  
  # remove -Infs ....
  # unmarked FROC images can have -Infs; these belong in the lowest ROC bin;
  # -Inf is not allowed as an ROC rating (will throw off binning alg)
  # find the lowest conf.level that is
  # not -Inf and set OneLtMinRating to one less than this value
  OneLtMinRating <- min(c(NL[NL != UNINITIALIZED],LL[LL != UNINITIALIZED])) - 1 # one less than lowest value
  NL[NL == UNINITIALIZED] <- OneLtMinRating # replace UNINITIALIZED values with OneLtMinRating
  LL[LL == UNINITIALIZED] <- OneLtMinRating # ditto
  
  # tailor the lesions list for an ROC dataset
  perCase <- rep(1, times = K2)
  IDs <- perCase
  dim(IDs) <- c(K2, 1)
  weights <- IDs
  
  # create dataset and return
  modalityID <- as.character(seq(1:I))
  readerID <- as.character(seq(1:J))
  fileName <- paste0("DfFroc2Roc(", dataset$descriptions$fileName, ")")
  name <- dataset$descriptions$name
  design <- dataset$descriptions$design
  
  type <- "ROC"
  truthTableStr <- AddTruthTableStr(dataset, type, perCase) # added 9/16/2023
  ds <- convert2dataset(NL, LL, LL_IL = NA, 
                             perCase, IDs, weights,
                             fileName, type, name, truthTableStr = truthTableStr, design,
                             modalityID, readerID)
  
  return (ds)
}

# In the following example, the highest rating comes from LLs on diseased cases for all 
# except case 51, where the highest rating comes from an NL rated 4 as indicated by the
# parenthesis around the rating
# > frocData$ratings$NL[1,1,46:55,]
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [2,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [3,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [4,]    7    9 -Inf -Inf -Inf -Inf -Inf
# [5,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [6,]  (4) -Inf -Inf -Inf -Inf -Inf -Inf # this is case 51
# [7,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [8,]    4 -Inf -Inf -Inf -Inf -Inf -Inf
# [9,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [10,]    2 -Inf -Inf -Inf -Inf -Inf -Inf

# > frocData$ratings$LL[1,1,1:10,]
# [,1] [,2] [,3]
# [1,]    5 -Inf -Inf
# [2,]   10 -Inf -Inf
# [3,]    7 -Inf -Inf
# [4,]    6    9 -Inf
# [5,] -Inf    9 -Inf
# [6,] -Inf -Inf -Inf
# [7,]   10 -Inf -Inf
# [8,]   10 -Inf -Inf
# [9,] -Inf -Inf -Inf
# [10,]    2 -Inf -Inf

# > rocData$ratings$LL[1,1,1:10,]
# [1]  5 10  7  9  9  (4) 10 10  0  2 # note that highest rating (4) is from NL on dis. case

# Another example
# > frocData$ratings$NL[1,3,46:55,]
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [2,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [3,]  (7)    7 -Inf -Inf -Inf -Inf -Inf  # this contributes highest rating
# [4,]  (10) -Inf -Inf -Inf -Inf -Inf -Inf # this contributes highest rating
# [5,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [6,]  (9)    8    8 -Inf -Inf -Inf -Inf  # this contributes highest rating
# [7,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf
# [8,]    8 -Inf -Inf -Inf -Inf -Inf -Inf
# [9,]    9    8 -Inf -Inf -Inf -Inf -Inf
# [10,] -Inf -Inf -Inf -Inf -Inf -Inf -Inf

# > frocData$ratings$LL[1,3,1:10,]
# [,1] [,2] [,3]
# [1,]    8 -Inf -Inf
# [2,]    9 -Inf -Inf
# [3,] -Inf -Inf -Inf
# [4,]    9    9 -Inf
# [5,] -Inf    9 -Inf
# [6,] -Inf -Inf -Inf
# [7,]    9 -Inf -Inf
# [8,]   10 -Inf -Inf
# [9,]    9 -Inf -Inf
# [10,] -Inf -Inf -Inf
# > rocData$ratings$LL[1,3,1:10,]

# [1]  8  9  (7) (10)  9  (9)  9 10  9  0
dpc10ster/rjafroc documentation built on Jan. 18, 2024, 4:37 a.m.