It is actually possible to simulate discrete subject visits in the current version of badminton. However, due to complexity of specifying progression graphs, this is not recommended. This vignette briefly describes how a visit schedule could be implemented. This is followed by a full specification for the implementation of discrete visits and a guide as to how they could be implemented.
Suppose there are three states progressing
, progressed
and death
with exponentially distributed transition times with rate parameters 0.2 (progressing -> progressed
) and 4 (progressed -> death
). However, subjects only know they have entered progressed
at a discrete visit point and subjects make visits four times a month (i.e. at time = 0.25, 0.5, 0.75, 1.0,...)
The DAG we specify has an extra node hiddenProgressed
and at every visit when no progression has occurred, a subject transitions from progressing
into progressing
and the patient switch times reset. Note this means we no longer have a DAG and a warning message is displayed.
library("badminton") graph.par(list(nodes=list(fontsize=30))) g <- InitializeProgressionGraph() g <- AddNode.ProgressionGraph(g,c("progressing","hiddenProgressed","progressed","death")) g <- AddEdge.ProgressionGraph(g,c("progressing","progressing","hiddenProgressed","progressed","hiddenProgressed"), c("progressing","hiddenProgressed","progressed","death","death")) g <- SetIsResetEdge.ProgressionGraph(g,"progressing","progressing",isResetEdge=TRUE) plot(g)
We define a patient switch point at 0.25 and set up the simulator:
switches <- InitializeStudySwitches() switches <- SetSubjectSwitchTimes.Switches(switches,0,0.25) rModel <- simpleAccrual(duration=0, weight=1.0) mySim <- InitializeEventSim(progressionGraph=g,switches=switches,rModel)
For the progressing
node we have the following transition rates:
#Before a visit you never transition back into progressing mySim <- InsertRate.EventSim(mySim,"progressing","progressing",calendarStartTime=0,patientStartTime=0,rate=0) #If you have not progressed by the visit time then you transition into progressing and #the patient switch times are reset As isResetEdge = TRUE mySim <- InsertRate.EventSim(mySim,"progressing","progressing",calendarStartTime=0,patientStartTime=0.25,rate=Inf) mySim <- InsertRate.EventSim(mySim,"progressing","hiddenProgressed",rate=0.2)
For the progressed node we have the following transition rates:
#Before a visit cannot know you are progressed mySim <- InsertRate.EventSim(mySim,"hiddenProgressed","progressed",calendarStartTime=0,patientStartTime=0,rate=0) #At visit you will certainly find out you've progressed mySim <- InsertRate.EventSim(mySim,"hiddenProgressed","progressed",calendarStartTime=0,patientStartTime=0.25,rate=Inf) #You could die before knowing you have progressed (note rate = 4) mySim <- InsertRate.EventSim(mySim,"hiddenProgressed","death",rate=4) #Once progressed you then die... mySim <- InsertRate.EventSim(mySim,"progressed","death",rate=4)
It is then possible to run the simulation as before. As the progression graph is no longer a DAG, you must specify a duration
argument to the Simulate.EventSim
function. Each subject will be simulated until either they hit an absorbing state or patient time = duration
.
RawOutput <- Simulate.EventSim(mySim,c("progressing",10),duration=50) head(RawOutput$data,25)
Note that self transitions (i.e. progressing -> progressing
) are not output and that all progressed
times are multiples of 0.25. The raw output can be processed as before.
x_1
visits for y_1
visits then every x_2
visits for y_2
visits ... until finally every x_n
visits until hit absorbing state (or duration time)Within the R code:
isVisitNode
isProbabilityEdge
isProbabilityEdge
will be the transition probability and should be between 0 and 1.VisitSchedule
to contain the visit schedules and a new visitSchedule
property of nodes of the progressionGraph.Within the C++ code:
Extra Boolean flag known
for whether the current state is known
The rates will behave exactly as before (as isProbabilityEdge
edges will have 0 rates)
A new visits class which will contain the visit schedule for each node. Another time variable (in SubjectTime class) will be added, which will denote the time relative to the current visit schedule -- this will be reset when an isProbabilityEdge
or isResetEdge
is traversed?
The GetNextSwitch
function adapted so cannot sample beyond next visit time -- when reach a visit time, if known
is FALSE
it is set to TRUE
and the probability edge data is used to determine if there is a crossover transition at this visit. Irrespective of the value of the known
variable, the next visit time is then determined using the node visit schedule (and noise function associated with it) and the current patient visit time. Note the visit times must be calculated in the C++ code as it is not known a priori when subjects will end in an absorbing state.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.