Simulate outcomes from an individual-level continuous time state transition model (CTSTM). The class supports "clock-reset" (i.e., semi-Markov), "clock-forward" (i.e., Markov), and mixtures of clock-reset and clock-forward multi-state models as described in IndivCtstmTrans.

Format

An R6::R6Class object.

References

Incerti and Jansen (2021). See Section 2.2 for a mathematical description of an individual-level CTSTM and Section 4.1 for an example in oncology.

See also

The IndivCtstmTrans documentation describes the class for the transition model and the StateVals documentation describes the class for the cost and utility models. An IndivCtstmTrans object is typically created using create_IndivCtstmTrans().

There are currently two relevant vignettes. vignette("mstate") shows how to parameterize IndivCtstmTrans objects in cases where patient-level data is available by fitting a multi-state models. vignette("markov-inhomogeneous-indiv") shows how the time inhomogeneous Markov cohort model in vignette("markov-inhomogeneous-cohort") can be developed as an individual patient simulation; in doing so, it shows how IndivCtstm models can be used even without access to patient-level data.

Public fields

trans_model

The model for health state transitions. Must be an object of class IndivCtstmTrans.

utility_model

The model for health state utility. Must be an object of class StateVals.

cost_models

The models used to predict costs by health state. Must be a list of objects of class StateVals, where each element of the list represents a different cost category.

disprog_

An object of class disprog.

stateprobs_

An object of class stateprobs simulated using $sim_stateprobs().

qalys_

An object of class qalys simulated using $sim_qalys().

costs_

An object of class costs simulated using $sim_costs().

Methods


Method new()

Create a new IndivCtstm object.

Usage

IndivCtstm$new(trans_model = NULL, utility_model = NULL, cost_models = NULL)

Arguments

trans_model

The trans_model field.

utility_model

The utility_model field.

cost_models

The cost_models field.

Returns

A new IndivCtstm object.


Method sim_disease()

Simulate disease progression (i.e., individual trajectories through a multi-state model) using IndivCtstmTrans$sim_disease().

Usage

IndivCtstm$sim_disease(max_t = 100, max_age = 100, progress = NULL)

Arguments

max_t

A scalar or vector denoting the length of time to simulate the model. If a vector, must be equal to the number of simulated patients.

max_age

A scalar or vector denoting the maximum age to simulate each patient until. If a vector, must be equal to the number of simulated patients.

progress

An integer, specifying the PSA iteration (i.e., sample) that should be printed every progress PSA iterations. For example, if progress = 2, then every second PSA iteration is printed. Default is NULL, in which case no output is printed.

Returns

An instance of self with simulated output stored in disprog_.


Method sim_stateprobs()

Simulate health state probabilities as a function of time using the simulation output stored in disprog.

Usage

IndivCtstm$sim_stateprobs(t)

Arguments

t

A numeric vector of times.

Returns

An instance of self with simulated output of class stateprobs stored in stateprobs_.


Method sim_qalys()

Simulate quality-adjusted life-years (QALYs) as a function of disprog_ and utility_model.

Usage

IndivCtstm$sim_qalys(
  dr = 0.03,
  type = c("predict", "random"),
  lys = TRUE,
  by_patient = FALSE
)

Arguments

dr

Discount rate.

type

"predict" for mean values or "random" for random samples as in $sim() in StateVals.

lys

If TRUE, then life-years are simulated in addition to QALYs.

by_patient

If TRUE, then QALYs and/or costs are computed at the patient level. If FALSE, then they are averaged across patients by health state.

Returns

An instance of self with simulated output of class qalys stored in qalys_.


Method sim_costs()

Simulate costs as a function of disprog_ and cost_models.

Usage

IndivCtstm$sim_costs(
  dr = 0.03,
  type = c("predict", "random"),
  by_patient = FALSE,
  max_t = Inf
)

Arguments

dr

Discount rate.

type

"predict" for mean values or "random" for random samples as in $sim() in StateVals.

by_patient

If TRUE, then QALYs and/or costs are computed at the patient level. If FALSE, then they are averaged across patients by health state.

max_t

Maximum time duration to compute costs once a patient has entered a (new) health state. By default, equal to Inf, so that costs are computed over the entire duration that a patient is in a given health state. If time varies by each cost category, then time can also be passed as a numeric vector of length equal to the number of cost categories (e.g., c(1, 2, Inf, 3) for a model with four cost categories).

Returns

An instance of self with simulated output of class costs stored in costs_.


Method summarize()

Summarize costs and QALYs so that cost-effectiveness analysis can be performed. See summarize_ce().

Usage

IndivCtstm$summarize(by_grp = FALSE)

Arguments

by_grp

If TRUE, then costs and QALYs are computed by subgroup. If FALSE, then costs and QALYs are aggregated across all patients (and subgroups).


Method clone()

The objects of this class are cloneable with this method.

Usage

IndivCtstm$clone(deep = FALSE)

Arguments

deep

Whether to make a deep clone.

Examples

library("flexsurv")
#> Loading required package: survival
#> 
#> Attaching package: ‘flexsurv’
#> The following object is masked from ‘package:msm’:
#> 
#>     qgeneric

# Treatment strategies, target population, and model structure
strategies <- data.frame(strategy_id = c(1, 2))
patients <- data.frame(patient_id = seq(1, 3),
                       age = c(45, 50, 60),
                       female = c(0, 0, 1))
states <- data.frame(state_id = c(1, 2))
hesim_dat <- hesim_data(strategies = strategies,
                        patients = patients,
                        states = states)

