9 votos

Causas de las distribuciones bimodales en el bootstrap de un modelo de meta-análisis

Ayudo a un colega a realizar un bootstrap de un modelo de meta-análisis de efectos mixtos utilizando el metafor Marco del paquete R creado por @Wolfgang.

Resulta interesante y preocupante que para uno de los coeficientes del modelo obtenga una distribución bimodal al realizar el bootstrap (véase el panel inferior derecho de la figura siguiente).

Supongo que una de las causas principales podría ser el hecho de que al hacer bootstrapping, digamos que la mitad de los modelos convergen en una solución local y la otra mitad en otra. Intenté ajustar el algoritmo de convergencia como se sugiere en esta documentación de metafor - Problemas de convergencia con la función rma() . Además, he probado otros algoritmos de convergencia como bobyqa y newuoa como se sugiere en la documentación de ayuda de rma.mv función, pero obtuvo la misma respuesta bimodal.

También intenté eliminar algunos de los posibles valores atípicos del grupo problemático, como se sugiere en Cómo interpretar la distribución multimodal de la correlación bootstrapped pero en vano.

No pude encontrar una manera de reproducir esto así que cargué los datos en un Repositorio GitHub (también los enlaces en la sección de código de abajo deberían cargar en su entorno todo lo necesario para probar el caso). Ejecuto el bootstrapping en un cluster Linux como un trabajo de array (por si acaso, el shell script es trabajo.sh que ejecuta en cada CPU el R script bootstrap.r que ejecuta el modelo descrito a continuación). Una sola ejecución tarda entre 2 y 3 minutos. Tenga en cuenta que el bootstrap 100 veces también es suficiente para detectar la respuesta bimodal. A continuación se muestra un ejemplo para 1000 iteraciones. Estoy familiarizado con R y otros métodos pero no tanto con el meta-análisis.

Agradecería que me ayudaran a entender si la distribución bimodal está bien (aunque podría deberse a problemas de convergencia) y, si no, qué se puede hacer al respecto. (además de lo que ya he intentado)

A continuación, se comparan los coeficientes del bootstrapping (líneas rojas) y de una única ejecución del modelo completo (líneas azules). Los histogramas representan las distribuciones de cada coeficiente obtenidas por bootstrap. El muestreo de los datos para el bootstrapping se hizo como selección con reemplazo de cada grupo/combinación formada por los dos efectos fijos. Sus tamaños de muestra brutos son:

table(dt$f1, dt$f2)
#>       
#>        f2_1 f2_2 f2_3
#>   f1_1  177  174   41
#>   f1_2  359  363  107

library(data.table)
library(ggplot2)
library(metafor)
#> Loading required package: Matrix
#> Loading 'metafor' package (version 2.0-0). For an overview 
#> and introduction to the package please type: help(metafor).

load(url("https://github.com/valentinitnelav/test/raw/master/bimodal_distrib_boot/coef_boot_dt_1010.rda"))
load(url("https://github.com/valentinitnelav/test/raw/master/bimodal_distrib_boot/rmamv_model.rda"))
load(url("https://github.com/valentinitnelav/test/raw/master/bimodal_distrib_boot/data.rda"))

coef_dt <- data.frame(estim = rmamv_model[["beta"]])
coef_dt$coef_name <- rownames(coef_dt)
coef_dt <- rbind(coef_dt,
                 coef_boot_dt[, .(estim = mean(coef)), by = coef_name])
coef_dt[, gr := rep(c("estim_model", "estim_boot"), each = 6)]

ggplot(data = coef_boot_dt,
       aes(x = coef,
           group = coef_name)) +
  geom_histogram(bins = 100) +
  geom_vline(aes(xintercept = estim,
                 group = gr,
                 color = gr),
             lwd = 1,
             data = coef_dt) +
  facet_wrap(vars(coef_name), ncol = 2)

Creado el 2019-05-02 por el paquete reprex (v0.2.1)

El modelo es el siguiente:

rmamv_model <- rma.mv(y ~ f2:f1 - 1,
                  V = var_y,
                  random = list(~ 1|r1,
                                ~ 1|r2),
                  R = list(r2 = cor_mat),
                  data = dt,
                  method = "REML",
                  # Tune the convergence algorithm / optimizer
                  control = list(optimizer = "nlminb",
                                 iter.max = 1000,
                                 step.min = 0.4,
                                 step.max = 0.5))

