R/bayesdca.h.R

Defines functions bayesdca

Documented in bayesdca

# This file is automatically generated, you probably don't want to edit this

bayesdcaOptions <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
    "bayesdcaOptions",
    inherit = jmvcore::Options,
    public = list(
        initialize = function(
            outcomes = NULL,
            outcomePos = NULL,
            predictors = NULL,
            thresholdMin = 0.01,
            thresholdMax = 0.5,
            thresholdPoints = 50,
            useExternalPrevalence = FALSE,
            externalCases = 100,
            externalTotal = 500,
            bayesianAnalysis = TRUE,
            priorStrength = 2,
            bootstrapCI = TRUE,
            bootstrapReps = 2000,
            calculateEVPI = FALSE,
            nDraws = 2000,
            directionIndicator = ">=", ...) {

            super$initialize(
                package="ClinicoPath",
                name="bayesdca",
                requiresData=TRUE,
                ...)

            private$..outcomes <- jmvcore::OptionVariable$new(
                "outcomes",
                outcomes,
                suggested=list(
                    "nominal"),
                permitted=list(
                    "factor"))
            private$..outcomePos <- jmvcore::OptionLevel$new(
                "outcomePos",
                outcomePos,
                variable="(outcomes)")
            private$..predictors <- jmvcore::OptionVariables$new(
                "predictors",
                predictors,
                suggested=list(
                    "continuous",
                    "nominal"),
                permitted=list(
                    "numeric",
                    "factor"))
            private$..thresholdMin <- jmvcore::OptionNumber$new(
                "thresholdMin",
                thresholdMin,
                default=0.01,
                min=0.001,
                max=0.5)
            private$..thresholdMax <- jmvcore::OptionNumber$new(
                "thresholdMax",
                thresholdMax,
                default=0.5,
                min=0.01,
                max=0.99)
            private$..thresholdPoints <- jmvcore::OptionInteger$new(
                "thresholdPoints",
                thresholdPoints,
                default=50,
                min=10,
                max=100)
            private$..useExternalPrevalence <- jmvcore::OptionBool$new(
                "useExternalPrevalence",
                useExternalPrevalence,
                default=FALSE)
            private$..externalCases <- jmvcore::OptionInteger$new(
                "externalCases",
                externalCases,
                default=100,
                min=1)
            private$..externalTotal <- jmvcore::OptionInteger$new(
                "externalTotal",
                externalTotal,
                default=500,
                min=2)
            private$..bayesianAnalysis <- jmvcore::OptionBool$new(
                "bayesianAnalysis",
                bayesianAnalysis,
                default=TRUE)
            private$..priorStrength <- jmvcore::OptionNumber$new(
                "priorStrength",
                priorStrength,
                default=2,
                min=0.1,
                max=10)
            private$..bootstrapCI <- jmvcore::OptionBool$new(
                "bootstrapCI",
                bootstrapCI,
                default=TRUE)
            private$..bootstrapReps <- jmvcore::OptionInteger$new(
                "bootstrapReps",
                bootstrapReps,
                default=2000,
                min=500,
                max=10000)
            private$..calculateEVPI <- jmvcore::OptionBool$new(
                "calculateEVPI",
                calculateEVPI,
                default=FALSE)
            private$..nDraws <- jmvcore::OptionInteger$new(
                "nDraws",
                nDraws,
                default=2000,
                min=500,
                max=10000)
            private$..directionIndicator <- jmvcore::OptionList$new(
                "directionIndicator",
                directionIndicator,
                options=list(
                    ">=",
                    "<="),
                default=">=")

            self$.addOption(private$..outcomes)
            self$.addOption(private$..outcomePos)
            self$.addOption(private$..predictors)
            self$.addOption(private$..thresholdMin)
            self$.addOption(private$..thresholdMax)
            self$.addOption(private$..thresholdPoints)
            self$.addOption(private$..useExternalPrevalence)
            self$.addOption(private$..externalCases)
            self$.addOption(private$..externalTotal)
            self$.addOption(private$..bayesianAnalysis)
            self$.addOption(private$..priorStrength)
            self$.addOption(private$..bootstrapCI)
            self$.addOption(private$..bootstrapReps)
            self$.addOption(private$..calculateEVPI)
            self$.addOption(private$..nDraws)
            self$.addOption(private$..directionIndicator)
        }),
    active = list(
        outcomes = function() private$..outcomes$value,
        outcomePos = function() private$..outcomePos$value,
        predictors = function() private$..predictors$value,
        thresholdMin = function() private$..thresholdMin$value,
        thresholdMax = function() private$..thresholdMax$value,
        thresholdPoints = function() private$..thresholdPoints$value,
        useExternalPrevalence = function() private$..useExternalPrevalence$value,
        externalCases = function() private$..externalCases$value,
        externalTotal = function() private$..externalTotal$value,
        bayesianAnalysis = function() private$..bayesianAnalysis$value,
        priorStrength = function() private$..priorStrength$value,
        bootstrapCI = function() private$..bootstrapCI$value,
        bootstrapReps = function() private$..bootstrapReps$value,
        calculateEVPI = function() private$..calculateEVPI$value,
        nDraws = function() private$..nDraws$value,
        directionIndicator = function() private$..directionIndicator$value),
    private = list(
        ..outcomes = NA,
        ..outcomePos = NA,
        ..predictors = NA,
        ..thresholdMin = NA,
        ..thresholdMax = NA,
        ..thresholdPoints = NA,
        ..useExternalPrevalence = NA,
        ..externalCases = NA,
        ..externalTotal = NA,
        ..bayesianAnalysis = NA,
        ..priorStrength = NA,
        ..bootstrapCI = NA,
        ..bootstrapReps = NA,
        ..calculateEVPI = NA,
        ..nDraws = NA,
        ..directionIndicator = NA)
)

