0Pricing
R Academy · Lesson

Bootstrap Resampling in R

Implement bootstrap confidence intervals using sample() with replacement.

Bootstrap Resampling in R is a free R Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Bootstrap?

The bootstrap is a resampling method that estimates the sampling distribution of a statistic by resampling with replacement from the observed data. It requires no distributional assumptions — the data is the distribution.

set.seed(42)
# Original sample of 20 observations
original_data <- c(14, 18, 11, 13, 6, 8, 2, 17,
                   20, 10, 15, 12, 9, 16, 7, 3,
                   19, 5, 4, 1)
n <- length(original_data)

# One bootstrap resample: sample WITH replacement
bootstrap_sample1 <- sample(original_data, n, replace = TRUE)
print(bootstrap_sample1)
# Contains repeats! Some original values are missing.

mean(original_data)    # original mean
mean(bootstrap_sample1)  # bootstrap mean (different)

Bootstrap Distribution of the Mean

Generate many bootstrap resamples, compute the statistic on each, and collect the results. This bootstrap distribution approximates the sampling distribution of the statistic.

set.seed(42)
x <- c(14, 18, 11, 13, 6, 8, 2, 17, 20, 10,
        15, 12, 9, 16, 7, 3, 19, 5, 4, 1)
n <- length(x)
B <- 5000  # number of bootstrap replicates

# Bootstrap distribution of the mean
boot_means <- replicate(B, {
  x_star <- sample(x, n, replace = TRUE)
  mean(x_star)
})

cat('Original mean:', mean(x), '\n')
cat('Bootstrap mean:', mean(boot_means), '\n')
cat('Bootstrap SE:', sd(boot_means), '\n')
cat('Theoretical SE:', sd(x)/sqrt(n))

Bootstrap for Any Statistic

The bootstrap works for any statistic — median, correlation, regression coefficients, trimmed mean. Simply replace mean() with your statistic of interest in the replicate loop.

set.seed(42)
x <- c(2, 4, 6, 8, 10, 12, 100, 1, 3, 5)
# Notice the outlier 100 - makes the mean unreliable
B <- 5000; n <- length(x)

# Bootstrap distribution of the median
boot_medians <- replicate(B, {
  median(sample(x, n, replace = TRUE))
})

# Bootstrap distribution of the trimmed mean (10%)
boot_tmeans <- replicate(B, {
  mean(sample(x, n, replace = TRUE), trim = 0.1)
})

cat('Sample median:', median(x), '\n')
cat('Bootstrap SE of median:', sd(boot_medians), '\n')
cat('Bootstrap SE of trimmed mean:', sd(boot_tmeans))

Bootstrap Confidence Intervals: Percentile Method

The simplest bootstrap CI: take quantiles of the bootstrap distribution. The 95% CI uses the 2.5th and 97.5th percentiles. Quick and intuitive — but can have coverage issues for skewed statistics.

set.seed(42)
x <- rnorm(30, mean = 5, sd = 2)
B <- 5000; n <- length(x)

# Bootstrap CI for the mean
boot_means <- replicate(B, mean(sample(x, n, replace = TRUE)))

# Percentile CI
ci_percentile <- quantile(boot_means, c(0.025, 0.975))
cat('Percentile CI:', round(ci_percentile, 3), '\n')

# For comparison: t-interval (parametric)
t_ci <- mean(x) + qt(c(0.025, 0.975), df = n-1) * sd(x)/sqrt(n)
cat('t-interval CI:', round(t_ci, 3), '\n')

cat('True mean: 5')

Bootstrap Standard Error

The bootstrap standard error is simply sd(boot_statistics). It estimates how much the statistic would vary across repeated samples from the population — without making distributional assumptions.

set.seed(42)
# Bootstrap SE for the ratio of two means
group_a <- rnorm(20, mean = 10, sd = 2)
group_b <- rnorm(20, mean = 8, sd = 2)
all_data <- data.frame(
  value = c(group_a, group_b),
  group = rep(c('A', 'B'), each = 20)
)

