¿Cómo funciona realmente el bootstrapping en R?

22

He estado buscando en el paquete de arranque en R y aunque he encontrado una serie de buenos manuales sobre cómo usarlo, todavía no he encontrado nada que describa exactamente lo que está sucediendo "detrás de escena". Por ejemplo, en este ejemplo , la guía muestra cómo usar los coeficientes de regresión estándar como punto de partida para una regresión bootstrap, pero no explica qué está haciendo realmente el procedimiento bootstrap para derivar los coeficientes de regresión bootstrap. Parece que hay algún tipo de proceso iterativo que está sucediendo, pero parece que no puedo entender exactamente qué está sucediendo.

zgall1
fuente
3
Ha pasado mucho tiempo desde la última vez que lo abrí, así que no sé si responderá a su pregunta, pero el paquete de arranque se basa en particular en los métodos detallados en Davison, AC y Hinkley, DV (1997). Métodos Bootstrap y su aplicación. Cambridge: Cambridge University Press. (La referencia también se cita en el archivo de ayuda para el paquete de arranque .)
Gala del

Respuestas:

34

Hay varios "sabores" o formas de bootstrap (por ejemplo, no paramétrico, paramétrico, remuestreo residual y muchos más). El bootstrap en el ejemplo se llama bootstrap no paramétrico , o remuestreo de casos (ver aquí , aquí , aquí y aquí para aplicaciones en regresión). La idea básica es que trate su muestra como población y extraiga repetidamente nuevas muestras con reemplazo . Todas las observaciones originales tienen la misma probabilidad de ser dibujadas en la nueva muestra. Luego calcula y almacena las estadísticas de interés, esta puede ser la media, la mediana o los coeficientes de regresión utilizando la muestra recién extraída. Esto se repite veces. En cada iteración, algunas observaciones de su muestra original se dibujan varias veces, mientras que algunas observaciones pueden no extraerse en absoluto. Después de iteraciones, tiene estimaciones de bootstrap almacenadas de las estadísticas de interés (por ejemplo, si y la estadística de interés es la media, tiene 1000 estimaciones de bootstrap de la media). Por último, se calculan estadísticas resumidas como la media, la mediana y la desviación estándar de las estimaciones de arranque.nortenortenortenorte=1000norte

Bootstrapping se usa a menudo para:

  1. Cálculo de intervalos de confianza (y estimación de los errores estándar)
  2. Estimación del sesgo de las estimaciones puntuales.

Existen varios métodos para calcular los intervalos de confianza basados ​​en las muestras de bootstrap ( este documento proporciona una explicación y orientación). Un método muy simple para calcular un intervalo de confianza del 95% es simplemente calcular los percentiles empírico 2.5 y 97.5 de las muestras de bootstrap (este intervalo se denomina intervalo de percentil de bootstrap; consulte el código a continuación). El método del intervalo de percentil simple rara vez se usa en la práctica, ya que existen mejores métodos, como el bootstrap acelerado y con corrección de sesgos (BCa). Los intervalos BCa se ajustan tanto al sesgo como a la asimetría en la distribución de bootstrap.

El sesgo se estima simplemente como la diferencia entre la media de las muestras de rutina de carga almacenadas y las estimaciones originales.norte

Repitamos el ejemplo del sitio web pero usando nuestro propio ciclo incorporando las ideas que he esbozado anteriormente (dibujando repetidamente con reemplazo):

#-----------------------------------------------------------------------------
# Load packages
#-----------------------------------------------------------------------------

require(ggplot2)
require(pscl)
require(MASS)
require(boot)

#-----------------------------------------------------------------------------
# Load data
#-----------------------------------------------------------------------------

zinb <- read.csv("http://www.ats.ucla.edu/stat/data/fish.csv")
zinb <- within(zinb, {
  nofish <- factor(nofish)
  livebait <- factor(livebait)
  camper <- factor(camper)
})

#-----------------------------------------------------------------------------
# Calculate zero-inflated regression
#-----------------------------------------------------------------------------

m1 <- zeroinfl(count ~ child + camper | persons, data = zinb,
               dist = "negbin", EM = TRUE)

#-----------------------------------------------------------------------------
# Store the original regression coefficients
#-----------------------------------------------------------------------------

original.estimates <- as.vector(t(do.call(rbind, coef(summary(m1)))[, 1:2]))

#-----------------------------------------------------------------------------
# Set the number of replications
#-----------------------------------------------------------------------------

n.sim <- 2000

#-----------------------------------------------------------------------------
# Set up a matrix to store the results
#-----------------------------------------------------------------------------

store.matrix <- matrix(NA, nrow=n.sim, ncol=12)

#-----------------------------------------------------------------------------
# The loop
#-----------------------------------------------------------------------------

set.seed(123)

