1 0. Training purpose

This practical follows the order of the Stata binary-outcome workflow, but uses simpler R code for trainees.

Question: Does hyaluronidase reduce the risk of binary outcomes such as perineal trauma or episiotomy?

Outcome type: binary outcome: each study reports events and totals in two groups.

Effect measure: risk ratio (RR). For undesirable outcomes, RR < 1 favours hyaluronidase.

Important correction: the Stata forest-plot label says “OR” in one place, but the calculation is a risk ratio. The correct label is RR (95% CI).

2 1. Setup

packages <- c("readxl", "dplyr", "meta", "knitr")

missing <- packages[!sapply(packages, requireNamespace, quietly = TRUE)]
if (length(missing) > 0) install.packages(missing)

library(readxl)
library(dplyr)
library(meta)
library(knitr)

options(width = 110)
set.seed(2026)

fmt_num <- function(x, digits = 3) formatC(x, digits = digits, format = "f")
fmt_pct <- function(x, digits = 1) paste0(formatC(100 * x, digits = digits, format = "f"), "%")
fmt_p <- function(p) ifelse(p < 0.001, "<0.001", formatC(p, digits = 3, format = "f"))

# Simple Galbraith/radial plot with centre line and ±2 reference limits.
# The y-axis is the standardised effect: effect / standard error.
# The x-axis is study precision: 1 / standard error.
galbraith_plot <- function(m, main = "Galbraith/radial plot") {
  effect <- m$TE
  se <- m$seTE
  ok <- is.finite(effect) & is.finite(se) & se > 0
  effect <- effect[ok]
  se <- se[ok]
  labels <- m$studlab[ok]
  pooled <- m$TE.random
  
  x <- 1 / se
  y <- effect / se
  
  plot(x, y,
       pch = 19,
       xlab = "Inverse of standard error (precision)",
       ylab = "Standardised effect (z-score)",
       main = main)
  abline(a = 0,  b = pooled, lwd = 2)      # pooled-effect line
  abline(a = 2,  b = pooled, lty = 2)      # upper approximate 95% limit
  abline(a = -2, b = pooled, lty = 2)      # lower approximate 95% limit
  abline(h = 0, col = "grey80")
  legend("topleft",
         legend = c("Pooled-effect line", "Approx. ±2 limits"),
         lty = c(1, 2), lwd = c(2, 1), bty = "n", cex = 0.8)
}

# Small helper to extract key random-effects results from a meta object.
summary_row_rr <- function(m, analysis_name) {
  data.frame(
    Analysis = analysis_name,
    Studies = m$k,
    RR = exp(m$TE.random),
    Lower_95_CI = exp(m$lower.random),
    Upper_95_CI = exp(m$upper.random),
    Tau2 = m$tau2,
    I2_percent = 100 * m$I2,
    Q_p_value = m$pval.Q
  )
}

3 2. Read the Excel dataset

Equivalent Stata idea:

clear
import excel "...Hyaluronidase_MetaAnalysis_Dataset_statafinal1.xlsx", sheet("Calculated Stats_All") firstrow cellrange(A5:P45)
possible_files <- c(
  "Hyaluronidase_MetaAnalysis_Dataset_statafinal1_1.xlsx",
  "Hyaluronidase_MetaAnalysis_Dataset_statafinal1.xlsx"
)

data_file <- possible_files[file.exists(possible_files)][1]
if (is.na(data_file)) stop("Put the Hyaluronidase Excel file in the same folder as this Rmd.")

sheet_names <- excel_sheets(data_file)
sheet_to_use <- if ("Calculated Stats_All" %in% sheet_names) "Calculated Stats_All" else sheet_names[1]

perineal <- read_excel(data_file, sheet = sheet_to_use, range = "A5:P45", col_names = TRUE)

names(perineal) <- c(
  "Study", "ROBOverall", "aHAaseevents", "n1HAasetotal",
  "cControlevents", "n2Controltotal", "RiskHAase", "RiskControl",
  "RR", "lnRR", "SElnRR", "CILower", "CIUpper",
  "Outcome", "TypeofStudy", "RCT_design"
)

perineal <- perineal %>%
  mutate(
    Study = trimws(Study),
    Outcome = trimws(Outcome),
    RCT_design = trimws(RCT_design),
    ROBOverall = trimws(ROBOverall),
    aHAaseevents = as.numeric(aHAaseevents),
    n1HAasetotal = as.numeric(n1HAasetotal),
    cControlevents = as.numeric(cControlevents),
    n2Controltotal = as.numeric(n2Controltotal)
  )

