Nothing
#' Sharp bound
#'
#' `sharpbound()` returns a list with the sharp bound. All sensitivity parameters for
#' the population of interest must be set to numbers, and the rest can be left
#' as `NULL`. The sensitivity parameters can be inserted directly or as output
#' from `sensitivityparametersM()`.
#'
#' @param whichEst Input string. Defining the causal estimand of interest.
#' Available options are as follows. (1) Risk ratio in the total
#' population: `"RR_tot"`, (2) Risk difference in the total population:
#' `"RD_tot"`, (3) Risk ratio in the subpopulation: `"RR_sub"`, (4) Risk
#' difference in the subpopulation: `"RD_sub"`.
#' @param sens Possible method to input sensitivity parameters. `sens` can
#' be the output from sensitivityparametersM(), a data.frame with columns
#' 'parameter' and 'value', or a name list with correct names (e.g.
#' `"RR_UY_T1"`, `"RR_UY_T0"`, etc.). If not supplied, parameters can be
#' entered manually as specified below.
#' @param pY1_T1_S1 Input value. The probability P(Y=1|T=1,I_S=1). Must be
#' between 0 and 1.
#' @param pY1_T0_S1 Input value. The probability P(Y=1|T=0,I_S=1). Must be
#' between 0 and 1.
#' @param pT1_S1 Input value. The probability P(T=1|I_S=1). Must be
#' between 0 and 1. Only needed for the causal estimands in the subpopulation.
#' @param pT0_S1 Input value. The probability P(T=1|I_S=1). Must be
#' between 0 and 1. Only needed for the causal estimands in the subpopulation.
#' @param pS1_T1 Input value. The probability P(I_S=1|T=1). Must be
#' between 0 and 1. Can be set to 0 if the value is unknown. Only needed
#' for the causal estimands in the total population.
#' @param pS1_T0 Input value. The probability P(I_S=1|T=0). Must be
#' between 0 and 1. Can be set to 0 if the value is unknown. Only needed
#' for the causal estimands in the total population.
#' @param RR_UY_T1 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_UY|T=1. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_UY_T0 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_UY|T=0. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_SU_11 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_SU|11. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_SU_00 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_SU|00. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_SU_10 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_SU|10. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_SU_01 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_SU|01. Must be greater than or equal to 1.
#' Used in the bounds for the total population.
#' @param RR_UY_S1 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_UY|S=1. Must be greater than or equal to 1.
#' Used in the bounds for the subpopulation.
#' @param RR_TU_1 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_TU|1. Must be greater than or equal to 1.
#' Used in the bounds for the subpopulation.
#' @param RR_TU_0 Possible method to input sensitivity parameter.
#' The sensitivity parameter RR_TU|0. Must be greater than or equal to 1.
#' Used in the bounds for the subpopulation.
#'
#' @return A list containing the sharp lower and upper bounds.
#' @export
#'
#' @examples
#' # Example for risk ratio in the total population.
#' sharpbound(whichEst = "RR_tot", pY1_T1_S1 = 0.05, pY1_T0_S1 = 0.01,
#' pS1_T1 = 0.2, pS1_T0 = 0.7, RR_UY_T1 = 2, RR_UY_T0 = 2, RR_SU_11 = 1.7,
#' RR_SU_00 = 1.5, RR_SU_10 = 2.1, RR_SU_01 = 2.3)
#'
#' # Example for risk difference in the total population.
#' sharpbound(whichEst = "RD_tot", pY1_T1_S1 = 0.05, pY1_T0_S1 = 0.01,
#' pS1_T1 = 0.2, pS1_T0 = 0.7, RR_UY_T1 = 2, RR_UY_T0 = 2, RR_SU_11 = 1.7,
#' RR_SU_00 = 1.5, RR_SU_10 = 2.1, RR_SU_01 = 2.3)
#'
#' # Example for risk ratio in the subpopulation.
#' sharpbound(whichEst = "RR_sub", pY1_T1_S1 = 0.05, pY1_T0_S1 = 0.01,
#' pT1_S1 = 0.2, pT0_S1 = 0.1, RR_UY_S1 = 2.71, RR_TU_1 = 1.91, RR_TU_0 = 2.33)
#'
#' # Example for risk difference in the subpopulation.
#' sharpbound(whichEst = "RD_sub", pY1_T1_S1 = 0.05, pY1_T0_S1 = 0.01,
#' pT1_S1 = 0.2, pT0_S1 = 0.1, RR_UY_S1 = 2.71, RR_TU_1 = 1.91, RR_TU_0 = 2.33)
#'
#' # Example specifying the sensitivity parameters from sensitivityparametersM().
#' # Risk ratio in the subpopulation. DGP from the zika example.
#' V = matrix(c(1, 0, 0.85, 0.15), ncol = 2)
#' U = matrix(c(1, 0, 0.5, 0.5), ncol = 2)
#' Tr = c(-6.2, 1.75)
#' Y = c(-5.2, 5.0, -1.0)
#' S = matrix(c(1.2, 2.2, 0.0, 0.5, 2.0, -2.75, -4.0, 0.0), ncol = 4)
#' probT1 = 0.286
#' probT0 = 0.004
#' senspar = sensitivityparametersM(whichEst = "RR_sub", whichBound = "sharp",
#' Vval = V, Uval = U, Tcoef = Tr, Ycoef = Y, Scoef = S, Mmodel = "L",
#' pY1_T1_S1 = probT1, pY1_T0_S1 = probT0)
#'
#' sharpbound(whichEst = "RR_sub", sens = senspar, pY1_T1_S1 = probT1,
#' pY1_T0_S1 = probT0, pT1_S1 = 0.99, pT0_S1 = 0.01)
#'
#'
#' @references Zetterstrom S, Sjölander A, Waernbaum I. "Investigations of sharp bounds
#' for causal effects under selection bias." Statistical Methods in Medical
#' Research (2025).
#'
#'
sharpbound <- function(whichEst, sens = NULL, pY1_T1_S1, pY1_T0_S1, pT1_S1 = NULL,
pT0_S1 = NULL, pS1_T1 = NULL, pS1_T0 = NULL,
RR_UY_T1 = NULL, RR_UY_T0 = NULL, RR_SU_11 = NULL,
RR_SU_00 = NULL, RR_SU_10 = NULL, RR_SU_01 = NULL,
RR_UY_S1 = NULL, RR_TU_1 = NULL, RR_TU_0 = NULL)
{
if (!is.null(sens)) {
# Case 1: Output from sensitivityparametersM()
if (inherits(sens, "sensparams")) {
params <- stats::setNames(as.numeric(sens$value), sens$parameter)
# Case 2: Data frame with columns 'parameter' and 'value'
} else if (is.data.frame(sens)) {
params <- stats::setNames(as.numeric(sens$value), sens$parameter)
# Case 3: Named list with correct names
} else if (is.list(sens)) {
params <- unlist(sens)
} else {
stop("'sens' must be a named list (with correct names), data.frame (with columns 'parameter' and 'value'), or 'sensparams' object.")
}
}
# Check if the estimand is one of the four "RR_tot", "RD_tot", "RR_sub", "RD_sub".
if(whichEst != "RR_tot" & whichEst != "RD_tot" & whichEst != "RR_sub" & whichEst != "RD_sub")
stop('The estimand must be "RR_tot", "RD_tot", "RR_sub" or "RD_sub".')
# Check if the probabilities are valid.
if((pY1_T1_S1 < 0 | pY1_T1_S1 > 1 | pY1_T0_S1 < 0 | pY1_T0_S1 > 1))
stop("P(Y=1|T=1,I_S=1) and P(Y=1|T=0,I_S=1) cannot be smaller than 0 or larger than 1.")
# Check if the probabilities are valid.
if(!is.null(pT1_S1) & !is.null(pT0_S1))
{
if((pT1_S1 > 1 | pT0_S1 > 1 | pT1_S1 < 0 | pT0_S1 < 0))
stop("P(T=1|I_S=1) and P(T=0|I_S=1) cannot be smaller than 0 or larger than 1 (if not set to NULL).")
}
# Check if the probabilities are valid.
if(!is.null(pS1_T1) & !is.null(pS1_T0))
{
if((pS1_T1 > 1 | pS1_T0 > 1 | pS1_T1 < 0 | pS1_T0 < 0))
stop("P(I_S=1|T=1) and P(I_S=1|T=0) cannot be smaller than 0 or larger than 1 (if not set to NULL).")
}
# The observational estimands.
RRobs = pY1_T1_S1 / pY1_T0_S1
RDobs = pY1_T1_S1 - pY1_T0_S1
pS0_T1 = 1 - pS1_T1
pS0_T0 = 1 - pS1_T0
# Calculations for the total population.
if(whichEst == "RR_tot" | whichEst == "RD_tot")
{
# Extracting the sensitivity parameters from the input list.
if (!is.null(sens))
{
RR_UY_T1 = params[["RR_UY|T=1"]]
RR_UY_T0 = params[["RR_UY|T=0"]]
RR_SU_11 = params[["RR_SU|11"]]
RR_SU_00 = params[["RR_SU|00"]]
RR_SU_10 = params[["RR_SU|10"]]
RR_SU_01 = params[["RR_SU|01"]]
}
# Check if the correct sensitivity parameters are specified.
if(is.null(RR_UY_T1) | is.null(RR_UY_T0) | is.null(RR_SU_11) | is.null(RR_SU_00) | is.null(RR_SU_10) | is.null(RR_SU_01))
stop("When the total population is of interest, RR_UY_T1, RR_UY_T0,
RR_SU_11, RR_SU_00, RR_SU_10, and RR_SU_01 cannot be equal to NULL." )
if(is.null(pS1_T1) & is.null(pS1_T0))
stop("P(I_S=1|T=1) and P(I_S=1|T=0) cannot be NULL when the total population is of interest. If thery are unknown, they can be set to 0 for conservative bounds.")
# Check if the sensitivity parameters are valid.
if(RR_UY_T1 < 1 | RR_UY_T0 < 1 | RR_SU_11 < 1 | RR_SU_00 < 1 | RR_SU_10 < 1 | RR_SU_01 < 1)
stop("All sensitivity parameters must be greater than or equal to 1.")
# Calculate BF_11, BF_00, BF_10, and BF_01. Used in both "RR_tot" and "RD_tot".
BF11 = (RR_UY_T1 * RR_SU_11) / (RR_UY_T1 + RR_SU_11 - 1)
BF00 = (RR_UY_T0 * RR_SU_00) / (RR_UY_T0 + RR_SU_00 - 1)
BF10 = (RR_UY_T1 * RR_SU_10) / (RR_UY_T1 + RR_SU_10 - 1)
BF01 = (RR_UY_T0 * RR_SU_01) / (RR_UY_T0 + RR_SU_01 - 1)
lower_pY1_T1 = pY1_T1_S1 * (pS1_T1 + pS0_T1 * BF11)
upper_pY1_T1 = pY1_T1_S1 * (pS1_T1 + pS0_T1 * min(BF10, 1 / pY1_T1_S1))
lower_pY1_T0 = pY1_T0_S1 * (pS1_T0 + pS0_T0 * BF01)
upper_pY1_T0 = pY1_T0_S1 * (pS1_T0 + pS0_T0 * min(BF00, 1 / pY1_T0_S1))
# Sharp bound for RR in tot pop.
lowerboundRRtot = round((lower_pY1_T1 / upper_pY1_T0), 2)
upperboundRRtot = round((upper_pY1_T1 / lower_pY1_T0), 2)
# Sharp bound for RD in tot pop.
lowerboundRDtot = round((lower_pY1_T1 - upper_pY1_T0), 2)
upperboundRDtot = round((upper_pY1_T1 - lower_pY1_T0), 2)
}else
{ # Calculations for the subpopulation.
if (!is.null(sens))
{
# Extracting the sensitivity parameters from the input list.
RR_UY_S1 = params[["RR_UY|S=1"]]
RR_TU_1 = params[["RR_TU|1"]]
RR_TU_0 = params[["RR_TU|0"]]
}
# Check if the correct sensitivity parameters are specified.
if(is.null(RR_UY_S1) | is.null(RR_TU_1 ) | is.null(RR_TU_0))
stop("When the subpopulation is of interest, RR_UY_S1, RR_TU_1, and RR_TU_0 cannot be equal to NULL." )
if(is.null(pT1_S1) & is.null(pT0_S1))
stop("P(T=1|I_S=1) and P(T=0|I_S=1) cannot be NULL when the subpopulation is of interest.")
# Check if the sensitivity parameters are valid.
if(RR_UY_S1 < 1 | RR_TU_1 < 1 | RR_TU_0 < 1)
stop("All sensitivity parameters must be greater than or equal to 1.")
# Calculate BF_1. Used in both "RR_sub" and "RD_sub".
BF1 = (RR_UY_S1 * RR_TU_1) / (RR_UY_S1 + RR_TU_1 - 1)
BF0 = (RR_UY_S1 * RR_TU_0) / (RR_UY_S1 + RR_TU_0 - 1)
lower_pY11_S1 = pY1_T1_S1 * (pT1_S1 + pT0_S1 / BF1)
upper_pY11_S1 = pY1_T1_S1 * (pT1_S1 + pT0_S1 * min(BF0, (1 / pY1_T1_S1)))
lower_pY01_S1 = pY1_T0_S1 * (pT0_S1 + pT1_S1 * BF0)
upper_pY01_S1 = pY1_T0_S1 * (pT0_S1 + pT1_S1 * min(BF1, (1 / pY1_T0_S1)))
# Sharp bound for RR in subpop.
lowerboundRRs = round((lower_pY11_S1 / upper_pY01_S1), 2)
upperboundRRs = round((upper_pY11_S1 / lower_pY01_S1), 2)
# Sharp bound for RD in subpop.
lowerboundRDs = round((lower_pY11_S1 - upper_pY01_S1), 2)
upperboundRDs = round((upper_pY11_S1 - lower_pY01_S1), 2)
}
# The return list.
heading = c("Sharp lower bound", "Sharp upper bound")
if(whichEst == "RR_tot"){
values = list(lowerboundRRtot, upperboundRRtot)
}else if(whichEst == "RD_tot"){
values = list(lowerboundRDtot,upperboundRDtot)
}else if(whichEst == "RR_sub"){
values = list(lowerboundRRs, upperboundRRs)
}else{
values = list(lowerboundRDs, upperboundRDs)
}
returnDat = matrix(cbind(heading, values), ncol = 2)
return(returnDat)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.