Cómo Hacer un Forest Plot en R con metafor (Paso a Paso)

Saber leer e interpretar un forest plot es una cosa; construir el tuyo y que salga con calidad de publicación es otra. En este tutorial vas a hacer un forest plot completo en R con el paquete metafor (la referencia para metaanálisis en R) desde unos datos brutos de medias y desviaciones típicas hasta un gráfico listo para enviar a una revista Q1. Todo el código es reproducible: cópialo, cámbialo por tus datos y funciona.

Qué necesitas antes de empezar

Un forest plot resume un metaanálisis, así que necesitas datos de varios estudios sobre la misma pregunta. Hay dos escenarios habituales:

  • Tienes los datos brutos: para cada estudio, las medias, desviaciones típicas y tamaños muestrales de los dos grupos (tratamiento y control). A partir de ahí calcularás el tamaño del efecto.
  • Tienes los efectos ya calculados: para cada estudio, el tamaño del efecto (por ejemplo, una d de Cohen o un odds ratio) y su varianza o error estándar. Esto suele venir de tablas de artículos previos.

En ambos casos, el flujo en metafor es el mismo: (1) obtener el efecto y su varianza con escalc(), (2) ajustar el modelo con rma() y (3) dibujar con forest(). Vamos paso a paso.

Paso 1: Instalar y cargar metafor

# Solo la primera vez
install.packages("metafor")

library(metafor)

El paquete metafor (Viechtbauer, 2010) es, con diferencia, el más usado para metaanálisis en R y el que esperan ver los revisores. Está activamente mantenido y cubre desde el metaanálisis básico hasta metarregresión, modelos multinivel y modelos de efectos robustos.

Paso 2: Preparar los datos y calcular el tamaño del efecto

Supongamos que tienes seis estudios que comparan una intervención psicológica frente a un grupo control sobre una medida de ansiedad. Montamos el data frame y calculamos el tamaño del efecto con escalc():

misdatos <- data.frame(
  estudio = c("García 2019", "López 2020", "Martínez 2021",
              "Chen 2021", "Fernández 2022", "Sánchez 2023"),
  m_trat  = c(22.1, 19.8, 24.5, 21.0, 26.2, 20.4),
  sd_trat = c(5.2, 4.8, 6.1, 5.5, 5.9, 4.6),
  n_trat  = c(40, 65, 32, 58, 45, 70),
  m_ctrl  = c(24.8, 21.5, 27.0, 22.3, 29.1, 22.0),
  sd_ctrl = c(5.4, 5.0, 6.3, 5.2, 6.0, 4.9),
  n_ctrl  = c(38, 63, 30, 55, 44, 68)
)

# Diferencia de medias estandarizada (g de Hedges, corregida por muestra pequeña)
dat <- escalc(measure = "SMD",
              m1i = m_trat, sd1i = sd_trat, n1i = n_trat,
              m2i = m_ctrl, sd2i = sd_ctrl, n2i = n_ctrl,
              data = misdatos, slab = estudio)

Tras esto, dat tiene dos columnas nuevas: yi (el tamaño del efecto, en este caso la g de Hedges) y vi (su varianza muestral). El argumento measure = "SMD" devuelve la g de Hedges, que aplica la corrección por sesgo de muestra pequeña sobre la d de Cohen, el estándar en psicología. Si trabajas con datos dicotómicos, usa measure = "OR" (odds ratio) o "RR" (riesgo relativo) con los argumentos de frecuencias (ai, bi, ci, di); y si ya tienes los efectos calculados, salta este paso y pasa directamente tus columnas yi y vi al modelo.

El argumento slab (de study label) define las etiquetas de cada estudio que aparecerán a la izquierda del gráfico. Defínelo aquí y no tendrás que repetirlo después.

Paso 3: Ajustar el modelo de efectos aleatorios

res <- rma(yi, vi, data = dat, method = "REML")
res