perineal %>%
  select(Study, Outcome, RCT_design, aHAaseevents, n1HAasetotal,
         cControlevents, n2Controltotal, ROBOverall) %>%
  head(12) %>%
  kable(caption = "First 12 rows of the binary-outcome dataset")
First 12 rows of the binary-outcome dataset
Study Outcome RCT_design aHAaseevents n1HAasetotal cControlevents n2Controltotal ROBOverall
Chatfield 1966* Perineal_Trauma Placebo 58 67 62 67 High
Colacioppo 2011* Perineal_Trauma Placebo 86 115 89 113 Low
Kwon 2020* Perineal_Trauma Placebo 61 88 68 86 Low
Martinez 2019 (sim) Perineal_Trauma Placebo 70 95 74 93 Low
Chen 2020 (sim) Perineal_Trauma Placebo 82 110 86 108 Some Concerns
Kumar 2021 (sim) Perineal_Trauma Placebo 55 80 59 78 High
Johansson 2018 (sim) Perineal_Trauma Placebo 48 70 52 68 Some Concerns
Patel 2022 (sim) Perineal_Trauma Placebo 66 92 71 90 Low
Nguyen 2021 (sim) Perineal_Trauma Placebo 44 65 48 63 High
Osei 2020 (sim) Perineal_Trauma Placebo 35 55 38 53 High
Chatfield 1966* Episiotomy Placebo 22 67 28 67 High
Colacioppo 2011* Episiotomy Placebo 41 115 47 113 Low

4 3. Manual risk ratio calculation

This section helps trainees understand what the software is pooling.

Equivalent Stata idea:

gen riskratio = (aHAaseevents * n2Controltotal) / (n1HAasetotal * cControlevents)
gen logriskratio = ln(riskratio)
gen se_logrr_manual = sqrt((1/aHAaseevents) - (1/n1HAasetotal) + (1/cControlevents) - (1/n2Controltotal))
perineal <- perineal %>%
  mutate(
    riskratio = (aHAaseevents / n1HAasetotal) / (cControlevents / n2Controltotal),
    logriskratio = log(riskratio),
    se_logrr_manual = sqrt(
      (1 / aHAaseevents) - (1 / n1HAasetotal) +
        (1 / cControlevents) - (1 / n2Controltotal)
    )
  )

perineal %>%
  select(Study, Outcome, RCT_design, riskratio, logriskratio, se_logrr_manual) %>%
  mutate(
    riskratio = round(riskratio, 3),
    logriskratio = round(logriskratio, 3),
    se_logrr_manual = round(se_logrr_manual, 3)
  ) %>%
  head(10) %>%
  kable(caption = "Manual RR, log(RR), and SE[log(RR)]")
Manual RR, log(RR), and SE[log(RR)]
Study Outcome RCT_design riskratio logriskratio se_logrr_manual
Chatfield 1966* Perineal_Trauma Placebo 0.935 -0.067 0.059
Colacioppo 2011* Perineal_Trauma Placebo 0.949 -0.052 0.073
Kwon 2020* Perineal_Trauma Placebo 0.877 -0.132 0.090
Martinez 2019 (sim) Perineal_Trauma Placebo 0.926 -0.077 0.081
Chen 2020 (sim) Perineal_Trauma Placebo 0.936 -0.066 0.074
Kumar 2021 (sim) Perineal_Trauma Placebo 0.909 -0.096 0.099
Johansson 2018 (sim) Perineal_Trauma Placebo 0.897 -0.109 0.105
Patel 2022 (sim) Perineal_Trauma Placebo 0.909 -0.095 0.085
Nguyen 2021 (sim) Perineal_Trauma Placebo 0.888 -0.118 0.111
Osei 2020 (sim) Perineal_Trauma Placebo 0.888 -0.119 0.134

5 4. Main analysis: HAase versus placebo

For binary event data, the simplest R function is metabin().

placebo_data <- perineal %>% filter(RCT_design == "Placebo")
placebo_models <- list()