# Parameter estimation
## Multi-state model
tmat <- rbind(c(NA, 1, 2),
              c(3, NA, 4),
              c(NA, NA, NA))
fits <- vector(length = max(tmat, na.rm = TRUE), mode = "list")
surv_dat <- data.frame(mstate3_exdata$transitions)
for (i in 1:length(fits)){
  fits[[i]] <- flexsurvreg(Surv(years, status) ~ factor(strategy_id),
                           data = surv_dat,
                           subset = (trans == i),
                           dist = "weibull")
}
fits <- flexsurvreg_list(fits)

## Utility
utility_tbl <- stateval_tbl(data.frame(state_id = states$state_id,
                                       mean = mstate3_exdata$utility$mean,
                                       se = mstate3_exdata$utility$se),
                            dist = "beta")
## Costs
drugcost_tbl <- stateval_tbl(data.frame(strategy_id = strategies$strategy_id,
                                        est = mstate3_exdata$costs$drugs$costs),
                             dist = "fixed")
medcost_tbl <- stateval_tbl(data.frame(state_id = states$state_id,
                                       mean = mstate3_exdata$costs$medical$mean,
                                       se = mstate3_exdata$costs$medical$se),
                            dist = "gamma")

# Economic model
n_samples = 2

## Construct model
### Transitions
transmod_data <- expand(hesim_dat)
transmod <- create_IndivCtstmTrans(fits, input_data = transmod_data,
                                   trans_mat = tmat,
                                   n = n_samples)

### Utility
utilitymod <- create_StateVals(utility_tbl, n = n_samples, hesim_data = hesim_dat)

### Costs
drugcostmod <- create_StateVals(drugcost_tbl, n = n_samples, hesim_data = hesim_dat)
medcostmod <- create_StateVals(medcost_tbl, n = n_samples, hesim_data = hesim_dat)
costmods <- list(drugs = drugcostmod,
                 medical = medcostmod)

### Combine
ictstm <- IndivCtstm$new(trans_model = transmod,
                         utility_model = utilitymod,
                         cost_models = costmods)


## Simulate outcomes
head(ictstm$sim_disease()$disprog_)
#>    sample strategy_id patient_id grp_id  from    to final  time_start
#>     <num>       <int>      <int>  <int> <num> <num> <int>       <num>
#> 1:      1           1          1      1     1     2     0 0.000000000
#> 2:      1           1          1      1     2     3     1 0.393003227
#> 3:      1           1          2      1     1     2     0 0.000000000
#> 4:      1           1          2      1     2     3     1 1.702282887
#> 5:      1           1          3      1     1     2     0 0.000000000
#> 6:      1           1          3      1     2     1     0 0.003928804
#>      time_stop
#>          <num>
#> 1: 0.393003227
#> 2: 0.855571106
#> 3: 1.702282887
#> 4: 3.171624306
#> 5: 0.003928804
#> 6: 1.679816476
head(ictstm$sim_stateprobs(t = c(0, 5, 10))$stateprobs_[t == 5])
#>    sample strategy_id grp_id state_id     t      prob
#>     <num>       <int>  <int>    <num> <num>     <num>
#> 1:      1           1      1        1     5 0.0000000
#> 2:      1           1      1        2     5 0.0000000
#> 3:      1           1      1        3     5 1.0000000
#> 4:      1           2      1        1     5 0.3333333
#> 5:      1           2      1        2     5 0.0000000
#> 6:      1           2      1        3     5 0.6666667
ictstm$sim_qalys(dr = .03)
ictstm$sim_costs(dr = .03)

### Summarize cost-effectiveness
ce <- ictstm$summarize()
head(ce)
#> $costs
#>     category    dr sample strategy_id     costs grp_id
#>       <char> <num>  <num>       <int>     <num>  <num>
#>  1:    drugs  0.03      1           1 10144.883      1
#>  2:    drugs  0.03      1           2 38646.339      1
#>  3:    drugs  0.03      2           1 27826.855      1
#>  4:    drugs  0.03      2           2 33744.345      1
#>  5:  medical  0.03      1           1  2707.041      1
#>  6:  medical  0.03      1           2  4092.512      1
#>  7:  medical  0.03      2           1  6864.213      1
#>  8:  medical  0.03      2           2  3551.016      1
#>  9:    total  0.03      1           1 12851.924      1
#> 10:    total  0.03      1           2 42738.851      1
#> 11:    total  0.03      2           1 34691.069      1
#> 12:    total  0.03      2           2 37295.361      1
#> 
#> $qalys
#>       dr sample strategy_id    qalys grp_id
#>    <num>  <num>       <int>    <num>  <num>
#> 1:  0.03      1           1 1.756493      1
#> 2:  0.03      1           2 2.869877      1
#> 3:  0.03      2           1 5.032089      1
#> 4:  0.03      2           2 2.920488      1
#> 
format(summary(ce), pivot_from = "strategy")
#>    Discount rate        Outcome                       1                       2
#>            <num>         <fctr>                  <char>                  <char>
#> 1:          0.03          QALYs       3.39 (1.84, 4.95)       2.90 (2.87, 2.92)
#> 2:          0.03   Costs: drugs 18,986 (10,587, 27,385) 36,195 (33,867, 38,524)
#> 3:          0.03 Costs: medical    4,786 (2,811, 6,760)    3,822 (3,565, 4,079)
#> 4:          0.03   Costs: total 23,771 (13,398, 34,145) 40,017 (37,431, 42,603)