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 isProbabilityEdgeisProbabilityEdge 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.