for (outcome_name in unique(placebo_data$Outcome)) {
  cat("\n\n### Forest plot:", outcome_name, "— HAase vs placebo\n\n")
  
  dat <- placebo_data %>% filter(Outcome == outcome_name)
  
  m <- metabin(
    event.e = aHAaseevents,
    n.e     = n1HAasetotal,
    event.c = cControlevents,
    n.c     = n2Controltotal,
    studlab = Study,
    data    = dat,
    sm      = "RR",
    method  = "MH",
    common  = FALSE,
    random  = TRUE,
    method.tau = "REML",
    method.random.ci = "HK"
  )
  
  placebo_models[[outcome_name]] <- m
  print(summary(m))
  
  forest(
    m,
    prediction = TRUE,
    print.tau2 = TRUE,
    print.I2 = TRUE,
    leftcols = c("studlab", "event.e", "n.e", "event.c", "n.c"),
    leftlabs = c("Study", "HAase events", "HAase total", "Control events", "Control total"),
    rightcols = c("effect", "ci", "w.random"),
    rightlabs = c("RR", "95% CI", "Weight"),
    xlab = "Risk Ratio (RR)",
    smlab = "HAase vs placebo"
  )
}

5.1 Forest plot: Perineal_Trauma — HAase vs placebo

                     RR           95%-CI %W(random)

Chatfield 1966* 0.9355 [0.8328; 1.0508] 20.3 Colacioppo 2011* 0.9495 [0.8230; 1.0954] 13.4 Kwon 2020* 0.8767 [0.7348; 1.0459] 8.8 Martinez 2019 (sim) 0.9260 [0.7905; 1.0848] 11.0 Chen 2020 (sim) 0.9362 [0.8098; 1.0822] 13.1 Kumar 2021 (sim) 0.9089 [0.7485; 1.1036] 7.3 Johansson 2018 (sim) 0.8967 [0.7296; 1.1021] 6.5 Patel 2022 (sim) 0.9094 [0.7695; 1.0746] 9.9 Nguyen 2021 (sim) 0.8885 [0.7149; 1.1042] 5.8 Osei 2020 (sim) 0.8876 [0.6831; 1.1531] 4.0

Number of studies: k = 10 Number of observations: o = 1656 (o.e = 837, o.c = 819) Number of events: e = 1252

                     RR           95%-CI      t  p-value

Random effects model 0.9193 [0.9021; 0.9368] -10.08 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0; tau = 0; I^2 = 0.0% [0.0%; 62.4%]; H = 1.00 [1.00; 1.63]

Test of heterogeneity: Q d.f. p-value 0.88 9 0.9997

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 9)

5.2 Forest plot: Episiotomy — HAase vs placebo

                     RR           95%-CI %W(random)

Chatfield 1966* 0.7857 [0.5040; 1.2249] 8.8 Colacioppo 2011* 0.8572 [0.6171; 1.1907] 16.1 Kwon 2020* 0.7996 [0.5292; 1.2082] 10.2 Martinez 2019 (sim) 0.8702 [0.5946; 1.2735] 12.0 Chen 2020 (sim) 0.8677 [0.6137; 1.2267] 14.5 Kumar 2021 (sim) 0.8357 [0.5344; 1.3070] 8.7 Johansson 2018 (sim) 0.7771 [0.4789; 1.2611] 7.4 Patel 2022 (sim) 0.8106 [0.5448; 1.2059] 11.0 Nguyen 2021 (sim) 0.7930 [0.4726; 1.3307] 6.5 Osei 2020 (sim) 0.7495 [0.4164; 1.3491] 5.0

Number of studies: k = 10 Number of observations: o = 1656 (o.e = 837, o.c = 819) Number of events: e = 580

                     RR           95%-CI      t  p-value

Random effects model 0.8248 [0.7966; 0.8539] -12.53 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0; tau = 0; I^2 = 0.0% [0.0%; 62.4%]; H = 1.00 [1.00; 1.63]

Test of heterogeneity: Q d.f. p-value 0.47 9 1.0000

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 9)

6 5. Summary table and interpretation

placebo_summary <- do.call(rbind, lapply(names(placebo_models), function(nm) {
  summary_row_rr(placebo_models[[nm]], nm)
}))

placebo_summary %>%
  mutate(
    RR = fmt_num(RR),
    Lower_95_CI = fmt_num(Lower_95_CI),
    Upper_95_CI = fmt_num(Upper_95_CI),
    Tau2 = fmt_num(Tau2, 4),
    I2_percent = fmt_num(I2_percent, 1),
    Q_p_value = fmt_p(Q_p_value)
  ) %>%
  kable(caption = "Random-effects RR summary for HAase versus placebo")