for(i in 1:n.sim) {

  #-----------------------------------------------------------------------------
  # Draw the observations WITH replacement
  #-----------------------------------------------------------------------------

  data.new <- zinb[sample(1:dim(zinb)[1], dim(zinb)[1], replace=TRUE),]

  #-----------------------------------------------------------------------------
  # Calculate the model with this "new" data
  #-----------------------------------------------------------------------------

  m <- zeroinfl(count ~ child + camper | persons,
                data = data.new, dist = "negbin",
                start = list(count = c(1.3711, -1.5152, 0.879),
                             zero = c(1.6028, -1.6663)))

  #-----------------------------------------------------------------------------
  # Store the results
  #-----------------------------------------------------------------------------

  store.matrix[i, ] <- as.vector(t(do.call(rbind, coef(summary(m)))[, 1:2]))

}


#-----------------------------------------------------------------------------
# Save the means, medians and SDs of the bootstrapped statistics
#-----------------------------------------------------------------------------

boot.means <- colMeans(store.matrix, na.rm=T)

boot.medians <- apply(store.matrix,2,median, na.rm=T)

boot.sds <- apply(store.matrix,2,sd, na.rm=T)

#-----------------------------------------------------------------------------
# The bootstrap bias is the difference between the mean bootstrap estimates
# and the original estimates
#-----------------------------------------------------------------------------

boot.bias <- colMeans(store.matrix, na.rm=T) - original.estimates

#-----------------------------------------------------------------------------
# Basic bootstrap CIs based on the empirical quantiles
#-----------------------------------------------------------------------------

conf.mat <- matrix(apply(store.matrix, 2 ,quantile, c(0.025, 0.975), na.rm=T),
ncol=2, byrow=TRUE)
colnames(conf.mat) <- c("95%-CI Lower", "95%-CI Upper")

Y aquí está nuestra tabla resumen:

#-----------------------------------------------------------------------------
# Set up summary data frame
#-----------------------------------------------------------------------------

summary.frame <- data.frame(mean=boot.means, median=boot.medians,
sd=boot.sds, bias=boot.bias, "CI_lower"=conf.mat[,1], "CI_upper"=conf.mat[,2])

summary.frame

      mean  median       sd       bias CI_lower CI_upper
1   1.2998  1.3013  0.39674 -0.0712912  0.51960   2.0605
2   0.2527  0.2486  0.03208 -0.0034461  0.19898   0.3229
3  -1.5662 -1.5572  0.26220 -0.0509239 -2.12900  -1.0920
4   0.2005  0.1986  0.01949  0.0049019  0.16744   0.2418
5   0.9544  0.9252  0.48915  0.0753405  0.03493   1.9025
6   0.2702  0.2688  0.02043  0.0009583  0.23272   0.3137
7  -0.8997 -0.9082  0.22174  0.0856793 -1.30664  -0.4380
8   0.1789  0.1781  0.01667  0.0029513  0.14494   0.2140
9   2.0683  1.7719  1.59102  0.4654898  0.44150   8.0471
10  4.0209  0.8270 13.23434  3.1845710  0.58114  57.6417
11 -2.0969 -1.6717  1.56311 -0.4306844 -8.43440  -1.1156
12  3.8660  0.6435 13.27525  3.1870642  0.33631  57.6062

Algunas explicaciones

  • La diferencia entre la media de las estimaciones de arranque y las estimaciones originales es lo que se llama "sesgo" en la salida de boot
  • Lo que el resultado de las bootllamadas "error estándar" es la desviación estándar de las estimaciones de arranque

Compárelo con la salida de boot:

#-----------------------------------------------------------------------------
# Compare with boot output and confidence intervals
#-----------------------------------------------------------------------------

set.seed(10)
res <- boot(zinb, f, R = 2000, parallel = "snow", ncpus = 4)

res

Bootstrap Statistics :
       original       bias    std. error
t1*   1.3710504 -0.076735010  0.39842905
t2*   0.2561136 -0.003127401  0.03172301
t3*  -1.5152609 -0.064110745  0.26554358
t4*   0.1955916  0.005819378  0.01933571
t5*   0.8790522  0.083866901  0.49476780
t6*   0.2692734  0.001475496  0.01957823
t7*  -0.9853566  0.083186595  0.22384444
t8*   0.1759504  0.002507872  0.01648298
t9*   1.6031354  0.482973831  1.58603356
t10*  0.8365225  3.240981223 13.86307093
t11* -1.6665917 -0.453059768  1.55143344
t12*  0.6793077  3.247826469 13.90167954

perc.cis <- matrix(NA, nrow=dim(res$t)[2], ncol=2)
    for( i in 1:dim(res$t)[2] ) {
  perc.cis[i,] <- boot.ci(res, conf=0.95, type="perc", index=i)$percent[4:5] 
}
colnames(perc.cis) <- c("95%-CI Lower", "95%-CI Upper")

