Capítulo 4

Bootstrap y Remuestreo

4.1 El Principio del Bootstrap

El bootstrap usa remuestreo con reemplazo de los datos originales para estimar la distribución muestral de un estadístico. No asume ninguna distribución teórica.

Muestra original: {x1,,xn}    Bootstrap: {x1,,xn}\text{Muestra original: } \{x_1, \ldots, x_n\} \implies \text{Bootstrap: } \{x_1^*, \ldots, x_n^*\}

Repetimos B veces (típicamente 1000-10000) para obtener la distribución bootstrap del estadístico.

4.2 Bootstrap para la Media

python
import numpy as np

np.random.seed(42)
data = np.random.exponential(scale=5, size=100)
print(f"Media muestral: {np.mean(data):.3f}")

B = 10000
means = np.zeros(B)
for i in range(B):
    sample = np.random.choice(data, size=len(data), replace=True)
    means[i] = np.mean(sample)

ci_low = np.percentile(means, 2.5)
ci_high = np.percentile(means, 97.5)
print(f"IC 95% bootstrap: [{ci_low:.3f}, {ci_high:.3f}]")
print(f"Error estándar bootstrap: {np.std(means):.3f}")

4.3 Bootstrap para la Mediana (o cualquier estadístico)

El bootstrap funciona para cualquier estadístico: mediana, correlación, diferencia de medias, ratio, percentiles...

python
# Bootstrap para la mediana
medians = np.zeros(B)
for i in range(B):
    sample = np.random.choice(data, size=len(data), replace=True)
    medians[i] = np.median(sample)

ci_low = np.percentile(medians, 2.5)
ci_high = np.percentile(medians, 97.5)
print(f"Mediana: {np.median(data):.3f}")
print(f"IC bootstrap mediana: [{ci_low:.3f}, {ci_high:.3f}]")

4.4 Bootstrap de dos grupos

python
g1 = np.random.normal(5, 1, 50)
g2 = np.random.normal(5.5, 1, 50)

diffs = np.zeros(B)
for i in range(B):
    s1 = np.random.choice(g1, size=len(g1), replace=True)
    s2 = np.random.choice(g2, size=len(g2), replace=True)
    diffs[i] = np.mean(s1) - np.mean(s2)

ci = np.percentile(diffs, [2.5, 97.5])
print(f"Diferencia observada: {np.mean(g1) - np.mean(g2):.3f}")
print(f"IC 95%: [{ci[0]:.3f}, {ci[1]:.3f}]")
# Si el IC no contiene 0 → diferencia significativa

4.5 Tests de Permutación

Los tests de permutación son la versión no paramétrica de un test de hipótesis vía remuestreosin reemplazo. Se mezclan aleatoriamente las etiquetas de grupo.

python
observado = np.mean(g1) - np.mean(g2)
combined = np.concatenate([g1, g2])
n1 = len(g1)

count = 0
N = 10000
for _ in range(N):
    np.random.shuffle(combined)
    perm_mean = np.mean(combined[:n1]) - np.mean(combined[n1:])
    if abs(perm_mean) >= abs(observado):
        count += 1

p_valor = count / N
print(f"Diferencia observada: {observado:.3f}")
print(f"p-valor permutación: {p_valor:.4f}")

4.6 Jackknife

El jackknife estima sesgo y varianza dejando fuera una observación cada vez:

θ^(i)=estadıˊstico sin la obs i\hat{\theta}_{(i)} = \text{estadístico sin la obs } i
Sesgo=(n1)(θ^ˉ()θ^)\text{Sesgo} = (n-1)(\bar{\hat{\theta}}_{(\cdot)} - \hat{\theta})
python
n = len(data)
jack_means = np.zeros(n)
for i in range(n):
    mask = np.ones(n, dtype=bool)
    mask[i] = False
    jack_means[i] = np.mean(data[mask])

jack_mean = np.mean(jack_means)
sesgo = (n - 1) * (jack_mean - np.mean(data))
print(f"Sesgo estimado: {sesgo:.4f}")