Random-effects RR summary for HAase versus placebo
Analysis Studies RR Lower_95_CI Upper_95_CI Tau2 I2_percent Q_p_value
Perineal_Trauma 10 0.919 0.902 0.937 0.0000 0.0 1.000
Episiotomy 10 0.825 0.797 0.854 0.0000 0.0 1.000
for (nm in names(placebo_models)) {
  m <- placebo_models[[nm]]
  rr <- exp(m$TE.random)
  lcl <- exp(m$lower.random)
  ucl <- exp(m$upper.random)
  cat("\n\n**", nm, ":** The pooled RR is ", fmt_num(rr),
      " (95% CI ", fmt_num(lcl), " to ", fmt_num(ucl), "). ",
      "Because the outcome is undesirable, RR < 1 favours hyaluronidase. ",
      "I² = ", fmt_num(100 * m$I2, 1), "%, tau² = ", fmt_num(m$tau2, 4),
      ", Q-test p = ", fmt_p(m$pval.Q), ".", sep = "")
}

Perineal_Trauma: The pooled RR is 0.919 (95% CI 0.902 to 0.937). Because the outcome is undesirable, RR < 1 favours hyaluronidase. I² = 0.0%, tau² = 0.0000, Q-test p = 1.000.

Episiotomy: The pooled RR is 0.825 (95% CI 0.797 to 0.854). Because the outcome is undesirable, RR < 1 favours hyaluronidase. I² = 0.0%, tau² = 0.0000, Q-test p = 1.000.

7 6. Sensitivity analysis: different tau-squared estimators

Equivalent Stata idea: compare REML, DerSimonian-Laird (DL), and Sidik-Jonkman (SJ).

tau_methods <- c("REML", "DL", "SJ")
tau_results <- list()

for (outcome_name in unique(placebo_data$Outcome)) {
  dat <- placebo_data %>% filter(Outcome == outcome_name)
  
  for (tm in tau_methods) {
    m <- metabin(
      event.e = aHAaseevents, n.e = n1HAasetotal,
      event.c = cControlevents, n.c = n2Controltotal,
      studlab = Study, data = dat,
      sm = "RR", method = "MH",
      common = FALSE, random = TRUE,
      method.tau = tm,
      method.random.ci = "HK"
    )
    tau_results[[paste(outcome_name, tm, sep = " - ")]] <- summary_row_rr(m, paste(outcome_name, tm, sep = " - "))
  }
}

do.call(rbind, tau_results) %>%
  mutate(
    RR = fmt_num(RR),
    Lower_95_CI = fmt_num(Lower_95_CI),
    Upper_95_CI = fmt_num(Upper_95_CI),
    Tau2 = fmt_num(Tau2, 4),
    I2_percent = fmt_num(I2_percent, 1),
    Q_p_value = fmt_p(Q_p_value)
  ) %>%
  kable(caption = "Sensitivity of pooled RR to tau-squared estimator")
Sensitivity of pooled RR to tau-squared estimator
Analysis Studies RR Lower_95_CI Upper_95_CI Tau2 I2_percent Q_p_value
Perineal_Trauma - REML Perineal_Trauma - REML 10 0.919 0.902 0.937 0.0000 0.0 1.000
Perineal_Trauma - DL Perineal_Trauma - DL 10 0.919 0.902 0.937 0.0000 0.0 1.000
Perineal_Trauma - SJ Perineal_Trauma - SJ 10 0.919 0.902 0.937 0.0001 0.0 1.000
Episiotomy - REML Episiotomy - REML 10 0.825 0.797 0.854 0.0000 0.0 1.000
Episiotomy - DL Episiotomy - DL 10 0.825 0.797 0.854 0.0000 0.0 1.000
Episiotomy - SJ Episiotomy - SJ 10 0.825 0.797 0.854 0.0001 0.0 1.000

Teaching point: if the pooled RR and conclusion are similar across REML, DL, and SJ, the result is less dependent on the heterogeneity estimator.

8 7. Leave-one-out analysis

Equivalent Stata idea:

meta summarize ..., leaveoneout random(reml) se(khartung)
for (nm in names(placebo_models)) {
  cat("\n\n### Leave-one-out:", nm, "\n\n")
  loo <- metainf(placebo_models[[nm]], pooled = "random")
  print(summary(loo))
  forest(loo, xlab = "Risk Ratio (RR)")
}

8.1 Leave-one-out: Perineal_Trauma