bayesdcaResults <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
    "bayesdcaResults",
    inherit = jmvcore::Group,
    active = list(
        instructions = function() private$.items[["instructions"]],
        summary = function() private$.items[["summary"]],
        netBenefitTable = function() private$.items[["netBenefitTable"]],
        modelResults = function() private$.items[["modelResults"]],
        comparisonTable = function() private$.items[["comparisonTable"]],
        evpiTable = function() private$.items[["evpiTable"]],
        mainPlot = function() private$.items[["mainPlot"]],
        deltaPlot = function() private$.items[["deltaPlot"]],
        probPlot = function() private$.items[["probPlot"]],
        evpiPlot = function() private$.items[["evpiPlot"]]),
    private = list(),
    public=list(
        initialize=function(options) {
            super$initialize(
                options=options,
                name="",
                title="Bayesian Decision Curve Analysis")
            self$add(jmvcore::Html$new(
                options=options,
                name="instructions",
                title="Instructions",
                visible=TRUE))
            self$add(jmvcore::Html$new(
                options=options,
                name="summary",
                title="Analysis Summary",
                visible=TRUE))
            self$add(jmvcore::Table$new(
                options=options,
                name="netBenefitTable",
                title="Net Benefit Results",
                visible=TRUE,
                columns=list(
                    list(
                        `name`="threshold", 
                        `title`="Threshold", 
                        `type`="number", 
                        `format`="pc"),
                    list(
                        `name`="treatAll", 
                        `title`="Treat All", 
                        `type`="number", 
                        `format`="zto"),
                    list(
                        `name`="treatNone", 
                        `title`="Treat None", 
                        `type`="number", 
                        `format`="zto"))))
            self$add(jmvcore::Array$new(
                options=options,
                name="modelResults",
                title="Model/Test Results",
                visible=TRUE,
                template=jmvcore::Table$new(
                    options=options,
                    title="$key",
                    columns=list(
                        list(
                            `name`="threshold", 
                            `title`="Threshold", 
                            `type`="number", 
                            `format`="pc"),
                        list(
                            `name`="netBenefit", 
                            `title`="Net Benefit", 
                            `type`="number", 
                            `format`="zto"),
                        list(
                            `name`="lowerCI", 
                            `title`="Lower CI", 
                            `type`="number", 
                            `format`="zto", 
                            `visible`="(bayesianAnalysis || bootstrapCI)"),
                        list(
                            `name`="upperCI", 
                            `title`="Upper CI", 
                            `type`="number", 
                            `format`="zto", 
                            `visible`="(bayesianAnalysis || bootstrapCI)"),
                        list(
                            `name`="sensitivity", 
                            `title`="Sensitivity", 
                            `type`="number", 
                            `format`="pc"),
                        list(
                            `name`="specificity", 
                            `title`="Specificity", 
                            `type`="number", 
                            `format`="pc")))))
            self$add(jmvcore::Table$new(
                options=options,
                name="comparisonTable",
                title="Strategy Comparison",
                visible=TRUE,
                columns=list(
                    list(
                        `name`="threshold", 
                        `title`="Threshold", 
                        `type`="number", 
                        `format`="pc"),
                    list(
                        `name`="bestStrategy", 
                        `title`="Best Strategy", 
                        `type`="text"),
                    list(
                        `name`="diffFromNext", 
                        `title`="Difference from Next Best", 
                        `type`="number", 
                        `format`="zto"),
                    list(
                        `name`="probBest", 
                        `title`="Probability Best", 
                        `type`="number", 
                        `format`="pc", 
                        `visible`="(bayesianAnalysis)"))))
            self$add(jmvcore::Table$new(
                options=options,
                name="evpiTable",
                title="Expected Value of Perfect Information",
                visible="(calculateEVPI)",
                columns=list(
                    list(
                        `name`="threshold", 
                        `title`="Threshold", 
                        `type`="number", 
                        `format`="pc"),
                    list(
                        `name`="evpi", 
                        `title`="EVPI", 
                        `type`="number", 
                        `format`="zto"))))
            self$add(jmvcore::Image$new(
                options=options,
                name="mainPlot",
                title="Decision Curves",
                width=600,
                height=450,
                renderFun=".plotDCA",
                visible=TRUE))
            self$add(jmvcore::Image$new(
                options=options,
                name="deltaPlot",
                title="Net Benefit Differences",
                width=600,
                height=450,
                renderFun=".plotDeltaNB",
                visible=TRUE))
            self$add(jmvcore::Image$new(
                options=options,
                name="probPlot",
                title="Probability of Superiority",
                width=600,
                height=450,
                renderFun=".plotProbability",
                visible="(bayesianAnalysis)"))
            self$add(jmvcore::Image$new(
                options=options,
                name="evpiPlot",
                title="Expected Value of Perfect Information",
                width=600,
                height=450,
                renderFun=".plotEVPI",
                visible="(calculateEVPI)"))}))

