Supongamos que tengo unos datos con dos grupos independientes:
g1.lengths <- c (112.64, 97.10, 84.18, 106.96, 98.42, 101.66)
g2.lengths <- c (84.44, 82.10, 83.26, 81.02, 81.86, 86.80,
85.84, 97.08, 79.64, 83.32, 91.04, 85.92,
73.52, 85.58, 97.70, 89.72, 88.92, 103.72,
105.02, 99.48, 89.50, 81.74)
group = rep (c ("g1", "g2"), c (length (g1.lengths), length (g2.lengths)))
lengths = data.frame( lengths = c(g1.lengths, g2.lengths), group)
Es evidente que el tamaño de la muestra por grupo está sesgado cuando g1 tiene 6 observaciones y g2 tiene 22 . El ANOVA tradicional sugiere que los grupos tienen medias diferentes cuando el valor crítico se fija en 0,05 (el valor p es 0.0044 ).
summary (aov (lengths~group, data = lengths))
Dado que mi objetivo es comparar la diferencia de medias, unos datos tan desequilibrados y con una muestra tan pequeña podrían dar resultados inadecuados con el enfoque tradicional. Por lo tanto, quiero realizar una prueba de permutación y bootstrap.
PRUEBA DE PERMUTACIÓN
La hipótesis nula (H0) afirma que las medias de los grupos son iguales. Esta hipótesis en la prueba de permutación se justifica agrupando los grupos en una sola muestra. Esto garantiza que las muestras de los dos grupos se extrajeron de la misma distribución. Mediante el muestreo repetido (o, más exactamente, la reorganización) de los datos agrupados, las observaciones se reasignan (barajan) a las muestras de una nueva forma y se calcula el estadístico de la prueba. Si se realiza esto n veces, se obtendrá la distribución de muestreo de los estadísticos de la prueba en el supuesto de que H0 sea VERDADERO. Al final, en la hipótesis H0, el valor p es la probabilidad de que el estadístico de prueba sea igual o superior al valor observado.
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.p <- mean (g1.lengths) - mean (g2.lengths)
iterations <- 10000
sampl.dist.p <- NULL
set.seed (5)
for (i in 1 : iterations) {
resample <- sample (c(1:length (pool)), length(pool))
g1.perm = pool[resample][1 : s.size.g1]
g2.perm = pool[resample][(s.size.g1+1) : length(pool)]
sampl.dist.p[i] = mean (g1.perm) - mean (g2.perm)
}
p.permute <- (sum (abs (sampl.dist.p) >= abs(obs.diff.p)) + 1)/ (iterations+1)
El valor p de la prueba de permutación es 0.0053 . OK, si lo he hecho correctamente, las permutaciones y el ANOVA paramétrico dan resultados casi idénticos.
BOOTSTRAP
En primer lugar, soy consciente de que bootstrap no puede ayudar cuando el tamaño de la muestra es demasiado pequeño. Este post demostró que puede ser aún peor y engañoso . También, el segundo puso de relieve que la prueba de permutación suele ser mejor que la bootstrap cuando la comprobación de hipótesis es el objetivo principal. No obstante, este gran post aborda importantes diferencias entre los métodos informáticos intensivos. Sin embargo, aquí quiero plantear (creo) una cuestión diferente.
Permítanme presentarles primero el enfoque bootstrap más común (Bootstrap1: remuestreo dentro de la muestra conjunta ):
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.b1 <- mean (g1.lengths) - mean (g2.lengths)
iterations <- 10000
sampl.dist.b1 <- NULL
set.seed (5)
for (i in 1 : iterations) {
resample <- sample (c(1:length (pool)), length(pool), replace = TRUE)
# "replace = TRUE" is the only difference between bootstrap and permutations
g1.perm = pool[resample][1 : s.size.g1]
g2.perm = pool[resample][(s.size.g1+1) : length(pool)]
sampl.dist.b1[i] = mean (g1.perm) - mean (g2.perm)
}
p.boot1 <- (sum (abs (sampl.dist.b1) >= obs.diff.b1) + 1)/ (iterations+1)
El valor P del bootstrap realizado de esta forma es 0.005 . Aunque esto suene razonable y casi idéntico al ANOVA paramétrico y a la prueba de permutación, ¿es apropiado justificar H0 en este bootstrap sobre la base de que sólo muestras agrupadas de la que extrajimos las muestras posteriores?
Enfoque diferente que he encontrado en varios artículos científicos. En concreto, vi que los investigadores modifican los datos para cumplir H0 antes del bootstrap. Buscando por ahí, he encontrado muy interesante post en CV donde @jan.s explicó resultados inusuales de bootstrap en la pregunta posterior en la que el objetivo era comparar dos medias. Sin embargo, en ese post no se explica cómo realizar el bootstrap cuando los datos se modifican antes del bootstrap. El enfoque en el que los datos se modifican antes del bootstrap es el siguiente:
- H0 afirma que las medias de dos grupos son iguales
- H0 se cumple si restamos las observaciones individuales de la media de la muestra conjunta
En este caso, la modificación de los datos debería afectar a las medias de los grupos, y por tanto a su diferencia, pero no a la variación dentro de (y entre) los grupos.
- Los datos modificados servirán de base para otros bootstrap, con la advertencia de que el muestreo se lleva a cabo dentro de cada grupo por separado .
- Se calcula la diferencia entre la media bootstrapped de g1 y g2 y se compara con la diferencia observada (no modificada) entre grupos.
- La proporción de valores extremos iguales o superiores al observado dividida por el número de iteraciones dará el valor p.
Aquí está el código (Bootstrap2: remuestreo dentro de los grupos tras modificar que H0 es VERDADERO ):
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.b2 <- mean (g1.lengths) - mean (g2.lengths)
# make H0 to be true (no difference between means of two groups)
H0 <- pool - mean (pool)
# g1 from H0
g1.H0 <- H0[1:s.size.g1]
# g2 from H0
g2.H0 <- H0[(s.size.g1+1):length(pool)]
iterations <- 10000
sampl.dist.b2 <- NULL
set.seed (5)
for (i in 1 : iterations) {
# Sample with replacement in g1
g1.boot = sample (g1.H0, replace = T)
# Sample with replacement in g2
g2.boot = sample (g2.H0, replace = T)
# bootstrapped difference
sampl.dist.b2[i] <- mean (g1.boot) - mean (g2.boot)
}
p.boot2 <- (sum (abs (sampl.dist.b2) >= obs.diff.b2) + 1)/ (iterations+1)
Tal bootstrap realizado dará un valor p de 0.514 que es tremendamente diferente en comparación con las pruebas anteriores. Creo que esto tiene que ver con @jan.s explicación, pero no puedo averiguar dónde está la clave ...