Leave-one-out meta-analysis

                              RR           95%-CI  p-value tau^2 tau I^2

Omitting Chatfield 1966* 0.9152 [0.8958; 0.9350] < 0.0001 0 0 0% Omitting Colacioppo 2011* 0.9147 [0.8975; 0.9321] < 0.0001 0 0 0% Omitting Kwon 2020* 0.9235 [0.9077; 0.9396] < 0.0001 0 0 0% Omitting Martinez 2019 (sim) 0.9185 [0.8989; 0.9384] < 0.0001 0 0 0% Omitting Chen 2020 (sim) 0.9168 [0.8977; 0.9363] < 0.0001 0 0 0% Omitting Kumar 2021 (sim) 0.9201 [0.9009; 0.9397] < 0.0001 0 0 0% Omitting Johansson 2018 (sim) 0.9209 [0.9023; 0.9398] < 0.0001 0 0 0% Omitting Patel 2022 (sim) 0.9204 [0.9010; 0.9402] < 0.0001 0 0 0% Omitting Nguyen 2021 (sim) 0.9212 [0.9031; 0.9396] < 0.0001 0 0 0% Omitting Osei 2020 (sim) 0.9206 [0.9024; 0.9392] < 0.0001 0 0 0%

Random effects model 0.9193 [0.9021; 0.9368] < 0.0001 0 0 0%

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = {8, 9})

8.2 Leave-one-out: Episiotomy

Leave-one-out meta-analysis

                              RR           95%-CI  p-value tau^2 tau I^2

Omitting Chatfield 1966* 0.8286 [0.7983; 0.8600] < 0.0001 0 0 0% Omitting Colacioppo 2011* 0.8187 [0.7880; 0.8506] < 0.0001 0 0 0% Omitting Kwon 2020* 0.8277 [0.7963; 0.8603] < 0.0001 0 0 0% Omitting Martinez 2019 (sim) 0.8188 [0.7896; 0.8490] < 0.0001 0 0 0% Omitting Chen 2020 (sim) 0.8177 [0.7886; 0.8479] < 0.0001 0 0 0% Omitting Kumar 2021 (sim) 0.8237 [0.7921; 0.8567] < 0.0001 0 0 0% Omitting Johansson 2018 (sim) 0.8287 [0.7991; 0.8594] < 0.0001 0 0 0% Omitting Patel 2022 (sim) 0.8265 [0.7945; 0.8598] < 0.0001 0 0 0% Omitting Nguyen 2021 (sim) 0.8270 [0.7962; 0.8589] < 0.0001 0 0 0% Omitting Osei 2020 (sim) 0.8289 [0.8013; 0.8575] < 0.0001 0 0 0%

Random effects model 0.8248 [0.7966; 0.8539] < 0.0001 0 0 0%

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = {8, 9})

Interpretation guide: if omitting any one study does not materially change the pooled RR or its direction, the result is not driven by a single study.

9 8. Galbraith/radial plot

Equivalent Stata idea:

meta galbraithplot ..., random(reml)

The plot below adds the pooled-effect line plus the upper and lower approximate ±2 reference limits. Studies outside these limits may be statistical outliers.

for (nm in names(placebo_models)) {
  cat("\n\n### Galbraith/radial plot:", nm, "\n\n")
  galbraith_plot(placebo_models[[nm]], main = paste("Galbraith plot:", nm))
}

9.1 Galbraith/radial plot: Perineal_Trauma

9.2 Galbraith/radial plot: Episiotomy

10 9. Funnel plot

Equivalent Stata idea:

meta funnel ..., random(reml)
for (nm in names(placebo_models)) {
  cat("\n\n### Funnel plot:", nm, "\n\n")
  funnel(placebo_models[[nm]], xlab = "log(RR)")
}

10.1 Funnel plot: Perineal_Trauma

10.2 Funnel plot: Episiotomy

11 10. Egger’s test for small-study effects

Equivalent Stata idea:

meta bias ..., egger
for (nm in names(placebo_models)) {
  cat("\n\n### Egger test:", nm, "\n\n")
  print(metabias(placebo_models[[nm]], method.bias = "linreg", k.min = 3))
}

11.1 Egger test: Perineal_Trauma

Linear regression test of funnel plot asymmetry

Test result: t = -3.45, df = 8, p-value = 0.0087 Bias estimate: -1.0487 (SE = 0.3039)

