twig is an R package designed to simplify decision and cost-effectiveness analyses. It introduces a Grammar of Modeling approach, inspired by the Grammar of Graphics in ggplot2, to streamline the creation, maintenance, and debugging of complex models.
Key features include:
- Vectorized operations for efficient computation.
- Flexible modeling of decisions, states, events, and payoffs.
- Interactive syntax building via the DecisionTwig interface.
Install twig from CRAN or GitHub:
# Install from CRAN
install.packages("twig")
# Or install the latest development version from GitHub
library(devtools)
install_github("hjalal/twig")Below is a simple example of using twig to define a Markov model:
library(twig)
# Define a basic Markov model using `twig`
mytwig <- twig() +
decisions(names = c(A, B)) + # Decision alternatives
states(names = c(Alive, Dead), # States and initial probabilities
init_probs = c(1, 0)) +
event(name = death_event, # Define an event (death)
options = c(yes, none), # Possible outcomes
probs = c(pDie, leftover), # Probabilities
transitions = c(Dead, stay)) + # Transitions
payoffs(names = c(cost, utility)) # Define payoffs
This syntax minimizes repetition and allows you to model decisions, events, and payoffs efficiently.
In DecisionTwig, this twig model can be built interactively:
DecisionTwig is a graphical user interface for building and debugging twig syntax, making it ideal for more complex models.
Next, we define the functions used in the twig model. These functions are vectorized using ifelse statements for efficiency and can take core arguments (decision, state, cycle, cycle_in_state, and prior events):
# 1. Probability of death depends on state and decision
pDie <- function(state, decision, rrMortA) {
rDie <- ifelse(state == "Alive", # if Alive then
0.01 * # multiply base mortality (0.01) by
ifelse(decision == "A", rrMortA, 1), # a relative risk of mortality if the decision is A, otherwise 1 for B
0) # else if the state is Dead rate of death should be 0.
rate2prob(rDie) # Convert rate to probability
}
# 2. Cost depends on the decision
cost <- function(decision, cA, cB) {
ifelse(decision == "A", cA, cB) # if decision is A then cost of A, else cost of B
}
# 3. Utility depends on the state
utility <- function(state, uAlive) {
ifelse(state == "Alive", uAlive, 0) # if state is Alive then utility of alive, otherwise 0 for Dead
}You can also use concise conditional syntax (state=="Alive") which returns 1 if TRUE and 0 if FALSE to avoids nesting multiple ifelse statements, making it easier to read and maintain. See the Vignettes.
Create a probabilistic data frame for parameter sampling:
n_sims <- 1000 # Number of simulations
psa_params <- data.frame(
rrMortA = rnorm(n_sims, 0.9, 0.1), # Relative risk of mortality
cA = rlnorm(n_sims, 6, 1), # Cost of A
cB = rlnorm(n_sims, 5, 1), # Cost of B
uAlive = rbeta(n_sims, 0.8, 0.2) # Utility of being alive
)
head(psa_params) # Examine the first six samplestwig also accepts a list of scalar parameter values.
Run the model for 50 cycles (e.g., years) and compute the average expected values for costs and utilities:
results <- run_twig(twig_obj = mytwig, params = psa_params, n_cycles = 50)
results$mean_ev # Average across simulations
# payoff
# decision cost utility
# A 32379.32 32.11033
# B 12503.32 31.32062Your results may vary slightly due to randomness in the parameter sampling.
Calculate the ICER using the calculate_icers function:
calculate_icers(results$mean_ev)
# decision cost utility inc_cost inc_utility ICER status
# B B 12503.32 31.32062 NA NA NA ND
# A A 32379.32 32.11033 19875.99 0.7897148 25168.57 NDND = Not dominated
Plot the CEAC using a range of willingness-to-pay (WTP) thresholds:
plot_ceac(results$sim_ev, wtp_range = seq(0, 100000, by = 1000))-
- Transition probabilities dependent on decisions, states, time, tunnels, and prior events
- Payoffs dependent on decisions, states, time, tunnels, prior events, and discounting
-
- Building a decision tree for cost-effectiveness analysis
- Handling multiple sequential events and dependent probabilities
Both DecisionTwig and twig are under active development and are provided as-is without warranty.
This project is licensed under the GPL v3 International.
- Jalal, H. (2024). Grammar of Modelling, twig R package. Retrieved from https://github.com/hjalal/twig
- Jalal, H. (2024). DecisionTwig. Retrieved from https://www.dashlab.ca/projects/decision_twig/