#---
#title: "MSMplus"
#output: rmarkdown::html_vignette
#vignette: >
#  %\VignetteIndexEntry{MSMplus_application_input}
#  %\VignetteEngine{knitr::rmarkdown}
#  %\VignetteEncoding{UTF-8}
#---
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
#options(width = 60)
#local({
#  hook_output <- knitr::knit_hooks$get('output')
#  knitr::knit_hooks$set(output = function(x, options) {
#    if (!is.null(options$max.height)) options$attr.output <- c(
#      options$attr.output,
#      sprintf('style="max-height: %s;"', options$max.height)
#    )
#    hook_output(x, options)
#  })
#})
library("MSMplus")
library("survival")
library("mstate")
library("dplyr")
library("reshape2")
library("flexsurv")
library("msm")

MSMplus is a useful tool for presentation of results from a multi-state analysis in an easy, comprehensible and meaningful way. The intended users of the app are researchers who have built multi-state models, and want to present their results to targeted audiences.

The results need to be provided to the app either as json or a csv/excel files of a specific structure.

Users of the supported Stata or R packages can automatically derive the json files while running the multi-state models. In Stata, this is done via the commands msboxes and predictms and in R via the current package and the use of its funtions: msboxes_R, flexjson, msmjson and mstatejson.

The csv/excel file format is necessary only for users who did not build their model using the supported Stata or R packages. The formatting and naming rules for creating the csv file inputs are described in this tutorial. Users of the app with little knowledge of R or Stata can benefit from this input format, as the analysis can be conducted via any statistical software and then the results can be prepared as a csv/excel file.

Here is an example csv data file structure:

load("excel_input_file_ex.rda", envir = parent.frame(), verbose = FALSE)

excel_input_file_ex[104:106,1:39]

The user can locally launch the MSMplus application by writting MSMplus_prepare::runMSMplus() or access it online at https://nskbiostatistics.shinyapps.io/MSMplus/

Files input preparation

Function msboxes_R

Generating information to create a multi-state graph with updated frequencies in each state across different time points

We will start by using data from the European Blood and Marrow Transplant registry. The dataset consists of 2204 patients who received bone marrow transplantation. The three states a patient can be in is 1) Post- transplant, 2) Platelet recovery 3) Relapse/Death. The covariate patterns used in this example are the 3 age categories, namely <20 y.old, 20-40y.old and >40 y.old . This dataset is freely available from mstate package and you can access more information by typing ?ebmt3.

load("ebmt.rda", envir = parent.frame(), verbose = FALSE)

head(ebmt)

Let's first define the transition matrix

tmat <- transMat(x = list(c(2, 3),c(3), c() ), names = c("Transplant", "Platelet Recovery", "Relapse/Death" ) )

We will now create dummy variables for the age categories

ebmt$age2=  recode(ebmt$age, ">40" =0, "20-40"=1,"<=20" =0 )
ebmt$age3=  recode(ebmt$age, ">40" =1, "20-40"=0,"<=20" =0 )

Data preparation- From one row per participant to multiple rows per participant, one for each allowed transition.

msebmt <- msprep(data = ebmt, trans = tmat, 
                 time = c(NA, "prtime", "rfstime"), status = c(NA, "prstat", "rfsstat"), keep=c("age2","age3"))

head(msebmt)

We can now call function msboxes_R

msboxes_R will create a json file containing parameters that will help MSMplus to automatically create the multi-state graph of each specific setting. However, the user has the option to design and create the multistate graph within the app as well.

results3_days=MSMplus::msboxes_R(data=msebmt,id= msebmt$id, yb=c(0.3,0.5,0.75),
                        xb=c(0.5,0.2,0.7),boxwidth=0.1,boxheight=0.1,
                        tmatrix= tmat, tstop=msebmt$Tstop,vartime=c(seq(0,10,by=1)),scale=365.25,
                        jsonpath="~", name="msboxes_EBMT.json" ) 
results3_days

MSMplus Json input file of predictions: The flexjson function

Provide time vector

tgrid <- seq(1, 10, by = 1)   

Provide transition matrix

tmat <- rbind(c(NA, 1, 2), c(NA, NA, 3), c(NA, NA, NA)) 

Run transition specific hazard models: Clock forward approach and use of flexible parametric models

cfwei.list<-vector(3,mode="list")

for (i in 1:3) {

  cfwei.list[[i]]<-flexsurvreg(Surv(Tstart,Tstop,status)~age2+age3,subset=(trans==i),
                               dist="weibull",data=msebmt)
}

Prediction for different covariate patterns (the 3 age categories)

wh1 <- which(msebmt$age2 == 0 & msebmt$age3 == 0)
pat1 <- msebmt[rep(wh1[1], 3), 9:10]
attr(pat1, "trans") <- tmat


wh2 <- which(msebmt$age2 == 1 & msebmt$age3 == 0)
pat2 <- msebmt[rep(wh2[1], 3), 9:10]
attr(pat2, "trans") <- tmat

wh3 <- which(msebmt$age2 == 0 & msebmt$age3 == 1)
pat3 <- msebmt[rep(wh3[1], 3), 9:10]
attr(pat3, "trans") <- tmat

We now run the flexsurvjson function to perform the multi-state model analysis using the function from package flexsurv and the pack the predictions in a json file.

