gmod is build on the Grammar of Modeling, and meant to allow for building decision trees and Markov models using a concise and flexible syntax. This introductory example illustrates a simple decision tree that we will gradually build on in other vignettes.

If you haven’t already, install gmod using devtools. Also, make sure to enable use_vignettes so that vignettes render correctly.

#library(devtools)
#install_github("hjalal/gmod", use_vignettes = TRUE, force = TRUE)
rm(list = ls())
library(gmod)
#> Please note that active development of gmod is now moved to twig. Please install twig https://hjalal.github.io/twig/ and review the vignettes for the latest features.

First, we define the gmod object by defining its layers.

mygmod <- gmod() + 
  decisions("A", "B") + 
  event(name = "get_infection",  
        scenarios = c(T, F), 
        probs = c(pSick(decision), Inf), 
        outcomes = c("Sick", "Healthy")) + 
  payoffs(life_expectancy = compute_le(final_outcome))

The gmod() function creates a gmod object of type “Decision” standing for a decision tree.
For a Markov model, please see the Markov model Vignette.
The decision() function describes the decision options. These can later be referred to with the special keyword (decision) below. There should be only one decisions layer per gmod object. The event_mapping() describes a single event “get_infection”. This event takes two values TRUE or FALSE. [Below we expand this to use more than two values.] If TRUE the person ends up with the “Sick” final_outcome, otherwise they end up with the “Healthy” final_outcome. The probs argument defines the probability of getting sick. Notice that we are using an external function pSick (that we will define next). This function returns a different value depending on the decision. The Inf is a place holder computes the complementary probbility (i.e., 1-pSick()) and reduces the amount of typing required. The payoffs layer defines the payoffs. Here we use a single payoff life_expectancy the value of which is computed using the compute_LE() function by taking the special keyword final_outcome defined below. final_outcomes are the outcomes of the final events in the gmod object.

pSick <- function(decision){
  if (decision == "A") 0.5 else 0.7
}

pSick is a simple function here that will return 0.5 if the decision=“A”, otherwise 0.7. Later we will show how to create more complex probabilities that can take into account the value of prior events which will help us keep the code concise.

compute_le <- function(final_outcome){
  if (final_outcome == "Sick") 20 else 40
}

Similar to pSick above, we define the compute_le() as a function of the final_outcome. If Sick, it returns 20 years, if Healthy, it returns 40 years.

NOTE: R is case sensitivie, so you have to make sure that all the oucomes, payoffs, values, decisions follow the same case. For example, if we use final_outcome=="sick" that is not the same as final_outcome=="Sick".

Then, we can build the gmod object by calling gmod_build() function which returns the formulae of our decision tree as a list

