Bootstrap confidence intervals represent a major advancement in
Relative Weights Analysis, addressing a long-standing methodological
limitation. This vignette provides comprehensive guidance on using
bootstrap methods with the rwa package for statistical
significance testing of predictor importance.
As noted by Tonidandel et al. (2009):
“The difficulty in determining the statistical significance of relative weights stems from the fact that the exact (or small sample) sampling distribution of relative weights is unknown.”
Traditional RWA provides point estimates of relative importance but lacks a framework for statistical inference. Bootstrap methods solve this by empirically estimating the sampling distribution of relative weights.
Bootstrap resampling: 1. Creates multiple samples
from your original data 2. Calculates RWA for each
bootstrap sample
3. Estimates confidence intervals from the distribution
of bootstrap results 4. Enables significance testing by
comparing each predictor against a randomly generated variable
A relative weight cannot be tested against zero. Raw relative weights are non-negative, so a predictor with no real relationship to the outcome still receives a small positive weight, and an interval around that weight will almost always exclude zero.
Following Tonidandel, LeBreton and Johnson (2009) — who suggest
comparing a weight against that of a randomly generated variable to
judge whether it exceeds what chance alone would produce (see also the
discussion in vignette("evaluating-rwa-method-reference"))
— significance is instead assessed by adding a randomly
generated variable to the model and bootstrapping the
difference between each predictor’s weight and the random
variable’s weight.
The directional cutoff applied by this package is: a predictor is flagged significant only when the lower bound of that difference interval is above zero, meaning it explains meaningfully more variance than noise would. An interval lying entirely below zero means the predictor performed worse than the random variable, which is equally not evidence of importance, so it is not flagged significant either.
This means the package reports two distinct intervals:
| Columns | Purpose |
|---|---|
Raw.RelWeight.CI.Lower / .Upper |
Descriptive interval around the weight itself. Not a significance test. |
Random.Diff.CI.Lower / .Upper |
Difference from a random variable’s weight.
Raw.Significant is TRUE when
Random.Diff.CI.Lower > 0. |
The implementation uses independent, identically distributed (iid)
individual-row resampling. For observation-weighted RWA, each sampled
row carries its original weight; clusters, strata, and replicate-weight
survey designs are not supported. Outcome-missing rows are removed
before resampling, while other missing-data filters are applied within
each sample. Invalid samples stop with an error rather than dropping
predictors or retrying. See
vignette("weighted-missing-data") for the filtering
contract and examples.
# Bootstrap analysis with 1000 samples
result_bootstrap <- mtcars %>%
rwa(outcome = "mpg",
predictors = c("cyl", "disp", "hp", "gear"),
bootstrap = TRUE,
n_bootstrap = 1000,
conf_level = 0.95)
# View results with confidence intervals
result_bootstrap$result
#> Variables Raw.RelWeight Rescaled.RelWeight Sign Raw.RelWeight.CI.Lower
#> 1 hp 0.2321744 29.79691 - 0.17994305
#> 2 cyl 0.2284797 29.32274 - 0.17978211
#> 3 disp 0.2221469 28.50999 - 0.15733870
#> 4 gear 0.0963886 12.37037 + 0.04021568
#> Raw.RelWeight.CI.Upper Random.Diff.CI.Lower Random.Diff.CI.Upper
#> 1 0.2776723 0.18500702 0.3029704
#> 2 0.2817795 0.15651347 0.3036993
#> 3 0.2806779 0.15031200 0.2954721
#> 4 0.1725336 0.02443039 0.1955195
#> Raw.Significant
#> 1 TRUE
#> 2 TRUE
#> 3 TRUE
#> 4 TRUEThe bootstrap analysis enhances the standard RWA output with:
TRUE when the random-comparison interval excludes zero# Bootstrap-specific information
cat("Bootstrap samples used:", result_bootstrap$bootstrap$n_bootstrap, "\n")
#> Bootstrap samples used: 1000
# Detailed CI information
print(result_bootstrap$bootstrap$ci_results$raw_weights)
#> # A tibble: 4 × 6
#> variable weight_index ci_lower ci_upper ci_method ci_type
#> <chr> <int> <dbl> <dbl> <chr> <chr>
#> 1 cyl 1 0.180 0.282 bca raw
#> 2 disp 2 0.157 0.281 bca raw
#> 3 hp 3 0.180 0.278 bca raw
#> 4 gear 4 0.0402 0.173 bca raw
# Identify significant predictors
significant_vars <- result_bootstrap$result %>%
filter(Raw.Significant == TRUE) %>%
pull(Variables)
cat("Significant predictors:", paste(significant_vars, collapse = ", "))
#> Significant predictors: hp, cyl, disp, gearFor detailed analysis including focal variable comparisons:
# Comprehensive bootstrap with focal variable comparison
result_comprehensive <- mtcars %>%
rwa(outcome = "mpg",
predictors = c("cyl", "disp", "hp", "gear", "wt"),
bootstrap = TRUE,
comprehensive = TRUE,
focal = "wt", # Compare other variables to weight
n_bootstrap = 500) # Fewer samples for speed
# Access all bootstrap results
names(result_comprehensive$bootstrap$ci_results)
#> [1] "raw_weights" "random_comparison" "focal_comparison"Key parameters for bootstrap analysis:
n_bootstrap: Number of bootstrap
samples (default: 1000)conf_level: Confidence level (default:
0.95)focal: Focal variable for comparative
analysiscomprehensive: Enable additional
bootstrap tests# Example with different parameters
custom_bootstrap <- mtcars %>%
rwa(outcome = "mpg",
predictors = c("cyl", "disp"),
bootstrap = TRUE,
n_bootstrap = 2000, # More samples for precision
conf_level = 0.99) # 99% confidence intervals
custom_bootstrap$result
#> Variables Raw.RelWeight Rescaled.RelWeight Sign Raw.RelWeight.CI.Lower
#> 1 cyl 0.3837012 50.51586 - 0.2813497
#> 2 disp 0.3758646 49.48414 - 0.2309071
#> Raw.RelWeight.CI.Upper Random.Diff.CI.Lower Random.Diff.CI.Upper
#> 1 0.4568403 0.1748707 0.4470895
#> 2 0.4637872 0.2073237 0.4656827
#> Raw.Significant
#> 1 TRUE
#> 2 TRUERescaled weight confidence intervals should be interpreted with caution due to compositional data constraints. They are not recommended for formal statistical inference.
# Rescaled CIs (use with caution)
result_rescaled_ci <- mtcars %>%
rwa(outcome = "mpg",
predictors = c("cyl", "disp", "hp"),
bootstrap = TRUE,
include_rescaled_ci = TRUE,
n_bootstrap = 500)
# Note the warning message about interpretation
result_rescaled_ci$result
#> Variables Raw.RelWeight Rescaled.RelWeight Sign Raw.RelWeight.CI.Lower
#> 1 disp 0.2793550 36.37966 - 0.2124971
#> 2 cyl 0.2723144 35.46279 - 0.2133034
#> 3 hp 0.2162184 28.15755 - 0.1438879
#> Raw.RelWeight.CI.Upper Random.Diff.CI.Lower Random.Diff.CI.Upper
#> 1 0.3456126 0.15780643 0.3218527
#> 2 0.3322052 0.11788124 0.2895544
#> 3 0.2622216 0.02978695 0.2415767
#> Raw.Significant Rescaled.RelWeight.CI.Lower Rescaled.RelWeight.CI.Upper
#> 1 TRUE 30.10095 42.87168
#> 2 TRUE 30.20278 43.36890
#> 3 TRUE 20.80491 35.82311Rescaled weights are compositional data (they sum to 100%), which creates dependencies between variables. This violates assumptions needed for independent confidence intervals.
Recommendation: Focus on raw weight confidence intervals for statistical inference.
# Analyze diamond price drivers
diamonds_subset <- diamonds %>%
select(price, carat, depth, table, x, y, z) %>%
sample_n(1000) # Sample for faster computation
diamond_rwa <- diamonds_subset %>%
rwa(outcome = "price",
predictors = c("carat", "depth", "table", "x", "y", "z"),
bootstrap = TRUE,
applysigns = TRUE,
n_bootstrap = 500)
print(diamond_rwa$result)
#> Variables Raw.RelWeight Rescaled.RelWeight Sign Sign.Rescaled.RelWeight
#> 1 carat 0.2827671839 33.61747478 + 33.61747478
#> 2 y 0.2410353741 28.65608554 + 28.65608554
#> 3 x 0.2390627389 28.42156395 + 28.42156395
#> 4 z 0.0721865633 8.58207780 + 8.58207780
#> 5 table 0.0053869575 0.64044174 + 0.64044174
#> 6 depth 0.0006927239 0.08235619 - -0.08235619
#> Raw.RelWeight.CI.Lower Raw.RelWeight.CI.Upper Random.Diff.CI.Lower
#> 1 0.2540326046 0.3432575285 0.255325134
#> 2 0.2227669146 0.2868371992 0.221011017
#> 3 0.2206290118 0.2847261569 0.218437901
#> 4 -0.0603570553 0.1169361261 -0.063730598
#> 5 0.0008142242 0.0086470381 -0.002033129
#> 6 -0.0020080833 0.0008013738 -0.003736398
#> Random.Diff.CI.Upper Raw.Significant
#> 1 0.3379597540 TRUE
#> 2 0.2852931602 TRUE
#> 3 0.2827117062 TRUE
#> 4 0.1153072073 FALSE
#> 5 0.0071742124 FALSE
#> 6 -0.0002043083 FALSE# Focus on significant predictors (results are already sorted by importance)
significant_drivers <- diamond_rwa$result %>%
filter(Raw.Significant == TRUE) %>%
select(Variables, Rescaled.RelWeight, Sign.Rescaled.RelWeight)
cat("Significant diamond price drivers (sorted by importance):\n")
#> Significant diamond price drivers (sorted by importance):
print(significant_drivers)
#> Variables Rescaled.RelWeight Sign.Rescaled.RelWeight
#> 1 carat 33.61747 33.61747
#> 2 y 28.65609 28.65609
#> 3 x 28.42156 28.42156
cat("\nModel R-squared:", round(diamond_rwa$rsquare, 3))
#>
#> Model R-squared: 0.841# Check your sample size
n_obs <- mtcars %>%
select(mpg, cyl, disp, hp, gear) %>%
na.omit() %>%
nrow()
cat("Sample size:", n_obs)
#> Sample size: 32
cat("\nRecommended bootstrap samples:", min(2000, n_obs * 10))
#>
#> Recommended bootstrap samples: 320
# Rule of thumb: At least 1000 bootstrap samples, more for smaller datasetsThe intervals around the raw weights describe
precision, not significance. Use them to judge how
tightly each weight is estimated; use Raw.Significant (from
the random-variable comparison) to judge importance.
# Examine CI characteristics
ci_data <- result_bootstrap$bootstrap$ci_results$raw_weights
print(head(ci_data))
#> # A tibble: 4 × 6
#> variable weight_index ci_lower ci_upper ci_method ci_type
#> <chr> <int> <dbl> <dbl> <chr> <chr>
#> 1 cyl 1 0.180 0.282 bca raw
#> 2 disp 2 0.157 0.281 bca raw
#> 3 hp 3 0.180 0.278 bca raw
#> 4 gear 4 0.0402 0.173 bca raw
# Assess precision
ci_analysis <- ci_data %>%
mutate(
ci_width = ci_upper - ci_lower,
precision = case_when(
ci_width < 0.05 ~ "High precision",
ci_width < 0.15 ~ "Medium precision",
TRUE ~ "Low precision"
)
)
print(ci_analysis)
#> # A tibble: 4 × 8
#> variable weight_index ci_lower ci_upper ci_method ci_type ci_width precision
#> <chr> <int> <dbl> <dbl> <chr> <chr> <dbl> <chr>
#> 1 cyl 1 0.180 0.282 bca raw 0.102 Medium pre…
#> 2 disp 2 0.157 0.281 bca raw 0.123 Medium pre…
#> 3 hp 3 0.180 0.278 bca raw 0.0977 Medium pre…
#> 4 gear 4 0.0402 0.173 bca raw 0.132 Medium pre…The package automatically selects the best available bootstrap CI method:
# For large datasets or many predictors, consider:
# 1. Reduce bootstrap samples for initial exploration
quick_result <- mtcars %>%
rwa(outcome = "mpg",
predictors = c("cyl", "disp"),
bootstrap = TRUE,
n_bootstrap = 500) # Faster
# 2. Use comprehensive analysis only when needed
# comprehensive = TRUE adds computational overhead
# 3. Consider parallel processing for very large analyses
# (not currently implemented but could be future enhancement)# Bootstrap objects can be large - access specific components
str(result_bootstrap$bootstrap, max.level = 1)
#> List of 7
#> $ boot_object :List of 11
#> ..- attr(*, "class")= chr "boot"
#> ..- attr(*, "boot_type")= chr "boot"
#> $ boot_object_random:List of 11
#> ..- attr(*, "class")= chr "boot"
#> ..- attr(*, "boot_type")= chr "boot"
#> $ ci_results :List of 2
#> $ n_bootstrap : num 1000
#> $ conf_level : num 0.95
#> $ comprehensive : logi FALSE
#> $ focal : NULL
# For memory efficiency, extract only needed results
ci_summary <- result_bootstrap$bootstrap$ci_results$raw_weights %>%
select(variable, ci_lower, ci_upper, ci_method)
print(ci_summary)
#> # A tibble: 4 × 4
#> variable ci_lower ci_upper ci_method
#> <chr> <dbl> <dbl> <chr>
#> 1 cyl 0.180 0.282 bca
#> 2 disp 0.157 0.281 bca
#> 3 hp 0.180 0.278 bca
#> 4 gear 0.0402 0.173 bca# 1. Check for perfect multicollinearity
cor_check <- mtcars %>%
select(cyl, disp, hp, gear) %>%
cor()
# Look for correlations = 1.0 (excluding diagonal)
perfect_cor <- which(abs(cor_check) == 1 & cor_check != diag(diag(cor_check)), arr.ind = TRUE)
if(length(perfect_cor) > 0) {
cat("Perfect multicollinearity detected - remove redundant variables")
} else {
cat("No perfect multicollinearity detected")
}
#> No perfect multicollinearity detected
# 2. Ensure adequate sample size
min_sample_size <- 5 * length(c("cyl", "disp", "hp", "gear")) # 5 obs per predictor
actual_sample_size <- nrow(na.omit(mtcars[c("mpg", "cyl", "disp", "hp", "gear")]))
cat("\nMinimum recommended sample size:", min_sample_size)
#>
#> Minimum recommended sample size: 20
cat("\nActual sample size:", actual_sample_size)
#>
#> Actual sample size: 32When reporting bootstrap RWA results, include:
# Generate a summary report
report_data <- result_bootstrap$result %>%
filter(Raw.Significant == TRUE) %>%
arrange(desc(Rescaled.RelWeight)) %>%
select(Variables, Rescaled.RelWeight, Raw.RelWeight.CI.Lower, Raw.RelWeight.CI.Upper)
cat("Relative Weights Analysis Results\n")
#> Relative Weights Analysis Results
cat("=================================\n")
#> =================================
cat("Sample size:", result_bootstrap$n, "\n")
#> Sample size: 32
cat("Bootstrap samples:", result_bootstrap$bootstrap$n_bootstrap, "\n")
#> Bootstrap samples: 1000
cat("Model R-squared:", round(result_bootstrap$rsquare, 3), "\n\n")
#> Model R-squared: 0.779
cat("Significant Predictors:\n")
#> Significant Predictors:
print(report_data)
#> Variables Rescaled.RelWeight Raw.RelWeight.CI.Lower Raw.RelWeight.CI.Upper
#> 1 hp 29.79691 0.17994305 0.2776723
#> 2 cyl 29.32274 0.17978211 0.2817795
#> 3 disp 28.50999 0.15733870 0.2806779
#> 4 gear 12.37037 0.04021568 0.1725336Bootstrap Methods in RWA:
General Bootstrap Theory:
Compositional Data Analysis:
Bootstrap confidence intervals provide a robust solution for statistical inference in Relative Weights Analysis. By following the guidelines in this vignette, researchers can:
The bootstrap functionality in the rwa package
represents a significant advancement in making RWA a complete tool for
both exploratory analysis and confirmatory research.