La función rma() ajusta un modelo de efectos aleatorios por defecto (estimador REML), que es el estándar en psicología y ciencias de la salud: asume que cada estudio estima un efecto verdadero distinto extraído de una distribución, e incorpora la varianza entre estudios (τ²) al cálculo. Si por algún motivo justificado necesitas efectos fijos, usa method = "FE", pero salvo excepciones muy concretas, mantén REML.

Al imprimir res obtienes el efecto combinado, su intervalo de confianza, y los indicadores de heterogeneidad: , τ² y el test Q. Conviene que entiendas qué significan antes de dibujar nada; si el es alto, el rombo del forest plot será un promedio poco representativo. La guía sobre heterogeneidad en metaanálisis (I²) explica cómo interpretarlos y cuándo el efecto combinado deja de ser informativo.

Paso 4: Dibujar el forest plot básico

Con el modelo ajustado, una sola línea genera el gráfico:

forest(res)

Esto ya produce un forest plot funcional: una fila por estudio con su cuadrado proporcional al peso y su intervalo de confianza, el rombo del efecto combinado al pie y el eje con la escala del efecto. Pero para publicación conviene afinarlo.

Estudio g [IC 95%] García 2019 −0.50 [−0.95, −0.05] López 2020 −0.34 [−0.69, 0.01] Martínez 2021 −0.41 [−0.91, 0.09] Chen 2021 −0.24 [−0.61, 0.13] Fernández 2022 −0.48 [−0.96, 0.00] Sánchez 2023 −0.29 [−0.66, 0.08] RE Model −0.36 [−0.51, −0.21] −1.0 0 1.0 g de Hedges ← Favorece tratamiento Favorece control →
Salida aproximada de forest(res) con etiquetas y columna de efectos: seis estudios y el rombo del modelo de efectos aleatorios (RE Model).

Paso 5: Personalizar para calidad de publicación

Estos argumentos cubren el 95% de lo que necesitas para que el gráfico quede como en un artículo Q1:

forest(res,
       header = c("Estudio", "g [IC 95%]"),  # cabeceras de columnas
       xlab   = "g de Hedges",                # etiqueta del eje
       mlab   = "Modelo de efectos aleatorios (REML)",  # etiqueta del rombo
       slab   = dat$estudio,                  # etiquetas de estudio
       order  = "obs",                        # ordenar por tamaño del efecto
       cex    = 0.9)                           # tamaño de fuente

Algunos argumentos útiles adicionales: xlim y alim controlan los límites del área de dibujo y del eje; at fija las marcas del eje (por ejemplo at = c(-1, -0.5, 0, 0.5)); refline mueve la línea de nulidad (por defecto 0 para diferencias, conviene refline = 1 si trabajas con odds ratios); y ilab permite añadir columnas extra como los tamaños muestrales. Para odds ratios o riesgos relativos, añade atransf = exp para que el eje muestre la escala original en lugar de la logarítmica.

Paso 6: Añadir los estadísticos de heterogeneidad al gráfico

Un forest plot publicable muestra , Q y τ², normalmente bajo el rombo. Puedes incluirlos automáticamente con bquote y mlab:

forest(res, header = TRUE, xlab = "g de Hedges",
       mlab = bquote(paste("RE Model (Q = ",
              .(formatC(res$QE, digits = 2, format = "f")),
              ", df = ", .(res$k - res$p),
              ", p = ", .(formatC(res$QEp, digits = 3, format = "f")),
              "; ", I^2, " = ", .(formatC(res$I2, digits = 1, format = "f")), "%)")))

Así el lector ve de un vistazo si la heterogeneidad invalida la lectura del rombo, sin tener que buscarla en el texto.

Forest plot con subgrupos

Si una variable moderadora (por ejemplo, el formato de la intervención: presencial vs. online) puede explicar la heterogeneidad, conviene un forest plot con subgrupos. La forma más limpia es ajustar el modelo con el moderador y dibujar los estudios agrupados, añadiendo un rombo parcial por subgrupo con addpoly():

# Modelo con moderador categórico
res.mod <- rma(yi, vi, mods = ~ formato, data = dat)

# Submodelos por nivel
res.pres <- rma(yi, vi, data = dat, subset = (formato == "presencial"))
res.onl  <- rma(yi, vi, data = dat, subset = (formato == "online"))