Details: - multiplicative residual heterogeneity variance (tau^2 = 0.0441) - predictor: standard error - weight: inverse variance - reference: Egger et al. (1997), BMJ

11.2 Egger test: Episiotomy

Linear regression test of funnel plot asymmetry

Test result: t = -4.56, df = 8, p-value = 0.0018 Bias estimate: -1.1171 (SE = 0.2447)

Details: - multiplicative residual heterogeneity variance (tau^2 = 0.0163) - predictor: standard error - weight: inverse variance - reference: Egger et al. (1997), BMJ

Teaching caution: Egger’s test has low power with few studies and should not be interpreted as proof of publication bias.

12 11. Trim-and-fill sensitivity analysis

Equivalent Stata idea:

meta trimfill ..., random(reml)
for (nm in names(placebo_models)) {
  cat("\n\n### Trim-and-fill:", nm, "\n\n")
  tf <- trimfill(placebo_models[[nm]])
  print(summary(tf))
  funnel(tf, xlab = "log(RR)")
}

12.1 Trim-and-fill: Perineal_Trauma

                          RR           95%-CI %W(random)

Chatfield 1966* 0.9355 [0.8328; 1.0508] 17.1 Colacioppo 2011* 0.9495 [0.8230; 1.0954] 11.3 Kwon 2020* 0.8767 [0.7348; 1.0459] 7.4 Martinez 2019 (sim) 0.9260 [0.7905; 1.0848] 9.2 Chen 2020 (sim) 0.9362 [0.8098; 1.0822] 11.0 Kumar 2021 (sim) 0.9089 [0.7485; 1.1036] 6.1 Johansson 2018 (sim) 0.8967 [0.7296; 1.1021] 5.4 Patel 2022 (sim) 0.9094 [0.7695; 1.0746] 8.3 Nguyen 2021 (sim) 0.8885 [0.7149; 1.1042] 4.9 Osei 2020 (sim) 0.8876 [0.6831; 1.1531] 3.4 Filled: Nguyen 2021 (sim) 0.9690 [0.7797; 1.2044] 4.9 Filled: Osei 2020 (sim) 0.9700 [0.7466; 1.2603] 3.4 Filled: Kwon 2020* 0.9821 [0.8232; 1.1716] 7.4

Number of studies: k = 13 (with 3 added studies) Number of observations: o = 2066 (o.e = 1045, o.c = 1021) Number of events: e = 1546

                     RR           95%-CI     t  p-value

Random effects model 0.9279 [0.9096; 0.9465] -8.20 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0; tau = 0; I^2 = 0.0% [0.0%; 56.6%]; H = 1.00 [1.00; 1.52]

Test of heterogeneity: Q d.f. p-value 1.66 12 0.9998

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 12) - Trim-and-fill method to adjust for funnel plot asymmetry (L-estimator)

12.2 Trim-and-fill: Episiotomy

                             RR           95%-CI %W(random)

Chatfield 1966* 0.7857 [0.5040; 1.2249] 6.9 Colacioppo 2011* 0.8572 [0.6171; 1.1907] 12.6 Kwon 2020* 0.7996 [0.5292; 1.2082] 8.0 Martinez 2019 (sim) 0.8702 [0.5946; 1.2735] 9.4 Chen 2020 (sim) 0.8677 [0.6137; 1.2267] 11.3 Kumar 2021 (sim) 0.8357 [0.5344; 1.3070] 6.8 Johansson 2018 (sim) 0.7771 [0.4789; 1.2611] 5.8 Patel 2022 (sim) 0.8106 [0.5448; 1.2059] 8.6 Nguyen 2021 (sim) 0.7930 [0.4726; 1.3307] 5.1 Osei 2020 (sim) 0.7495 [0.4164; 1.3491] 3.9 Filled: Nguyen 2021 (sim) 0.8966 [0.5343; 1.5046] 5.1 Filled: Chatfield 1966* 0.9049 [0.5805; 1.4107] 6.9 Filled: Johansson 2018 (sim) 0.9149 [0.5638; 1.4847] 5.8 Filled: Osei 2020 (sim) 0.9487 [0.5270; 1.7076] 3.9

Number of studies: k = 14 (with 4 added studies) Number of observations: o = 2164 (o.e = 1094, o.c = 1070) Number of events: e = 747

                     RR           95%-CI      t  p-value

Random effects model 0.8432 [0.8138; 0.8737] -10.37 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0; tau = 0; I^2 = 0.0% [0.0%; 55.0%]; H = 1.00 [1.00; 1.49]

