--- title: "Basic BRAID Usage" output: rmarkdown::html_vignette bibliography: "braid.bib" vignette: > %\VignetteIndexEntry{Basic BRAID Usage} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup, include=FALSE} library(braidrm) ``` ## The BRAID Model The bivariate response to additive interacting doses (or BRAID) model is a parametric response surface model of the effect of combined doses of two agents. A full specification of the BRAID equation can be found in `vignette("derivation")`, but briefly, the BRAID model is specified by 9 parameters: a baseline minimal effect observed when no agent is present, three dose response parameters for each agent, an overall maximal effect parameter, and an interaction paramter $\kappa$ indicating the presence of a synergistic or antagonistic interaction. In the functions of the `braidrm` package, BRAID surfaces are specified by a numeric parameter vector. For a full, length-9 parameter vector, the values are the following * `IDMA`: The dose of median effect of the first agent * `IDMB`: The dose of median effect of the second agent * `na`: The Hill slope (or sigmoidicity) of the first agent * `nb`: The Hill slope (or sigmoidicity) of the second agent * `kappa`: The BRAID interaction parameter, which is between -2 and 0 for antagonistic surfaces, 0 for BRAID additive surfaces, and greater than 0 for synergistic surfaces * `E0`: The minimal effect observed when neither agent is present * `EfA`: The maximal effect of the first agent, theoretically observed at infinite concentration * `EfB`: The maximal effect of the second agent, theoretically observed at infinite concentration * `Ef`: The overall maximal effect of the combination The order of these parameters is meant to mirror the order of single-agent dose-response parameters in the `basicdrm` package: "potency" parameters, "shape" parameters (including interaction), minimal effect, maximal effects. In many cases, the response surface being modeled or studied will only need a subset of these parameters. Nearly all combination analyses assume (implicitly or explicitly) that the overall maximal effect of a combination (the parameter $E_f$) will be equal to the "larger" of the two individual maximal effects. (We place "larger" in quotes here is it refers to the effect value that is further from the minimal effect, but not necssarily the numerically greater value.) In some cases, it is even assumed that all maximal effects are simply equal to each other. For simplicity, many `braidrm` functions support shortened BRAID parameter vectors that carry these assumptions. If a BRAID parameter vector with *eight* values is passed to a `braidrm` function, it is assumed that the ninth parameter `Ef` has been left out, and the it should be equal to the "larger" of the two individual maximal effects. If a BRAID paramter vector with *seven* values is passed, it is assumed that parameters `EfA` and `EfB` have been leftout, and that they are both equal to the seventh value (assumed to be `Ef`). ## Evaluate BRAID Surfaces Creating a BRAID parameter vector is as simple as creating a numeric vector: ```{r} basicParameter <- c(1, 1, 3, 3, 0, 0, 100) ``` This vector specifies, in order, that: * The dose of median effect of drug A is 1 (the units are not specified, but for this vignette we'll assume they are micromolar) * The dose of median effect of drug B is 1 * The Hill slope of drug A is 3 * The Hill slope of drug B is 3 * The interaction parameter $\kappa$ is 0 (additivity) * The minimal effect is 0 * The overall maximal effect is 100 Because this vector is length seven, parameters `EfA` and `EfB` are implied and assumed to be equal to `Ef`. We could specify exactly the same surface with a full-length parameter vector: ```{r} fullParameter <- c(1, 1, 3, 3, 0, 0, 100, 100, 100) ``` Evaluating a BRAID surface requires the concentration or concentrations of the first drug, the concentration or concentrations of the second, and the BRAID parameter vector. For example: ```{r} evalBraidModel(1, 0, basicParameter) evalBraidModel(0, 1, basicParameter) evalBraidModel(1, 1, basicParameter) ``` The first two outputs demonstrate that, as expected, when either drug is present at 1 micromolar, we observe an effect of 50, halfway between the minimal effect and the maximal effect. The third output is noticeably higher, as when *both* drugs are present at 1 micromolar, the effect of the individual doses is compounded. We can however produce the same effect as 1 micromolar of either drug alone by halving their doses: ```{r} evalBraidModel(0.5, 0.5, basicParameter) ``` This is because the parameter vector represents an additive combination of two drugs with identical pharmacological properties. (Note that this does not work for all response surfaces, or even all BRAID additive surfaces. It is only in the case of identical Hill slopes and maximal effects that BRAID additivity aligns perfectly with the more classical Loewe additivity.) [@Loewe1926] We can also see that using the full, length-9 parameter vector produces exactly the same results: ```{r} evalBraidModel(1, 0, fullParameter) evalBraidModel(0, 1, fullParameter) evalBraidModel(0.5, 0.5, fullParameter) ``` Note what happens, however, when we introduce an interaction to the response surface (in this case, as $\kappa$ is positive, a synergistic interaction): ```{r} synergyParameter <- c(1, 1, 3, 3, 1.5, 0, 100) evalBraidModel(1, 0, synergyParameter) evalBraidModel(0, 1, synergyParameter) evalBraidModel(0.5, 0.5, synergyParameter) ``` While the effect of the individual drugs is unchanged, their combined effect is increased. This is the classic pharmacological definition of synergy: an effect in combination which is larger *than what would be expected*. What precisely is "expected" for any given pair of drugs is one of the primary debates of combination analysis; BRAID additivity is only one answer, albeit the one around which we have built the BRAID system. ## Fitting BRAID Surfaces ```{r, include=FALSE} set.seed(20240804) ``` Of course, the most common usage of the BRAID model is fitting it to experimental data to summarize and quantify that data. The main workhorse function for this task is `braidrm`, which produces a fit object of class `braidrm`. We can see it in action with the example data-set `additiveExample`: ```{r} head(additiveExample) additiveFit <- braidrm(measure ~ concA + concB, additiveExample) summary(additiveFit) ``` The data frame `additiveExample` is a synthetically generated set of response surface measurements, and contains four columns: `concA`, containing the dose of drug A for each measurement; `concB`, containing the dose of drug B for each measurement; `truth` containing the ground truth response generated by an additive response surface with effect ranging from 0 to 1; and `measure`, a noisy measurement sampled from a normal distribution centered on the ground truth with a standard deviation of 0.07. By default, `braidrm()` fits an eight-paramter BRAID surface (one which assumes the overall maximal effect is equal to the larger of the two individual maximal effects) to the given data with a moderate prior on the interaction parameter $\kappa$. (See `vignette("modelsAndConstraints")` for more details on specifying the BRAID model to be fit, and `vignette("bayesianKappa")` for a more in-depth explanation of the Bayesian stabilization of $\kappa$). By default `braidrm()` also estimates bootstrapped confidence intervals on all fit parameters, as can be seen the printed summary; note in particular that 0 lies within the confidence interval on $\kappa$, indicating no statistically significant deviation from BRAID additivity. (Estimating confidence intervals can take several seconds; so if you are running many fits and do not need the confidence intervals, you can forgo them by setting the parameter `getCIs` to `FALSE`.) We get a very different result, however, when we fit the example data-set `synergisticExample`, which has the same format as `additiveExample` but was generated with a synergistic parameter vector with a $\kappa$ of 2: ```{r} synergisticFit <- braidrm(measure ~ concA + concB, synergisticExample) summary(synergisticFit) ``` Though most of the parameter estimates are very similar (indeed the generating parameter vectors are identical except for $\kappa$), the confidence interval on $\kappa$ lies well above zero, centered quite close the true value of 2. Another useful fitting function is `findBestBraid()`, which uses the Bayesian or Akaike information criterion to select among several candidate models (again, see `vignette("modelsAndConstraints")` for more details) [@Schwarz1978, @Akaike1974]. This allows the user to stabilize underdetermined values to reasonable defaults and reduces the frequency of wildly implausible over-fitting. We have run the function on `antagonisticExample`, which, as the name implies, contains a synthetically generated set of response surface measurements taken on an antagonistic response surface with a true $\kappa$ of $-1$. The usage of `findBestBraid()` is very similar to that of `braidrm()`: ```{r} bestFit <- findBestBraid(measure ~ concA + concB, antagonisticExample, defaults = c(0,1)) summary(bestFit) ``` The `defaults` parameter here indicates that, absent any other evidence, we expect the minimal effect to 0 and the maximal effects to be 1, so simpler models that assume these fixed values and explain the data equally well should be preferred. This time the confidence interval on $\kappa$ lies well below zero and comfortably encloses the true value of $-1$. No confidence intervals on either minimal or maximal effects are included, indicating that the most parsimonious model was one which fixed `E0` at 0 and the three maximal effects at the default 1.