Bootstrap p-values and confidence intervals for regression models

Background

p-values can be computed by inverting the corresponding confidence intervals, as described in Section 14.2 of Thulin (2024) and Section 3.12 in Hall (1992). This package contains functions for computing bootstrap p-values in this way. The approach relies on the fact that:

Summaries for regression models

Summary tables with confidence intervals and p-values for the coefficients of regression models can be obtained using the boot_summary (most models) and censboot_summary (models with censored response variables) functions. Currently, the following models are supported:

A number of examples are available in Chapters 8 and 9 of Modern Statistics with R.

Here are some simple examples with a linear regression model for the mtcars data:

library(boot.pval)

# Bootstrap summary of a linear model for mtcars:
model <- lm(mpg ~ hp + vs, data = mtcars)
boot_summary(model)
#>                Estimate Lower.bound Upper.bound p.value
#> (Intercept) 26.96300111 21.44468818 32.77538261  <0.001
#> hp          -0.05453412 -0.08221779 -0.02469512  <0.001
#> vs           2.57622314 -1.50354455  6.67844351   0.214

# Use 9999 bootstrap replicates and adjust p-values for
# multiplicity using Holm's method:
boot_summary(model, R = 9999, adjust.method = "holm")
#>                Estimate Lower.bound Upper.bound p.value Adjusted p-value
#> (Intercept) 26.96300111 21.31260344 32.68770458  <1e-04           0.0003
#> hp          -0.05453412 -0.08250079 -0.02568031  <1e-04           0.0003
#> vs           2.57622314 -1.30707581  6.45327760  0.1976           0.1976

# Use case resampling instead of residual resampling:
boot_summary(model, method = "case")
#>                Estimate Lower.bound Upper.bound p.value
#> (Intercept) 26.96300111  21.7661374 34.95608728  <0.001
#> hp          -0.05453412  -0.1057451 -0.02850017  <0.001
#> vs           2.57622314  -1.5784635  6.39031708   0.277

# Export results to a gt table:
boot_summary(model, R = 9999) |>
  summary_to_gt()
Estimate 95 % CI p-value
(Intercept) 26.963 (21.200, 32.670) <1e-04
hp −0.055 (−0.083, −0.025) <1e-04
vs 2.576 (−1.383, 6.497) 0.1957

See Davison and Hinkley (1997) for details about residual resampling (the default) and case resampling.

# Export results to a Word document:
library(flextable)
boot_summary(model, R = 9999) |>
  summary_to_flextable() |> 
  save_as_docx(path = "my_table.docx")

And a toy example for a generalised linear mixed model (using a small number of bootstrap repetitions):

library(lme4)
model <- glmer(TICKS ~ YEAR + (1|LOCATION),
           data = grouseticks, family = poisson)
boot_summary(model, R = 99)

Speeding up computations

For complex models, speed can be greatly improved by using parallelisation. For lmer and glmer models, this is set using the parallel (available options are "multicore" and "snow"). The number of CPUs to use is set using ncpus.

model <- glmer(TICKS ~ YEAR + (1|LOCATION),
           data = grouseticks, family = poisson)
boot_summary(model, R = 999, parallel = "multicore", ncpus = 10)

For other models, use ncores:

model <- lm(mpg ~ hp + vs, data = mtcars)
boot_summary(model, R = 9999, ncores = 10)

Survival models

Survival regression models should be fitted using the argument model = TRUE. A summary table can then be obtained using censboot_summary. By default, the table contains exponentiated coefficients (i.e. hazard ratios, in the case of a Cox PH model).

library(survival)
#> Warning: package 'survival' was built under R version 4.6.1
# Weibull AFT model:
model <- survreg(formula = Surv(time, status) ~ age + sex, data = lung,
                dist = "weibull", model = TRUE)
# Table with exponentiated coefficients:
censboot_summary(model)
#> Using exponentiated coefficients.
#>                Estimate Lower.bound Upper.bound p.value
#> (Intercept) 531.0483429 219.9999467 1462.289530  <0.001
#> age           0.9878178   0.9724702    1.001419   0.077
#> sex           1.4653368   1.1625809    1.880702  <0.001

# Cox PH model:
model <- coxph(formula = Surv(time, status) ~ age + sex, data = lung,
               model = TRUE)
# Table with hazard ratios:
censboot_summary(model)
#> Using exponentiated coefficients.
#>     Estimate Lower.bound Upper.bound p.value
#> age 1.017191   0.9979638   1.0356228   0.082
#> sex 0.598566   0.4198728   0.8131057   0.003
# Table with original coefficients:
censboot_summary(model, coef = "raw")
#> Using raw coefficients.
#>        Estimate Lower.bound Upper.bound p.value
#> age  0.01704533 -0.00247862  0.03749254    0.07
#> sex -0.51321852 -0.85827273 -0.22328037  <0.001

To speed up computations using parallelisation, use the parallel and ncpus arguments:

censboot_summary(model, parallel = "multicore", ncpus = 10)

References