Información de la sesión de R:

devtools::session_info()
#> - Session info ----------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.5.2 (2018-12-20)
#>  os       Windows 7 x64 SP 1          
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  English_United States.1252  
#>  ctype    English_United States.1252               
#>  date     2019-05-02                  
#> 
#> - Packages --------------------------------------------------------------
#>  package     * version date       lib source        
#>  assertthat    0.2.1   2019-03-21 [1] CRAN (R 3.5.2)
#>  backports     1.1.3   2018-12-14 [1] CRAN (R 3.5.2)
#>  callr         3.2.0   2019-03-15 [1] CRAN (R 3.5.3)
#>  cli           1.1.0   2019-03-19 [1] CRAN (R 3.5.3)
#>  colorspace    1.4-1   2019-03-18 [1] CRAN (R 3.5.3)
#>  crayon        1.3.4   2017-09-16 [1] CRAN (R 3.5.1)
#>  curl          3.3     2019-01-10 [1] CRAN (R 3.5.2)
#>  data.table  * 1.12.0  2019-01-13 [1] CRAN (R 3.5.2)
#>  desc          1.2.0   2018-05-01 [1] CRAN (R 3.5.1)
#>  devtools      2.0.1   2018-10-26 [1] CRAN (R 3.5.1)
#>  digest        0.6.18  2018-10-10 [1] CRAN (R 3.5.1)
#>  dplyr         0.8.0.1 2019-02-15 [1] CRAN (R 3.5.2)
#>  evaluate      0.13    2019-02-12 [1] CRAN (R 3.5.2)
#>  fs            1.2.7   2019-03-19 [1] CRAN (R 3.5.3)
#>  ggplot2     * 3.1.0   2018-10-25 [1] CRAN (R 3.5.1)
#>  glue          1.3.1   2019-03-12 [1] CRAN (R 3.5.2)
#>  gtable        0.2.0   2016-02-26 [1] CRAN (R 3.5.1)
#>  highr         0.8     2019-03-20 [1] CRAN (R 3.5.3)
#>  htmltools     0.3.6   2017-04-28 [1] CRAN (R 3.5.1)
#>  httr          1.4.0   2018-12-11 [1] CRAN (R 3.5.2)
#>  knitr         1.22    2019-03-08 [1] CRAN (R 3.5.2)
#>  labeling      0.3     2014-08-23 [1] CRAN (R 3.5.0)
#>  lattice       0.20-38 2018-11-04 [2] CRAN (R 3.5.2)
#>  lazyeval      0.2.2   2019-03-15 [1] CRAN (R 3.5.3)
#>  magrittr      1.5     2014-11-22 [1] CRAN (R 3.5.1)
#>  Matrix      * 1.2-15  2018-11-01 [2] CRAN (R 3.5.2)
#>  memoise       1.1.0   2017-04-21 [1] CRAN (R 3.5.1)
#>  metafor     * 2.0-0   2017-06-22 [1] CRAN (R 3.5.2)
#>  mime          0.6     2018-10-05 [1] CRAN (R 3.5.1)
#>  munsell       0.5.0   2018-06-12 [1] CRAN (R 3.5.1)
#>  nlme          3.1-137 2018-04-07 [2] CRAN (R 3.5.2)
#>  pillar        1.3.1   2018-12-15 [1] CRAN (R 3.5.2)
#>  pkgbuild      1.0.3   2019-03-20 [1] CRAN (R 3.5.3)
#>  pkgconfig     2.0.2   2018-08-16 [1] CRAN (R 3.5.1)
#>  pkgload       1.0.2   2018-10-29 [1] CRAN (R 3.5.1)
#>  plyr          1.8.4   2016-06-08 [1] CRAN (R 3.5.1)
#>  prettyunits   1.0.2   2015-07-13 [1] CRAN (R 3.5.1)
#>  processx      3.3.0   2019-03-10 [1] CRAN (R 3.5.3)
#>  ps            1.3.0   2018-12-21 [1] CRAN (R 3.5.2)
#>  purrr         0.3.2   2019-03-15 [1] CRAN (R 3.5.3)
#>  R6            2.4.0   2019-02-14 [1] CRAN (R 3.5.2)
#>  Rcpp          1.0.1   2019-03-17 [1] CRAN (R 3.5.3)
#>  remotes       2.0.2   2018-10-30 [1] CRAN (R 3.5.1)
#>  rlang         0.3.4   2019-04-07 [1] CRAN (R 3.5.3)
#>  rmarkdown     1.12    2019-03-14 [1] CRAN (R 3.5.3)
#>  rprojroot     1.3-2   2018-01-03 [1] CRAN (R 3.5.1)
#>  scales        1.0.0   2018-08-09 [1] CRAN (R 3.5.1)
#>  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 3.5.1)
#>  stringi       1.4.3   2019-03-12 [1] CRAN (R 3.5.2)
#>  stringr       1.4.0   2019-02-10 [1] CRAN (R 3.5.1)
#>  tibble        2.1.1   2019-03-16 [1] CRAN (R 3.5.3)
#>  tidyselect    0.2.5   2018-10-11 [1] CRAN (R 3.5.1)
#>  usethis       1.4.0   2018-08-14 [1] CRAN (R 3.5.1)
#>  withr         2.1.2   2018-03-15 [1] CRAN (R 3.5.1)
#>  xfun          0.5     2019-02-20 [1] CRAN (R 3.5.2)
#>  xml2          1.2.0   2018-01-24 [1] CRAN (R 3.5.1)
#>  yaml          2.2.0   2018-07-25 [1] CRAN (R 3.5.1)