results_cf <- MSMplus::flexsurvjson( model=cfwei.list, vartime=seq(365.25,365.25,by=365.25), 
                                   qmat=tmat, process="Markov",
                                   totlos=TRUE, ci.json=FALSE, cl.json=0.95, B.json=10, tcovs=NULL,
                                   Mjson=100, variance=FALSE,
                                   covariates_list=list(pat1,pat2,pat3), 
                                   jsonpath="~",
                                   name="predictions_EBMT_flex.json" ) 
results_cf$timevar
results_cf$Nats
results_cf$atlist
results_cf$tmat
results_cf$Ntransitions
results_cf$is.cumhaz
results_cf[[7]]

If the user has used the clock reset approach they have to specify "semiMarkov" at the process argument.

MSMplus Json input file of predictions: The mstatejson function

Semi parametric analysis

Apply a Cox proportional hazard model with Markov assumption

cfcox <- coxph(Surv(Tstart, Tstop, status) ~age2+age3+strata(trans), data = msebmt)

Prediction for different covariate patterns (the 3 age categories)

wh1 <- which(msebmt$age2 == 0 & msebmt$age3 == 0)
pat1 <- msebmt[rep(wh1[1], 3), 9:10]
pat1$trans <- 1:3
attr(pat1, "trans") <- tmat
pat1$strata <- pat1$trans


wh2 <- which(msebmt$age2 == 1 & msebmt$age3 == 0)
pat2 <- msebmt[rep(wh2[1], 3), 9:10]
pat2$trans <- 1:3
attr(pat2, "trans") <- tmat
pat2$strata <- pat2$trans

wh3 <- which(msebmt$age2 == 0 & msebmt$age3 == 1)
pat3 <- msebmt[rep(wh3[1], 3), 9:10]
pat3$trans <- 1:3
attr(pat3, "trans") <- tmat
pat3$strata <- pat3$trans

We now run the mstatejson function to perform the multi-state model analysis using the function from package mstate and the pack the predictions in a json file.

results_semipar <- MSMplus::mstatejson(x=cfcox,  qmat=tmat, process="Markov", 
                                totlos=TRUE, ci.json=TRUE, cl.json=0.95, B.json=100,
                                variance=TRUE, vartype="greenwood",
                                covariates_list=list(pat1 ,pat2, pat3 ) , M=100,
                                jsonpath="~",
                                name="predictions_EBMT_mstate.json")
#Timevar
results_semipar$Nats
results_semipar$atlist
results_semipar$tmat
results_semipar$is.cumhaz
results_semipar[[6]]$P_1_to_1[,1:5]
results_semipar[[6]]$P_1_to_2[,1:5]
results_semipar[[6]]$P_1_to_3[,1:5]
results_semipar[[6]]$P_2_to_1[,1:5]
results_semipar[[6]]$P_2_to_2[,1:5]
results_semipar[[6]]$P_2_to_3[,1:5]
results_semipar[[6]]$P_3_to_1[,1:5]
results_semipar[[6]]$P_3_to_2[,1:5]
results_semipar[[6]]$P_3_to_3[,1:5]
#The measures are not displayed here to save space 

MSMplus Json input file of predictions: The msmjson function

options(scipen = 999,"digits"=10)
head(cav)

Renaming variable PTNUM to id

 cav$id=cav$PTNUM

Defining the transition matrix

    tmat=matrix(NA,nrow=4,ncol=4)
    tmat[1,2]=1; tmat[1,4]=2; tmat[2,1]=3; tmat[2,3]=4
    tmat[2,4]=5; tmat[3,2]=6; tmat[3,4]=7

We can now call function msboxes_R

    results3_days=MSMplus::msboxes_R(data=cav,id= cav$id, yb=c(0.3,0.5,0.6,0.75), msm=TRUE,
                            xb=c(0.5,0.2,0.7,0.3),boxwidth=0.1,boxheight=0.1,
                            tmatrix= tmat, vartime=seq(0,10,by=1),scale=1,
                            jsonpath="~", name="msboxes_msm.json" ) 

Defining the transition matrix with initial values under an initial assumption

0 for transitions not allowed, initial values for rest of transitions under a rationale ##

Q<- rbind(c(0,0.25,0,0.25),c(0.166,0,0.166,0.166),c(0,0.25,0,0.25),c(0,0,0,0))

Getting initial Q matrix in a default way- Feed the hand made matrix

    q.crude<- crudeinits.msm(state~years, id,data=cav, qmatrix=Q)

Apply the msm model

    cavsex.msm<- msm(state~years, covariates=~sex, id,data=cav,qmatrix=q.crude, deathexact = 4, control=list(trace=1,REPORT=1)) 
    summary(cavsex.msm)

Prediction for different covariate patterns (males and females)

results <- MSMplus::msmjson(msm.model=cavsex.msm, vartime=seq(1,3,1), mat.init=q.crude,
                       totlos=TRUE, visit=TRUE, sojourn=TRUE, pnext=TRUE, efpt=TRUE, envisits=TRUE,
                       ci.json="normal", cl.json=0.95, B.json=10,
                       cores.json=NULL,piecewise.times.json=NULL,
                       piecewise.covariates.json=NULL,num.integ.json=FALSE,
                       covariates_list=list(list(sex = 1),list(sex = 0)), 
                       jsonpath="~",
                       name="predictions_msm.json" ) 
results$timevar
results$Nats
results$atlist
results$tmat
results[[7]]
#The rest of the measures are not displayed here to save space 


nskourlis/MSMplus documentation built on Dec. 7, 2023, 4:53 a.m.