B <- 4000; n <- nrow(all_data)
boot_ratio <- replicate(B, {
  idx <- sample(1:n, n, replace = TRUE)
  d <- all_data[idx, ]
  mean(d$value[d$group == 'A']) /
    mean(d$value[d$group == 'B'])
})

cat('Observed ratio:', mean(group_a)/mean(group_b), '\n')
cat('Bootstrap SE:', round(sd(boot_ratio), 4), '\n')
cat('95% CI:', round(quantile(boot_ratio, c(.025,.975)), 3))

BCa Confidence Interval

The BCa (Bias-Corrected and Accelerated) CI is more accurate than the percentile CI, especially for skewed or biased statistics. It adjusts for bias and skewness in the bootstrap distribution.

# BCa CI implementation
bca_ci <- function(data, stat_fn, B = 2000, alpha = 0.05) {
  n <- length(data)
  theta_hat <- stat_fn(data)
  # Bootstrap replicates
  boot_vals <- replicate(B, stat_fn(sample(data, n, replace = TRUE)))
  # Bias correction z0
  z0 <- qnorm(mean(boot_vals < theta_hat))
  # Acceleration a (jackknife)
  jk <- sapply(seq_len(n), function(i) stat_fn(data[-i]))
  num <- sum((mean(jk) - jk)^3)
  den <- 6 * (sum((mean(jk) - jk)^2))^(3/2)
  a <- num / den
  # Adjusted quantiles
  z_alpha <- qnorm(c(alpha/2, 1 - alpha/2))
  p_adj <- pnorm(z0 + (z0 + z_alpha) / (1 - a * (z0 + z_alpha)))
  quantile(boot_vals, p_adj)
}

set.seed(42)
x <- rexp(25, rate = 0.5)  # skewed distribution
bca_ci(x, median)

Bootstrap for Regression

Bootstrap regression CIs by resampling rows of the data frame. This handles non-normal errors and gives valid inference without normality assumptions.

set.seed(42)
n <- 40
x <- runif(n, 0, 10)
y <- 2 + 1.5 * x + rnorm(n, sd = 2)
df <- data.frame(x = x, y = y)
B <- 3000

# Bootstrap the slope coefficient
boot_slopes <- replicate(B, {
  idx <- sample(1:n, n, replace = TRUE)
  d_boot <- df[idx, ]
  coef(lm(y ~ x, data = d_boot))[2]
})

cat('OLS slope:', round(coef(lm(y~x, data=df))[2], 3), '\n')
cat('Bootstrap SE of slope:', round(sd(boot_slopes), 4), '\n')
cat('Bootstrap 95% CI:', round(quantile(boot_slopes, c(.025,.975)), 3))

Number of Bootstrap Replicates

How many bootstrap replicates B do you need? For standard errors: B=200-500. For percentile CIs: B=1000-2000. For BCa CIs: B=2000-5000. More is always better but has diminishing returns beyond 10,000.

set.seed(42)
x <- rnorm(50, mean = 3, sd = 1)
B_values <- c(100, 500, 1000, 2000, 5000, 10000)

# See how CI width varies with B
results <- sapply(B_values, function(B) {
  boot_m <- replicate(B, mean(sample(x, length(x), replace = TRUE)))
  q <- quantile(boot_m, c(0.025, 0.975))
  q[2] - q[1]  # CI width
})

result_df <- data.frame(B = B_values, ci_width = round(results, 4))
print(result_df)
# CI width stabilizes as B increases

Paired Bootstrap

For two-sample problems, resample pairs (x, y) together — not x and y independently. This preserves the within-pair dependence structure, giving valid CIs for correlation and paired differences.

set.seed(42)
# Paired data: before/after treatment
before <- c(10, 12, 8, 15, 11, 9, 14, 13)
after  <- c(12, 14, 9, 16, 11, 10, 15, 12)
n <- length(before)
B <- 4000