perc.cis 

      95%-CI Lower 95%-CI Upper
 [1,]      0.52240       2.1035
 [2,]      0.19984       0.3220
 [3,]     -2.12820      -1.1012
 [4,]      0.16754       0.2430
 [5,]      0.04817       1.9084
 [6,]      0.23401       0.3124
 [7,]     -1.29964      -0.4314
 [8,]      0.14517       0.2149
 [9,]      0.29993       8.0463
[10,]      0.57248      56.6710
[11,]     -8.64798      -1.1088
[12,]      0.33048      56.6702

#-----------------------------------------------------------------------------
# Our summary table
#-----------------------------------------------------------------------------

summary.frame

      mean  median       sd       bias CI_lower CI_upper
1   1.2998  1.3013  0.39674 -0.0712912  0.51960   2.0605
2   0.2527  0.2486  0.03208 -0.0034461  0.19898   0.3229
3  -1.5662 -1.5572  0.26220 -0.0509239 -2.12900  -1.0920
4   0.2005  0.1986  0.01949  0.0049019  0.16744   0.2418
5   0.9544  0.9252  0.48915  0.0753405  0.03493   1.9025
6   0.2702  0.2688  0.02043  0.0009583  0.23272   0.3137
7  -0.8997 -0.9082  0.22174  0.0856793 -1.30664  -0.4380
8   0.1789  0.1781  0.01667  0.0029513  0.14494   0.2140
9   2.0683  1.7719  1.59102  0.4654898  0.44150   8.0471
10  4.0209  0.8270 13.23434  3.1845710  0.58114  57.6417
11 -2.0969 -1.6717  1.56311 -0.4306844 -8.43440  -1.1156
12  3.8660  0.6435 13.27525  3.1870642  0.33631  57.6062

Compare las columnas de "sesgo" y el "error estándar" con la columna "SD" de nuestra propia tabla de resumen. Nuestros intervalos de confianza del 95% son muy similares a los intervalos de confianza calculados boot.cimediante el método del percentil (aunque no todos: observe el límite inferior del parámetro con el índice 9).

COOLSerdash
fuente
Gracias por la respuesta detallada. ¿Básicamente estás diciendo que los coeficientes son el promedio de los 2000 conjuntos de coeficientes que se generaron?
zgall1
44
@ zgall1 Sí, básicamente (o las medianas). Pero con mayor frecuencia, las estimaciones puntuales son de menor interés en el arranque. A menudo, la razón para usar bootstrap es encontrar intervalos de confianza que tengan en cuenta la distribución de la muestra y no asuman ninguna distribución (por ejemplo, normal). De esa manera, los intervalos de confianza de arranque son a menudo asimétricos, mientras que los intervalos de confianza basados ​​en la distribución normal o son simétricos. t
COOLSerdash
"La idea básica es que trate su muestra como población y extraiga repetidamente nuevas muestras con reemplazo": ¿cómo determinar cuál es el tamaño de las nuevas muestras?
Sinusx
1
@Sinusx Normalmente, se extraen muestras del mismo tamaño que la muestra original. La idea crucial es extraer la muestra con reemplazo. Por lo tanto, algunos valores de la muestra original se dibujarán varias veces y otros no.
COOLSerdash
6

Debe centrarse en la función que se pasa bootcomo parámetro "estadístico" y observar cómo se construye.

f <- function(data, i) {
  require(pscl)
  m <- zeroinfl(count ~ child + camper | persons,
    data = data[i, ], dist = "negbin",
    start = list(count = c(1.3711, -1.5152, 0.879), zero = c(1.6028, -1.6663)))
  as.vector(t(do.call(rbind, coef(summary(m)))[, 1:2]))
}

El argumento "datos" recibirá un marco de datos completo, pero el argumento "i" recibirá una muestra de índices de fila generados por el "arranque" y tomados de 1: NROW (datos). Como puede ver en ese código, "i" se usa para crear una neo-muestra que se pasa zeroinly luego solo se devuelven partes seleccionadas de sus resultados.

Imaginemos que "i" es {1,2,3,3,3,6,7,7,10}. La función "[" devolverá solo aquellas filas con 3 copias de la fila 3 y 2 copias de la fila 7. Esa sería la base para un solo zeroinl()cálculo y luego los coeficientes se devolverán bootcomo resultado de esa réplica del proceso. El número de tales réplicas es controlado por el parámetro "R".

Dado que solo se devuelven los coeficientes de regresión statisticen este caso, la bootfunción devolverá estos coeficientes acumulados como el valor de "t". Se pueden realizar más comparaciones con otras funciones del paquete de arranque.

DWin
fuente