# Dibujar ordenando por subgrupo y añadir rombos parciales
forest(res, order = order(dat$formato), addfit = FALSE,
       header = TRUE, xlab = "g de Hedges")
addpoly(res.pres, row = 1, mlab = "Subtotal: presencial")
addpoly(res.onl,  row = 5, mlab = "Subtotal: online")

Ajusta los valores de row al número de estudios de cada subgrupo. El test de diferencias entre subgrupos (Qbetween) lo obtienes del res.mod: si es significativo, el moderador explica parte de la variación entre estudios.

Exportar el gráfico a calidad de publicación

Las revistas piden imágenes a 300 dpi o más, y muchas exigen formato vectorial (PDF, EPS, TIFF). Abre un dispositivo gráfico, dibuja y ciérralo:

# PNG a 300 dpi
png("forest_plot.png", width = 8, height = 6, units = "in", res = 300)
forest(res, header = TRUE, xlab = "g de Hedges")
dev.off()

# PDF vectorial (recomendado por muchas revistas)
pdf("forest_plot.pdf", width = 8, height = 6)
forest(res, header = TRUE, xlab = "g de Hedges")
dev.off()

El formato vectorial (PDF/EPS) no pierde calidad al ampliar y suele ser la opción preferida del editor de producción. Ajusta width y height hasta que las etiquetas no se solapen.

Cuatro errores frecuentes al crear el forest plot

1. Pasar la desviación típica en lugar de la varianza a vi. El segundo argumento de rma() es la varianza muestral del efecto, no el error estándar ni la desviación típica. Si pasas el error estándar, usa sei en su lugar (rma(yi, sei = mi_se, ...)). Confundirlos infla o reduce artificialmente la precisión y deforma los pesos.

2. Saltarse escalc() y meter medias brutas. Un forest plot necesita efectos en una escala común. Si comparas estudios con medias en escalas distintas sin estandarizar, el gráfico no tiene sentido. escalc() hace esa conversión y, además, corrige el sesgo de muestra pequeña en la g de Hedges.

3. Olvidar el signo del efecto. Decide desde el principio qué dirección es «mejora» y comprueba que todos los estudios estén codificados igual. Un estudio con la resta invertida (control − tratamiento en vez de tratamiento − control) aparecerá en el lado equivocado y sesgará el efecto combinado.

4. Usar efectos fijos sin justificarlo. Aunque rma() usa efectos aleatorios por defecto, a veces se copia código ajeno con method = "FE". Salvo que tengas un argumento sólido (muy pocos estudios funcionalmente idénticos), mantén efectos aleatorios: es lo que esperan los revisores en psicología y salud.

Alternativa: el paquete meta

Si prefieres una sintaxis algo más directa, el paquete meta también genera forest plots publicables. metacont() para datos continuos o metabin() para datos binarios calculan el efecto y el modelo en una sola función, y forest() dibuja el gráfico con un estilo ligeramente distinto. Tanto metafor como meta son opciones válidas y aceptadas en revistas indexadas; metafor ofrece más control y flexibilidad para análisis avanzados (multinivel, metarregresión, modelos robustos), por lo que es la que recomiendo si vas a crecer en complejidad.

Y cuando el gráfico esté listo

Crear el forest plot es el penúltimo paso. Antes de cerrar el análisis, comprueba el sesgo de publicación con un funnel plot y el test de Egger, y asegúrate de saber interpretar cada elemento del forest plot antes de redactar la discusión. Para la redacción final, la guía de cómo reportar resultados en APA 7 cubre el formato que esperan las revistas.

¿Quieres un metaanálisis completo, con forest plots a prueba de revisores?

Soy doctor en psicología y ejecuto metaanálisis de principio a fin en R: búsqueda sistemática, codificación, modelo de efectos aleatorios, forest plots, heterogeneidad y sesgo de publicación, con la redacción APA 7 lista para enviar.

Pídeme un diagnóstico gratis →

Sigue leyendo

Todos los articulos del blog