Per-Protocol: Censoring Analysis

Here, we’ll go over some examples of using per-protocol, censoring. First we need to load the library before getting in to some sample use cases.

library(SEQTaRget)

Per-protocol, censoring, weights in pre-expanded data and no truncation, no excused conditions (i.e. static interventions)

options <- SEQopts(# tells SEQuential to create Kaplan-Meier curves
                   km.curves = TRUE,
                   # tells SEQuential to weight the outcome model
                   weighted = TRUE, 
                   # tells SEQuential to build weights from the pre-expanded data
                   weight.preexpansion = TRUE)

# use some example data in the package
data <- SEQdata                                
model <- SEQuential(data, 
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

# retrieve risk plot
km_curve(model, plot.type = "risk")
# retrieve survival and risk data
survival_data <- km_data(model)
risk_data(model)
risk_comparison(model)

Per-protocol, censoring, weights in post-expanded data and no truncation, no excused conditions (i.e. static interventions)

options <- SEQopts(km.curves = TRUE,
                   weighted = TRUE, 
                   # tells SEQuential to build weights from the post-expanded data
                   weight.preexpansion = FALSE)

data <- SEQdata                                 
model <- SEQuential(data, 
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

km_curve(model, plot.type = "risk")
risk_data(model)
risk_comparison(model)

Per-protocol, censoring, weights in pre-expanded data and no truncation, excused conditions for initiators and non-initiators (i.e. dynamic interventions)

options <- SEQopts(km.curves = TRUE,
                   weighted = TRUE,
                   weight.preexpansion = TRUE,
                   # tells SEQuential to run a dynamic intervention
                   excused = TRUE,                               
                   # excusedZero excuses switches from treatment 0 to 1,
                   # excusedOne switches from 1 to 0
                   excused.cols = c("excusedZero", "excusedOne"), 
                   # tells SEQuential to expect treatment levels 0, 1
                   # (mapping to the same positions as the list in excused.cols)
                   treat.level = c(0, 1))
data <- SEQdata                                
model <- SEQuential(data, 
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

km_curve(model, plot.type = "risk")
risk_data(model)
risk_comparison(model)

Per-protocol, censoring, a flexible baseline hazard in the weight models

By default the weight models are quadratic in time: followup, followup_sq, trial and trial_sq when weight.preexpansion = FALSE, and the time column and its square when weight.preexpansion = TRUE. A quadratic only lets the hazard of treatment rise or flatten off, which can fit poorly when the cumulative incidence of treatment moves through several phases over follow-up. weight.spline = TRUE replaces each of those quadratics with a natural cubic spline basis (splines::ns()) with weight.spline.df degrees of freedom, letting the baseline hazard take a flexible shape over time. This applies to the treatment weight models and, when cense or visit is set, to those models too.

options <- SEQopts(km.curves = TRUE,
                   weighted = TRUE,
                   weight.preexpansion = FALSE,
                   # model time in the weight models as a natural cubic spline
                   weight.spline = TRUE,
                   # 4 degrees of freedom, i.e. 3 interior knots at quantiles
                   weight.spline.df = 4L)

data <- SEQdata
model <- SEQuential(data,
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

# the weight model formulas, with the spline knots fixed from the data
covariates(model)

For finer control - a spline in followup but not trial, a different number of knots per term, or a spline in a time-varying confounder - write the ns() terms into numerator and denominator yourself. Any ns(x, df = N) term in a model formula has its knots fixed from the data the model is fit on before fitting, so the basis is the same when the model is fit and when it is used to predict the weights, and is held constant across bootstrap resamples.

options <- SEQopts(weighted = TRUE,
                   weight.preexpansion = FALSE,
                   numerator = "sex+N_bas+L_bas+P_bas+ns(followup, df = 5)+trial+trial_sq",
                   denominator = "sex+N+L+P+N_bas+L_bas+P_bas+ns(followup, df = 5)+trial+trial_sq")

model <- SEQuential(data,
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

covariates(model)

Per-protocol, censoring, weights in post-expanded data and no truncation, excused conditions for initiators and non-initiators (i.e. dynamic interventions)

options <- SEQopts(km.curves = TRUE,
                   weighted = TRUE,
                   weight.preexpansion = FALSE,
                   excused = TRUE,                               
                   excused.cols = c("excusedZero", "excusedOne"), 
                   treat.level = c(0, 1),
                   weight.p99 = TRUE)
data <- SEQdata                                
model <- SEQuential(data, 
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

km_curve(model, plot.type = "risk")
risk_data(model)
risk_comparison(model)

Per-protocol, censoring, weights in post-expanded data and no truncation, excused conditions for initiators and non-initiators (i.e. dynamic interventions) and a competing event

options <- SEQopts(km.curves = TRUE,
                   weighted = TRUE,
                   weight.preexpansion = FALSE,
                   excused = TRUE,                               
                   excused.cols = c("excusedZero", "excusedOne"), 
                   treat.level = c(0, 1),
                   # add a competing event
                   compevent = "LTFU")

data <- SEQdata.LTFU                                
model <- SEQuential(data, 
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)

km_curve(model, plot.type = "risk")
risk_data(model)
risk_comparison(model)

Per-protocol, censoring, weights in post-expanded data and no truncation, excused conditions for initiators and non-initiators (i.e. dynamic interventions) and hazard ratio

options <- SEQopts(# tell SEQuential to run hazard ratios
                   hazard = TRUE,
                   weighted = TRUE,
                   weight.preexpansion = FALSE,
                   excused = TRUE,                               
                   excused.cols = c("excusedZero", "excusedOne"),
                   weight.p99 = TRUE)

data <- SEQdata                              
model <- SEQuential(data,
                    id.col = "ID",
                    time.col = "time",
                    eligible.col = "eligible",
                    treatment.col = "tx_init",
                    outcome.col = "outcome",
                    time_varying.cols = c("N", "L", "P"),
                    fixed.cols = "sex",
                    method = "censoring",
                    options = options)
hazard_ratio(model)

mirror server hosted at Truenetwork, Russian Federation.