# Bootstrap paired mean difference
boot_diff <- replicate(B, {
  idx <- sample(1:n, n, replace = TRUE)
  mean(after[idx] - before[idx])
})

observed_diff <- mean(after - before)
cat('Observed mean diff:', observed_diff, '\n')
cat('Bootstrap SE:', round(sd(boot_diff), 4), '\n')
cat('95% CI:', round(quantile(boot_diff, c(0.025, 0.975)), 3))

Bootstrap Hypothesis Test

Bootstrap can also test hypotheses. To test H₀: θ=θ₀, generate the null distribution by shifting/re-centering bootstrap samples, then compute the p-value as the fraction exceeding the observed statistic.

set.seed(42)
# Test H0: mean = 0 vs H1: mean != 0
x <- rnorm(30, mean = 0.5, sd = 2)
theta0 <- 0  # null hypothesis
observed_t <- (mean(x) - theta0) / (sd(x) / sqrt(length(x)))

B <- 5000; n <- length(x)
# Shift x to have mean = theta0 under H0
x_centered <- x - mean(x) + theta0

boot_t <- replicate(B, {
  x_star <- sample(x_centered, n, replace = TRUE)
  (mean(x_star) - theta0) / (sd(x_star) / sqrt(n))
})

p_value <- mean(abs(boot_t) >= abs(observed_t))
cat('Observed t:', round(observed_t, 3), '\n')
cat('Bootstrap p-value:', round(p_value, 4))

Boot Package Overview

The boot package provides boot(data, statistic, R) with advanced features: BCa CIs via boot.ci(), parallel computation, stratified sampling. The statistic function receives data and an index vector.

# library(boot)  # uncomment to use

# The boot() statistic function signature:
# statistic(data, indices) -> scalar or vector

# Example (conceptual - requires boot package):
# mean_stat <- function(data, indices) {
#   mean(data[indices])
# }
# results <- boot(data = x, statistic = mean_stat, R = 5000)
# boot.ci(results, type = c('perc', 'bca'))  # CIs
# plot(results)  # histogram of bootstrap distribution

# Manual equivalent:
set.seed(42)
x <- rnorm(30, mean = 5)
B <- 2000
boot_vals <- replicate(B, mean(sample(x, length(x), replace = TRUE)))
quantile(boot_vals, c(0.025, 0.975))

Quick Check

Test your understanding of bootstrap resampling in R.

Recap: Bootstrap Resampling

Key takeaways: Bootstrap resamples data with replacement using sample(x, n, replace=TRUE). Use replicate(B, ...) to generate B bootstrap statistics. sd(boot_stats) gives the bootstrap SE. Percentile CI: quantile(boot_stats, c(0.025, 0.975)). Use B≥2000 for CIs. The boot package adds BCa CIs and parallel computation. Bootstrap works for any statistic without distributional assumptions.

set.seed(42)
x <- c(3, 5, 7, 2, 9, 4, 6, 8, 1, 10)
n <- length(x); B <- 3000

# Generic bootstrap template:
boot_stat <- replicate(B, {
  x_star <- sample(x, n, replace = TRUE)
  median(x_star)  # replace with any statistic
})

# Summary
cat('Original median:', median(x), '\n')
cat('Bootstrap SE:', round(sd(boot_stat), 3), '\n')
ci <- quantile(boot_stat, c(0.025, 0.975))
cat('95% Percentile CI: [', ci[1], ',', ci[2], ']')

Frequently asked questions

Is the “Bootstrap Resampling in R” lesson free?

Yes — the full text of “Bootstrap Resampling in R” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

What will I learn in “Bootstrap Resampling in R”?

Implement bootstrap confidence intervals using sample() with replacement. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start R Academy?

No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Bootstrap Resampling in R” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this R Academy lesson?

Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. set.seed() and Reproducibility
  2. Generating Random Distributions
  3. Monte Carlo Simulation Basics
  4. Bootstrap Resampling in R
← Back to R Academy