bayesdcaBase <- if (requireNamespace("jmvcore", quietly=TRUE)) R6::R6Class(
    "bayesdcaBase",
    inherit = jmvcore::Analysis,
    public = list(
        initialize = function(options, data=NULL, datasetId="", analysisId="", revision=0) {
            super$initialize(
                package = "ClinicoPath",
                name = "bayesdca",
                version = c(0,0,3),
                options = options,
                results = bayesdcaResults$new(options=options),
                data = data,
                datasetId = datasetId,
                analysisId = analysisId,
                revision = revision,
                pause = NULL,
                completeWhenFilled = FALSE,
                requiresMissings = FALSE,
                weightsSupport = 'auto')
        }))

#' Bayesian Decision Curve Analysis
#'
#' 
#' @param data The data as a data frame.
#' @param outcomes Binary outcome variable (0/1) representing the true disease
#'   status or event.
#' @param outcomePos Specifies which level of the outcome variable should be
#'   treated as the positive class.
#' @param predictors Variables containing either probability predictions from
#'   models or binary results (0/1) from diagnostic tests.
#' @param thresholdMin Minimum decision threshold for the analysis.
#' @param thresholdMax Maximum decision threshold for the analysis.
#' @param thresholdPoints Number of threshold points to evaluate.
#' @param useExternalPrevalence Use external prevalence data instead of sample
#'   prevalence.
#' @param externalCases Number of cases in external prevalence data.
#' @param externalTotal Total sample size in external prevalence data.
#' @param bayesianAnalysis Perform Bayesian analysis with uncertainty
#'   quantification.
#' @param priorStrength Strength of prior (effective sample size).
#' @param bootstrapCI Calculate bootstrap confidence intervals for
#'   non-Bayesian analysis.
#' @param bootstrapReps Number of bootstrap replications for confidence
#'   intervals.
#' @param calculateEVPI Calculate Expected Value of Perfect Information.
#' @param nDraws Number of posterior draws for Bayesian analysis.
#' @param directionIndicator Direction of classification relative to the
#'   cutpoint. Use '>=' when higher values predict positive outcomes.
#' @return A results object containing:
#' \tabular{llllll}{
#'   \code{results$instructions} \tab \tab \tab \tab \tab a html \cr
#'   \code{results$summary} \tab \tab \tab \tab \tab a html \cr
#'   \code{results$netBenefitTable} \tab \tab \tab \tab \tab a table \cr
#'   \code{results$modelResults} \tab \tab \tab \tab \tab an array of tables \cr
#'   \code{results$comparisonTable} \tab \tab \tab \tab \tab a table \cr
#'   \code{results$evpiTable} \tab \tab \tab \tab \tab a table \cr
#'   \code{results$mainPlot} \tab \tab \tab \tab \tab an image \cr
#'   \code{results$deltaPlot} \tab \tab \tab \tab \tab an image \cr
#'   \code{results$probPlot} \tab \tab \tab \tab \tab an image \cr
#'   \code{results$evpiPlot} \tab \tab \tab \tab \tab an image \cr
#' }
#'
#' Tables can be converted to data frames with \code{asDF} or \code{\link{as.data.frame}}. For example:
#'
#' \code{results$netBenefitTable$asDF}
#'
#' \code{as.data.frame(results$netBenefitTable)}
#'
#' @export
bayesdca <- function(
    data,
    outcomes,
    outcomePos,
    predictors,
    thresholdMin = 0.01,
    thresholdMax = 0.5,
    thresholdPoints = 50,
    useExternalPrevalence = FALSE,
    externalCases = 100,
    externalTotal = 500,
    bayesianAnalysis = TRUE,
    priorStrength = 2,
    bootstrapCI = TRUE,
    bootstrapReps = 2000,
    calculateEVPI = FALSE,
    nDraws = 2000,
    directionIndicator = ">=") {

    if ( ! requireNamespace("jmvcore", quietly=TRUE))
        stop("bayesdca requires jmvcore to be installed (restart may be required)")

    if ( ! missing(outcomes)) outcomes <- jmvcore::resolveQuo(jmvcore::enquo(outcomes))
    if ( ! missing(predictors)) predictors <- jmvcore::resolveQuo(jmvcore::enquo(predictors))
    if (missing(data))
        data <- jmvcore::marshalData(
            parent.frame(),
            `if`( ! missing(outcomes), outcomes, NULL),
            `if`( ! missing(predictors), predictors, NULL))

    for (v in outcomes) if (v %in% names(data)) data[[v]] <- as.factor(data[[v]])

    options <- bayesdcaOptions$new(
        outcomes = outcomes,
        outcomePos = outcomePos,
        predictors = predictors,
        thresholdMin = thresholdMin,
        thresholdMax = thresholdMax,
        thresholdPoints = thresholdPoints,
        useExternalPrevalence = useExternalPrevalence,
        externalCases = externalCases,
        externalTotal = externalTotal,
        bayesianAnalysis = bayesianAnalysis,
        priorStrength = priorStrength,
        bootstrapCI = bootstrapCI,
        bootstrapReps = bootstrapReps,
        calculateEVPI = calculateEVPI,
        nDraws = nDraws,
        directionIndicator = directionIndicator)

    analysis <- bayesdcaClass$new(
        options = options,
        data = data)

    analysis$run()

    analysis$results
}
sbalci/ClinicoPathJamoviModule documentation built on June 13, 2025, 9:34 a.m.