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
.
An R6::R6Class object.
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.
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.
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()
.
new()
Create a new IndivCtstm
object.
IndivCtstm$new(trans_model = NULL, utility_model = NULL, cost_models = NULL)
sim_disease()
Simulate disease progression (i.e., individual trajectories through a multi-state
model) using IndivCtstmTrans$sim_disease()
.
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.
sim_stateprobs()
Simulate health state probabilities as a function of time using the
simulation output stored in disprog
.
An instance of self
with simulated output of class stateprobs
stored in stateprobs_
.
sim_qalys()
Simulate quality-adjusted life-years (QALYs) as a function of disprog_
and
utility_model
.
IndivCtstm$sim_qalys(
dr = 0.03,
type = c("predict", "random"),
lys = TRUE,
by_patient = FALSE
)
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.
An instance of self
with simulated output of
class qalys stored in qalys_
.
sim_costs()
Simulate costs as a function of disprog_
and cost_models
.
IndivCtstm$sim_costs(
dr = 0.03,
type = c("predict", "random"),
by_patient = FALSE,
max_t = Inf
)
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).
An instance of self
with simulated output of class costs
stored in costs_
.
summarize()
Summarize costs and QALYs so that cost-effectiveness analysis can be performed.
See summarize_ce()
.
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.702282891
#> 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.855571104
#> 3: 1.702282891
#> 4: 3.171624307
#> 5: 0.003928804
#> 6: 1.679816505
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.338 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.068 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)