Fits a Cox regression model and estimate hazard ratio to describe the effect size in a survival analysis.
Usage
h_coxreg_univar_formulas(variables, interaction = FALSE)
h_coxreg_multivar_formula(variables)
fit_coxreg_univar(variables, data, at = list(), control = control_coxreg())
# S3 method for summary.coxph
tidy(x, ...)
h_coxreg_univar_extract(effect, covar, data, mod, control = control_coxreg())
# S3 method for coxreg.univar
tidy(x, ...)
fit_coxreg_multivar(variables, data, control = control_coxreg())
h_coxreg_multivar_extract(var, data, mod, control = control_coxreg())
# S3 method for coxreg.multivar
tidy(x, ...)
s_coxreg(df, .var)
summarize_coxreg(
lyt,
conf_level,
multivar = FALSE,
vars = c("n", "hr", "ci", "pval")
)
Arguments
- variables
(
list
)
a named list corresponds to the names of variables found indata
, passed as a named list and corresponding totime
,event
,arm
,strata
, andcovariates
terms. Ifarm
is missing fromvariables
, then only Cox model(s) including thecovariates
will be fitted and the corresponding effect estimates will be tabulated later.- interaction
(
flag
)
ifTRUE
, the model includes the interaction between the studied treatment and candidate covariate. Note that for univariate models without treatment arm, and multivariate models, no interaction can be used so that this needs to beFALSE
.- data
(
data frame
)
the dataset containing the variables to fit the models.- at
(
list
ofnumeric
)
when the candidate covariate is anumeric
, useat
to specify the value of the covariate at which the effect should be estimated.- control
(
list
)
a list of parameters as returned by the helper functioncontrol_coxreg()
.- x
(
list
)
Result of the Cox regression model fitted byfit_coxreg_multivar()
.- ...
additional arguments for the lower level functions.
- effect
(
string
)
the treatment variable.- covar
(
string
)
the name of the covariate in the model.- mod
(
coxph
)
Cox regression model fitted bysurvival::coxph()
.- df
(
data frame
)
data set containing all analysis variables.- .var, var
(
string
)
single variable name that is passed byrtables
when requested by a statistics function.- lyt
(
layout
)
input layout where analyses will be added to.- conf_level
(
proportion
)
confidence level of the interval.- multivar
(
flag
)
ifTRUE
, the multi-variable Cox regression will run and no interaction will be considered between the studied treatment and c candidate covariate. Default isFALSE
for univariate Cox regression including an arm variable. When no arm variable is included in the univariate Cox regression, then alsoTRUE
should be used to tabulate the covariate effect estimates instead of the treatment arm effect estimate across models.- vars
(
character
)
the name of statistics to be reported amongn
(number of observation),hr
(Hazard Ratio),ci
(confidence interval),pval
(p.value of the treatment effect) andpval_inter
(the p.value of the interaction effect between the treatment and the covariate).
Value
The function h_coxreg_univar_formulas
returns a character
vector coercible
into formulas (e.g stats::as.formula()
).
The function h_coxreg_univar_formulas
returns a character
vector coercible
into formulas (e.g stats::as.formula()
).
The function fit_coxreg_univar
returns a coxreg.univar
class object which is a named list
with 5 elements:
mod
: Cox regression models fitted bysurvival::coxph()
.data
: The original data frame input.control
: The original control input.vars
: The variables used in the model.at
: Value of the covariate at which the effect should be estimated.
The function fit_coxreg_multivar
returns a coxreg.multivar
class object which is a named list
with 4 elements:
mod
: Cox regression model fitted bysurvival::coxph()
.data
: The original data frame input.control
: The original control input.vars
: The variables used in the model.
Details
Cox models are the most commonly used methods to estimate the magnitude of the effect in survival analysis. It assumes proportional hazards: the ratio of the hazards between groups (e.g., two arms) is constant over time. This ratio is referred to as the "hazard ratio" (HR) and is one of the most commonly reported metrics to describe the effect size in survival analysis (NEST Team, 2020).
Functions
-
h_coxreg_univar_formulas()
: Helper for Cox Regression FormulaCreates a list of formulas. It is used internally by
fit_coxreg_univar()
for the comparison of univariate Cox regression models. -
h_coxreg_multivar_formula()
: Helper for Multi-variable Cox Regression FormulaCreates a formulas string. It is used internally by
fit_coxreg_multivar()
for the comparison of multi-variable Cox regression models. Interactions will not be included in multi-variable Cox regression model. fit_coxreg_univar()
: Fit a series of univariate Cox regression models given the inputs.-
tidy(summary.coxph)
: Custom tidy method forsurvival::coxph()
summary results.Tidy the
survival::coxph()
results into adata.frame
to extract model results. h_coxreg_univar_extract()
: Utility function to help tabulate the result of a univariate Cox regression model.-
tidy(coxreg.univar)
: Custom tidy method for a Univariate Cox RegressionTidy up the result of a Cox regression model fitted by
fit_coxreg_univar()
. fit_coxreg_multivar()
: Fit a multi-variable Cox regression model.-
h_coxreg_multivar_extract()
: Tabulation of Multi-variable Cox RegressionsUtility function to help tabulate the result of a multi-variable Cox regression model for a treatment/covariate variable.
-
tidy(coxreg.multivar)
: Custom tidy method for a Multi-variable Cox RegressionTidy up the result of a Cox regression model fitted by
fit_coxreg_multivar()
. s_coxreg()
: transforms the tabulated results fromfit_coxreg_univar()
andfit_coxreg_multivar()
into a list. Not much calculation is done here, it rather prepares the data to be used by the layout creating function.summarize_coxreg()
: layout creating function.
Note
The usual formatting arguments for the layout creating function
summarize_coxreg
are not yet accepted (.stats
, .indent_mod
, .formats
,
.labels
).
When using fit_coxreg_univar
there should be two study arms.
Examples
# Testing dataset [survival::bladder].
library(survival)
library(rtables)
set.seed(1, kind = "Mersenne-Twister")
dta_bladder <- with(
data = bladder[bladder$enum < 5, ],
data.frame(
time = stop,
status = event,
armcd = as.factor(rx),
covar1 = as.factor(enum),
covar2 = factor(
sample(as.factor(enum)),
levels = 1:4, labels = c("F", "F", "M", "M")
)
)
)
labels <- c("armcd" = "ARM", "covar1" = "A Covariate Label", "covar2" = "Sex (F/M)")
formatters::var_labels(dta_bladder)[names(labels)] <- labels
dta_bladder$age <- sample(20:60, size = nrow(dta_bladder), replace = TRUE)
plot(
survfit(Surv(time, status) ~ armcd + covar1, data = dta_bladder),
lty = 2:4,
xlab = "Months",
col = c("blue1", "blue2", "blue3", "blue4", "red1", "red2", "red3", "red4")
)
# `h_coxreg_univar_formulas`
## Simple formulas.
h_coxreg_univar_formulas(
variables = list(
time = "time", event = "status", arm = "armcd", covariates = c("X", "y")
)
)
#> ref
#> "survival::Surv(time, status) ~ armcd"
#> X
#> "survival::Surv(time, status) ~ armcd + X"
#> y
#> "survival::Surv(time, status) ~ armcd + y"
## Addition of an optional strata.
h_coxreg_univar_formulas(
variables = list(
time = "time", event = "status", arm = "armcd", covariates = c("X", "y"),
strata = "SITE"
)
)
#> ref
#> "survival::Surv(time, status) ~ armcd + strata(SITE)"
#> X
#> "survival::Surv(time, status) ~ armcd + X + strata(SITE)"
#> y
#> "survival::Surv(time, status) ~ armcd + y + strata(SITE)"
## Inclusion of the interaction term.
h_coxreg_univar_formulas(
variables = list(
time = "time", event = "status", arm = "armcd", covariates = c("X", "y"),
strata = "SITE"
),
interaction = TRUE
)
#> ref
#> "survival::Surv(time, status) ~ armcd + strata(SITE)"
#> X
#> "survival::Surv(time, status) ~ armcd * X + strata(SITE)"
#> y
#> "survival::Surv(time, status) ~ armcd * y + strata(SITE)"
## Only covariates fitted in separate models.
h_coxreg_univar_formulas(
variables = list(
time = "time", event = "status", covariates = c("X", "y")
)
)
#> X y
#> "survival::Surv(time, status) ~ 1 + X" "survival::Surv(time, status) ~ 1 + y"
# `h_coxreg_multivar_formula`
h_coxreg_multivar_formula(
variables = list(
time = "AVAL", event = "event", arm = "ARMCD", covariates = c("RACE", "AGE")
)
)
#> [1] "survival::Surv(AVAL, event) ~ ARMCD + RACE + AGE"
# Addition of an optional strata.
h_coxreg_multivar_formula(
variables = list(
time = "AVAL", event = "event", arm = "ARMCD", covariates = c("RACE", "AGE"),
strata = "SITE"
)
)
#> [1] "survival::Surv(AVAL, event) ~ ARMCD + RACE + AGE + strata(SITE)"
# Example without treatment arm.
h_coxreg_multivar_formula(
variables = list(
time = "AVAL", event = "event", covariates = c("RACE", "AGE"),
strata = "SITE"
)
)
#> [1] "survival::Surv(AVAL, event) ~ 1 + RACE + AGE + strata(SITE)"
# fit_coxreg_univar
## Cox regression: arm + 1 covariate.
mod1 <- fit_coxreg_univar(
variables = list(
time = "time", event = "status", arm = "armcd",
covariates = "covar1"
),
data = dta_bladder,
control = control_coxreg(conf_level = 0.91)
)
## Cox regression: arm + 1 covariate + interaction, 2 candidate covariates.
mod2 <- fit_coxreg_univar(
variables = list(
time = "time", event = "status", arm = "armcd",
covariates = c("covar1", "covar2")
),
data = dta_bladder,
control = control_coxreg(conf_level = 0.91, interaction = TRUE)
)
## Cox regression: arm + 1 covariate, stratified analysis.
mod3 <- fit_coxreg_univar(
variables = list(
time = "time", event = "status", arm = "armcd", strata = "covar2",
covariates = c("covar1")
),
data = dta_bladder,
control = control_coxreg(conf_level = 0.91)
)
## Cox regression: no arm, only covariates.
mod4 <- fit_coxreg_univar(
variables = list(
time = "time", event = "status",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
library(survival)
library(broom)
library(rtables)
set.seed(1, kind = "Mersenne-Twister")
dta_bladder <- with(
data = bladder[bladder$enum < 5, ],
data.frame(
time = stop,
status = event,
armcd = as.factor(rx),
covar1 = as.factor(enum),
covar2 = factor(
sample(as.factor(enum)),
levels = 1:4, labels = c("F", "F", "M", "M")
)
)
)
labels <- c("armcd" = "ARM", "covar1" = "A Covariate Label", "covar2" = "Sex (F/M)")
formatters::var_labels(dta_bladder)[names(labels)] <- labels
dta_bladder$age <- sample(20:60, size = nrow(dta_bladder), replace = TRUE)
formula <- "survival::Surv(time, status) ~ armcd + covar1"
msum <- summary(coxph(stats::as.formula(formula), data = dta_bladder))
tidy(msum)
#> Pr(>|z|) exp(coef) exp(-coef) lower .95 upper .95 level n
#> 1 1.287954e-02 0.6110123 1.636628 0.41442417 0.9008549 armcd2 340
#> 2 6.407916e-04 0.4460731 2.241785 0.28061816 0.7090818 covar12 340
#> 3 5.272933e-06 0.3075864 3.251119 0.18517346 0.5109230 covar13 340
#> 4 2.125359e-08 0.1808795 5.528541 0.09943722 0.3290258 covar14 340
library(survival)
dta_simple <- data.frame(
time = c(5, 5, 10, 10, 5, 5, 10, 10),
status = c(0, 0, 1, 0, 0, 1, 1, 1),
armcd = factor(LETTERS[c(1, 1, 1, 1, 2, 2, 2, 2)], levels = c("A", "B")),
var1 = c(45, 55, 65, 75, 55, 65, 85, 75),
var2 = c("F", "M", "F", "M", "F", "M", "F", "U")
)
mod <- coxph(Surv(time, status) ~ armcd + var1, data = dta_simple)
result <- h_coxreg_univar_extract(
effect = "armcd", covar = "armcd", mod = mod, data = dta_simple
)
result
#> effect term term_label level n hr lcl ucl
#> 1 Treatment: armcd B vs control (A) B 8 6.551448 0.4606904 93.16769
#> pval
#> 1 0.165209
library(broom)
tidy(mod1)
#> effect term term_label level n hr lcl
#> ref Treatment: armcd 2 vs control (1) 2 340 0.6386426 0.4557586
#> covar1 Covariate: covar1 A Covariate Label 2 340 0.607037 0.4324571
#> ucl pval ci
#> ref 0.8949131 0.02423805 0.4557586, 0.8949131
#> covar1 0.8520935 0.01257339 0.4324571, 0.8520935
tidy(mod2)
#> effect term term_label level n hr
#> ref Treatment: armcd 2 vs control (1) 2 340 0.6386426
#> covar1.1 Covariate: covar1 A Covariate Label 340
#> covar1.armcd2/covar11 Covariate: covar1 1 1 0.6284569
#> covar1.armcd2/covar12 Covariate: covar1 2 2 0.5806499
#> covar1.armcd2/covar13 Covariate: covar1 3 3 0.5486103
#> covar1.armcd2/covar14 Covariate: covar1 4 4 0.6910725
#> covar2.1 Covariate: covar2 Sex (F/M) 340
#> covar2.armcd2/covar2F Covariate: covar2 F F 0.6678243
#> covar2.armcd2/covar2M Covariate: covar2 M M 0.5954021
#> lcl ucl pval pval_inter
#> ref 0.4557586 0.8949131 0.02423805
#> covar1.1 NA NA 0.9883021
#> covar1.armcd2/covar11 0.3450471 1.1446499
#> covar1.armcd2/covar12 0.2684726 1.2558239
#> covar1.armcd2/covar13 0.2226814 1.3515868
#> covar1.armcd2/covar14 0.2308006 2.0692373
#> covar2.1 NA NA 0.7759013
#> covar2.armcd2/covar2F 0.3649842 1.2219413
#> covar2.armcd2/covar2M 0.3572772 0.9922368
#> ci
#> ref 0.4557586, 0.8949131
#> covar1.1
#> covar1.armcd2/covar11 0.3450471, 1.1446499
#> covar1.armcd2/covar12 0.2684726, 1.2558239
#> covar1.armcd2/covar13 0.2226814, 1.3515868
#> covar1.armcd2/covar14 0.2308006, 2.0692373
#> covar2.1
#> covar2.armcd2/covar2F 0.3649842, 1.2219413
#> covar2.armcd2/covar2M 0.3572772, 0.9922368
# fit_coxreg_multivar
## Cox regression: multivariate Cox regression.
multivar_model <- fit_coxreg_multivar(
variables = list(
time = "time", event = "status", arm = "armcd",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
# Example without treatment arm.
multivar_covs_model <- fit_coxreg_multivar(
variables = list(
time = "time", event = "status",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
library(survival)
mod <- coxph(Surv(time, status) ~ armcd + var1, data = dta_simple)
result <- h_coxreg_multivar_extract(
var = "var1", mod = mod, data = dta_simple
)
result
#> pval hr lcl ucl level n term term_label
#> 2 0.4456195 0.9423284 0.808931 1.097724 var1 8 var1 var1
library(broom)
broom::tidy(multivar_model)
#> term pval term_label
#> armcd.1 armcd ARM (reference = 1)
#> armcd.2 ARM 0.01232761 2
#> covar1.1 covar1 7.209956e-09 A Covariate Label (reference = 1)
#> covar1.2 A Covariate Label 0.001120332 2
#> covar1.3 A Covariate Label 6.293725e-06 3
#> covar1.4 A Covariate Label 3.013875e-08 4
#> covar2.1 covar2 Sex (F/M) (reference = F)
#> covar2.2 Sex (F/M) 0.1910521 M
#> hr lcl ucl level ci
#> armcd.1 NA NA <NA>
#> armcd.2 0.6062777 0.40970194 0.8971710 2 0.4097019, 0.8971710
#> covar1.1 NA NA <NA>
#> covar1.2 0.4564763 0.28481052 0.7316115 2 0.2848105, 0.7316115
#> covar1.3 0.3069612 0.18386073 0.5124813 3 0.1838607, 0.5124813
#> covar1.4 0.1817017 0.09939435 0.3321668 4 0.09939435, 0.33216684
#> covar2.1 NA NA <NA>
#> covar2.2 1.289373 0.88087820 1.8873019 M 0.8808782, 1.8873019
# s_coxreg
univar_model <- fit_coxreg_univar(
variables = list(
time = "time", event = "status", arm = "armcd",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
df1 <- broom::tidy(univar_model)
s_coxreg(df = df1, .var = "hr")
#> $hr
#> $hr$`2 vs control (1)`
#> [1] 0.6386426
#>
#>
#> $hr
#> $hr$`A Covariate Label`
#> [1] 0.607037
#>
#>
#> $hr
#> $hr$`Sex (F/M)`
#> [1] 0.6242738
#>
#>
# Only covariates.
univar_covs_model <- fit_coxreg_univar(
variables = list(
time = "time", event = "status",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
df1_covs <- broom::tidy(univar_covs_model)
s_coxreg(df = df1_covs, .var = "hr")
#> $hr
#> $hr$`2`
#> [1] 0.446633
#>
#> $hr$`3`
#> [1] 0.3098658
#>
#> $hr$`4`
#> [1] 0.1828626
#>
#>
#> $hr
#> $hr$M
#> [1] 1.3271
#>
#>
#> $hr
#> $hr$`A Covariate Label (reference = 1)`
#> numeric(0)
#>
#>
#> $hr
#> $hr$`Sex (F/M) (reference = F)`
#> numeric(0)
#>
#>
# Multivariate.
multivar_model <- fit_coxreg_multivar(
variables = list(
time = "time", event = "status", arm = "armcd",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
df2 <- broom::tidy(multivar_model)
s_coxreg(df = df2, .var = "hr")
#> $hr
#> $hr$`2`
#> [1] 0.4564763
#>
#> $hr$`3`
#> [1] 0.3069612
#>
#> $hr$`4`
#> [1] 0.1817017
#>
#>
#> $hr
#> $hr$`2`
#> [1] 0.6062777
#>
#>
#> $hr
#> $hr$M
#> [1] 1.289373
#>
#>
#> $hr
#> $hr$`ARM (reference = 1)`
#> numeric(0)
#>
#>
#> $hr
#> $hr$`A Covariate Label (reference = 1)`
#> numeric(0)
#>
#>
#> $hr
#> $hr$`Sex (F/M) (reference = F)`
#> numeric(0)
#>
#>
# Multivariate without treatment arm.
multivar_covs_model <- fit_coxreg_multivar(
variables = list(
time = "time", event = "status",
covariates = c("covar1", "covar2")
),
data = dta_bladder
)
df2_covs <- broom::tidy(multivar_covs_model)
s_coxreg(df = df2_covs, .var = "hr")
#> $hr
#> $hr$`2`
#> [1] 0.4600728
#>
#> $hr$`3`
#> [1] 0.3100455
#>
#> $hr$`4`
#> [1] 0.1854177
#>
#>
#> $hr
#> $hr$M
#> [1] 1.285406
#>
#>
#> $hr
#> $hr$`A Covariate Label (reference = 1)`
#> numeric(0)
#>
#>
#> $hr
#> $hr$`Sex (F/M) (reference = F)`
#> numeric(0)
#>
#>
# summarize_coxreg
result_univar <- basic_table() %>%
split_rows_by("effect") %>%
split_rows_by("term", child_labels = "hidden") %>%
summarize_coxreg(conf_level = 0.95) %>%
build_table(df1)
result_univar
#> n Hazard Ratio 95% CI p-value
#> —————————————————————————————————————————————————————————————————
#> Treatment:
#> 2 vs control (1) 340 0.64 (0.43, 0.94) 0.0242
#> Covariate:
#> A Covariate Label 340 0.61 (0.41, 0.90) 0.0126
#> Sex (F/M) 340 0.62 (0.42, 0.92) 0.0182
result_multivar <- basic_table() %>%
split_rows_by("term", child_labels = "hidden") %>%
summarize_coxreg(multivar = TRUE, conf_level = .95) %>%
build_table(df2)
result_multivar
#> Hazard Ratio 95% CI p-value
#> —————————————————————————————————————————————————————————————————————————
#> ARM (reference = 1)
#> 2 0.61 (0.41, 0.90) 0.0123
#> A Covariate Label (reference = 1) <0.0001
#> 2 0.46 (0.28, 0.73) 0.0011
#> 3 0.31 (0.18, 0.51) <0.0001
#> 4 0.18 (0.10, 0.33) <0.0001
#> Sex (F/M) (reference = F)
#> M 1.29 (0.88, 1.89) 0.1911
# When tabulating univariate models with only covariates, also `multivar = TRUE`
# is used.
result_univar_covs <- basic_table() %>%
split_rows_by("term", child_labels = "hidden") %>%
summarize_coxreg(multivar = TRUE, conf_level = 0.95) %>%
build_table(df1_covs)
result_univar_covs
#> Hazard Ratio 95% CI p-value
#> —————————————————————————————————————————————————————————————————————————
#> A Covariate Label (reference = 1) <0.0001
#> 2 0.45 (0.28, 0.71) 0.0007
#> 3 0.31 (0.19, 0.52) <0.0001
#> 4 0.18 (0.10, 0.33) <0.0001
#> Sex (F/M) (reference = F)
#> M 1.33 (0.91, 1.94) 0.1414
# No change for the multivariate tabulation when no treatment arm is included.
result_multivar_covs <- basic_table() %>%
split_rows_by("term", child_labels = "hidden") %>%
summarize_coxreg(multivar = TRUE, conf_level = .95) %>%
build_table(df2_covs)
result_multivar_covs
#> Hazard Ratio 95% CI p-value
#> —————————————————————————————————————————————————————————————————————————
#> A Covariate Label (reference = 1) <0.0001
#> 2 0.46 (0.29, 0.74) 0.0012
#> 3 0.31 (0.19, 0.52) <0.0001
#> 4 0.19 (0.10, 0.34) <0.0001
#> Sex (F/M) (reference = F)
#> M 1.29 (0.88, 1.88) 0.1958