6voto

Derek Swingley Puntos 3851

Gracias por proporcionar los datos y el código. He vuelto a ajustar el modelo con el que trabajas y el segundo componente de la varianza (para el que cor_mat se especifica) se desplaza a un valor realmente grande, lo cual es extraño. Sin embargo, el perfil de este componente de la varianza (con profile(rmamv_model, sigma2=2) ) indica que no hay problemas, así que no creo que sea un problema de convergencia. En cambio, creo que el problema surge porque el modelo no incluye un efecto aleatorio a nivel de estimación (que básicamente todo modelo meta-analítico debería incluir). Por lo tanto, sugeriría ajustar:

dt$id <- 1:nrow(dt)

res <- rma.mv(y ~ f2:f1 - 1,
              V = var_y,
              random = list(~ 1|r1,
                            ~ 1|r2, 
                            ~ 1|id),
              R = list(r2 = cor_mat),
              data = dt,
              method = "REML")

Los resultados parecen mucho más razonables. Sospecho que esto también podría resolver el problema de la distribución bootstrap bimodal de ese último coeficiente.

1 votos

¡Gracias @Wolfgang ! Se ha solucionado el problema. Los coeficientes parecen ahora mucho más razonables (se ajustan a las expectativas/teoría) y también se ha solucionado el problema de la distribución bimodal. Ya que estás súper familiarizado con estos temas y si los tienes a mano, sería maravilloso si también puedes proporcionar algunas referencias revisadas por pares que respalden la idea de incorporar un efecto aleatorio a nivel de observación. He encontrado Harrison, 2014 pero parece ser particular para los datos de recuento. Muchas gracias de nuevo.

0 votos

No conozco una referencia que lo diga literalmente, pero tal vez quieras echarle un vistazo: metafor-project.org/doku.php/

1voto

usεr11852 Puntos 5514

Sin tener acceso a un ejemplo reproducible es extremadamente difícil dar una respuesta definitiva a este comportamiento de arranque. Asumiendo que efectivamente no hay valores atípicos, sospecho que observamos un caso leve de El fenómeno de Stein sobre todo porque la metodología de efectos mixtos sugiere que hay cierta agrupación en nuestros datos.

Dicho lo anterior, yo sugeriría seguir adelante y mirar algunas de las ejecuciones de los valores "inusuales" de f2f2_3:f1f1_2 interacción, donde hay valores muy diferentes, e investigar la distribución marginal de estas dos submuestras aleatorias. Por ejemplo, en algunos casos, f2f2_3:f1f1_2 está muy por debajo de $1$ mientras que el modelo estimado sugiere unos valores cercanos a $2.4$ . ¿Son similares las distribuciones marginales? ¿Existe un caso de solapamiento insuficiente? Tal vez el bootstrap "simple" sea inadecuado y tengamos que estratificar la muestra en cuestión con respecto a algunos de los factores.

0 votos

Gracias por tu aportación, los datos estaban disponibles y listos para cargar en los enlaces proporcionados. El código y los datos deberían seguir siendo reproducibles.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X