Test of heterogeneity: Q d.f. p-value 0.99 13 1.0000

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 13) - Trim-and-fill method to adjust for funnel plot asymmetry (L-estimator)

Teaching caution: trim-and-fill is exploratory. Report it as a sensitivity analysis, not as a definitive correction for publication bias.

13 12. Subgroup analysis by comparison design

Equivalent Stata idea: compare placebo-controlled and no-intervention studies.

for (outcome_name in unique(perineal$Outcome)) {
  cat("\n\n### Subgroup analysis by RCT design:", outcome_name, "\n\n")
  
  dat <- perineal %>% filter(Outcome == outcome_name)
  
  m_sub <- metabin(
    event.e = aHAaseevents,
    n.e     = n1HAasetotal,
    event.c = cControlevents,
    n.c     = n2Controltotal,
    studlab = Study,
    data    = dat,
    sm      = "RR",
    method  = "MH",
    common  = FALSE,
    random  = TRUE,
    method.tau = "REML",
    method.random.ci = "HK",
    subgroup = RCT_design
  )
  
  print(summary(m_sub))
  forest(
    m_sub,
    prediction = TRUE,
    print.tau2 = TRUE,
    print.I2 = TRUE,
    xlab = "Risk Ratio (RR)",
    smlab = "Subgrouped by comparison design"
  )
}

13.1 Subgroup analysis by RCT design: Perineal_Trauma

                     RR           95%-CI %W(random)      RCT_design

Chatfield 1966* 0.9355 [0.8328; 1.0508] 6.4 Placebo Colacioppo 2011* 0.9495 [0.8230; 1.0954] 5.9 Placebo Kwon 2020* 0.8767 [0.7348; 1.0459] 5.3 Placebo Martinez 2019 (sim) 0.9260 [0.7905; 1.0848] 5.7 Placebo Chen 2020 (sim) 0.9362 [0.8098; 1.0822] 5.9 Placebo Kumar 2021 (sim) 0.9089 [0.7485; 1.1036] 5.0 Placebo Johansson 2018 (sim) 0.8967 [0.7296; 1.1021] 4.8 Placebo Patel 2022 (sim) 0.9094 [0.7695; 1.0746] 5.5 Placebo Nguyen 2021 (sim) 0.8885 [0.7149; 1.1042] 4.6 Placebo Osei 2020 (sim) 0.8876 [0.6831; 1.1531] 3.9 Placebo Chatfield 1966* 0.8667 [0.7893; 0.9517] 6.8 No Intervention O’Leary 1965* 0.8571 [0.7547; 0.9735] 6.2 No Intervention Scarabotto 2008* 0.7602 [0.6286; 0.9194] 5.1 No Intervention Fernando 2017 (sim) 0.5993 [0.4596; 0.7816] 3.9 No Intervention Diallo 2019 (sim) 0.6119 [0.4663; 0.8029] 3.8 No Intervention Park 2018 (sim) 0.6314 [0.5036; 0.7917] 4.5 No Intervention Ahmed 2020 (sim) 0.6127 [0.4842; 0.7754] 4.3 No Intervention Rossi 2021 (sim) 0.6327 [0.5101; 0.7849] 4.6 No Intervention Williams 2022 (sim) 0.6243 [0.4933; 0.7902] 4.3 No Intervention Tanaka 2016 (sim) 0.6143 [0.4562; 0.8273] 3.4 No Intervention

Number of studies: k = 20 Number of observations: o = 2858 (o.e = 1448, o.c = 1410) Number of events: e = 2166

                     RR           95%-CI     t  p-value

Random effects model 0.8027 [0.7390; 0.8720] -5.56 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0.0192 [0.0075; 0.0600]; tau = 0.1385 [0.0863; 0.2450] I^2 = 65.6% [44.9%; 78.6%]; H = 1.71 [1.35; 2.16]

Test of heterogeneity: Q d.f. p-value 55.27 19 < 0.0001

Results for subgroups (random effects model): k RR 95%-CI tau^2 tau Q I^2 RCT_design = Placebo 10 0.9193 [0.9021; 0.9368] 0 0 0.88 0.0% RCT_design = No Intervention 10 0.6944 [0.6204; 0.7773] 0.0180 0.1343 29.71 69.7%