model_struc <- gmod_build(mygmod)
model_struc
#> $decisions
#> [1] "A" "B"
#> 
#> $n_decisions
#> [1] 2
#> 
#> $n_events
#> [1] 1
#> 
#> $final_outcomes
#> [1] "Sick"    "Healthy"
#> 
#> $n_final_outcomes
#> [1] 2
#> 
#> $events
#> [1] "get_infection"
#> 
#> $payoffs
#> $payoffs$life_expectancy
#> compute_le(final_outcome)
#> 
#> 
#> $payoff_names
#> [1] "life_expectancy"
#> 
#> $n_payoffs
#> [1] 1
#> 
#> $final_outcome_formulae
#> # A tibble: 4 × 6
#> # Groups:   decision, final_outcome [4]
#>   decision final_outcome path_id probs            get_infection life_expectancy 
#>   <chr>    <chr>           <dbl> <chr>            <chr>         <chr>           
#> 1 A        Healthy             2 (1-(pSick('A'))) FALSE         compute_le('Hea…
#> 2 A        Sick                1 (pSick('A'))     TRUE          compute_le('Sic…
#> 3 B        Healthy             2 (1-(pSick('B'))) FALSE         compute_le('Hea…
#> 4 B        Sick                1 (pSick('B'))     TRUE          compute_le('Sic…
#> 
#> $summary_formulae
#> # A tibble: 2 × 2
#>   decision life_expectancy                                                      
#>   <chr>    <chr>                                                                
#> 1 A        (1-(pSick('A')))*compute_le('Healthy')+(pSick('A'))*compute_le('Sick…
#> 2 B        (1-(pSick('B')))*compute_le('Healthy')+(pSick('B'))*compute_le('Sick…
#> 
#> attr(,"class")
#> [1] "gmod_decision"
gmod_gen_model_function(model_struc)
#> Warning in gmod_gen_model_function.gmod_decision(model_struc): Model function my_decision_model is generated. It can be run by calling it directly:
#> my_decision_model(params)
#> $decisions
#> [1] "A" "B"
#> 
#> $n_decisions
#> [1] 2
#> 
#> $n_events
#> [1] 1
#> 
#> $final_outcomes
#> [1] "Sick"    "Healthy"
#> 
#> $n_final_outcomes
#> [1] 2
#> 
#> $events
#> [1] "get_infection"
#> 
#> $payoffs
#> $payoffs$life_expectancy
#> compute_le(final_outcome)
#> 
#> 
#> $payoff_names
#> [1] "life_expectancy"
#> 
#> $n_payoffs
#> [1] 1
#> 
#> $final_outcome_formulae
#> # A tibble: 4 × 6
#> # Groups:   decision, final_outcome [4]
#>   decision final_outcome path_id probs            get_infection life_expectancy 
#>   <chr>    <chr>           <dbl> <chr>            <chr>         <chr>           
#> 1 A        Healthy             2 (1-(pSick('A'))) FALSE         compute_le('Hea…
#> 2 A        Sick                1 (pSick('A'))     TRUE          compute_le('Sic…
#> 3 B        Healthy             2 (1-(pSick('B'))) FALSE         compute_le('Hea…
#> 4 B        Sick                1 (pSick('B'))     TRUE          compute_le('Sic…
#> 
#> $summary_formulae
#> # A tibble: 2 × 2
#>   decision life_expectancy                                                      
#>   <chr>    <chr>                                                                
#> 1 A        (1-(pSick('A')))*compute_le('Healthy')+(pSick('A'))*compute_le('Sick…
#> 2 B        (1-(pSick('B')))*compute_le('Healthy')+(pSick('B'))*compute_le('Sick…
#> 
#> attr(,"class")
#> [1] "gmod_decision"
my_decision_model(model_struc)
#>   life_expectancy
#> A              30
#> B              26

This list returns information about our tree. For example, the final_outcomes and the payoffs. It also returns two tables the first one lists the expanded form of the tree and the formulae by decision and final_outcome and each path that leads to the final_outcome. The second is a summary table for the formulae involved in the payoffs. Let’s take a look at the payoff summary table.

model_struc$summary_formulae
#> # A tibble: 2 × 2
#>   decision life_expectancy                                                      
#>   <chr>    <chr>                                                                
#> 1 A        (1-(pSick('A')))*compute_le('Healthy')+(pSick('A'))*compute_le('Sick…
#> 2 B        (1-(pSick('B')))*compute_le('Healthy')+(pSick('B'))*compute_le('Sick…

This table will return two formuale for life expectancy, one per decision. For example life expectancy of A equals (1-(pSick('A')))*compute_le('Healthy')+(pSick('A'))*compute_le('Sick'). This is a meaningful formula as it describes the life expectancy of decision A as a weighted sum of probability of getting sick given A and life expectancy given each final_outcome Sick and Healthy. We can also evaluate this formula directly of gmod

(1-(pSick('A')))*compute_le('Healthy')+(pSick('A'))*compute_le('Sick')
#> [1] 30

This returns 30 years on average for treatment A.

We can formally evaluate our gmod object by calling the function gmod_evaluate():

model_res <- gmod_evaluate(model_struc)
#> Warning in gmod_evaluate.gmod_decision(model_struc): No parameters were provided. Will use the parameters from the global environment. 
#>             If instead you want to evaluate the model with specific parameter values, please provide 
#>             them here as list.
model_res
#> $summary_results
#> # A tibble: 2 × 2
#>   decision life_expectancy
#>   <chr>    <chr>          
#> 1 A        30             
#> 2 B        26             
#> 
#> attr(,"class")
#> [1] "gmod_decision"

The main output is a table containing the values of the payoffs. We can see the 30 years for A, and also we can see that the life expectancy for B is 26 years. Which we can double check by examing the formula for B:

(1-(pSick('B')))*compute_le('Healthy')+(pSick('B'))*compute_le('Sick')
#> [1] 26

In other vignette, we show other features, including:

  1. Event final_outcomes other than TRUE and FALSE
  2. Multiple sequential events
  3. Multiple payoffs (e.g., costs and effectiveness) for cost-effectiveness analyses
  4. The probability of an event depending on the final_outcome of upstream events
  5. The payoffs depending on the intermediate final_outcomes from upstream events