Test for subgroup differences (random effects model): Q d.f. p-value Between groups 30.83 1 < 0.0001

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Q-Profile method for confidence interval of tau^2 and tau - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 19) - Continuity correction of 0.5 in studies with zero cell frequencies

13.2 Subgroup analysis by RCT design: Episiotomy

                     RR           95%-CI %W(random)      RCT_design

Chatfield 1966* 0.7857 [0.5040; 1.2249] 5.5 Placebo Colacioppo 2011* 0.8572 [0.6171; 1.1907] 10.1 Placebo Kwon 2020* 0.7996 [0.5292; 1.2082] 6.4 Placebo Martinez 2019 (sim) 0.8702 [0.5946; 1.2735] 7.5 Placebo Chen 2020 (sim) 0.8677 [0.6137; 1.2267] 9.1 Placebo Kumar 2021 (sim) 0.8357 [0.5344; 1.3070] 5.5 Placebo Johansson 2018 (sim) 0.7771 [0.4789; 1.2611] 4.7 Placebo Patel 2022 (sim) 0.8106 [0.5448; 1.2059] 6.9 Placebo Nguyen 2021 (sim) 0.7930 [0.4726; 1.3307] 4.1 Placebo Osei 2020 (sim) 0.7495 [0.4164; 1.3491] 3.2 Placebo Chatfield 1966* 0.6192 [0.4106; 0.9338] 6.5 No Intervention O’Leary 1965* 0.6364 [0.3696; 1.0958] 3.7 No Intervention Scarabotto 2008* 0.6280 [0.3844; 1.0260] 4.5 No Intervention Fernando 2017 (sim) 0.4833 [0.2581; 0.9051] 2.8 No Intervention Diallo 2019 (sim) 0.4808 [0.2504; 0.9231] 2.6 No Intervention Park 2018 (sim) 0.5204 [0.3060; 0.8850] 3.9 No Intervention Ahmed 2020 (sim) 0.4828 [0.2682; 0.8689] 3.2 No Intervention Rossi 2021 (sim) 0.5185 [0.3114; 0.8633] 4.2 No Intervention Williams 2022 (sim) 0.4960 [0.2797; 0.8795] 3.3 No Intervention Tanaka 2016 (sim) 0.4792 [0.2402; 0.9557] 2.3 No Intervention

Number of studies: k = 20 Number of observations: o = 2858 (o.e = 1448, o.c = 1410) Number of events: e = 971

                     RR           95%-CI     t  p-value

Random effects model 0.7077 [0.6383; 0.7848] -7.00 < 0.0001

Quantifying heterogeneity (with 95%-CIs): tau^2 = 0 [0.0000; 0.0505]; tau = 0 [0.0000; 0.2248] I^2 = 0.0% [0.0%; 48.0%]; H = 1.00 [1.00; 1.39]

Test of heterogeneity: Q d.f. p-value 16.26 19 0.6398

Results for subgroups (random effects model): k RR 95%-CI tau^2 tau Q I^2 RCT_design = Placebo 10 0.8248 [0.7966; 0.8539] 0 0 0.47 0.0% RCT_design = No Intervention 10 0.5451 [0.4994; 0.5950] 0 0 1.75 0.0%

Test for subgroup differences (random effects model): Q d.f. p-value Between groups 98.73 1 < 0.0001

Details of meta-analysis methods: - Inverse variance method - Restricted maximum-likelihood estimator for tau^2 - Q-Profile method for confidence interval of tau^2 and tau - Calculation of I^2 based on Q - Hartung-Knapp adjustment for random effects model (df = 19)

14 13. Report-ready wording

In placebo-controlled studies, hyaluronidase was analysed using risk ratios and a random-effects model with REML estimation of between-study variance and Hartung-Knapp confidence intervals. Values below 1 favoured hyaluronidase. Results were checked using tau-estimator sensitivity, leave-one-out analysis, Galbraith/radial plots, funnel plots, Egger’s test, trim-and-fill sensitivity analysis, and subgroup analysis by comparison design.

15 14. Key learning points

  1. For binary outcomes, the simplest R function is metabin().
  2. event.e and n.e are the events and total in the experimental/intervention group.
  3. event.c and n.c are the events and total in the control group.
  4. The correct effect label here is risk ratio, not odds ratio.
  5. A Galbraith plot is easier to teach when it shows the pooled-effect line plus upper and lower ±2 limits.
  6. Robustness checks support interpretation but do not replace study-level risk-of-bias assessment.