Thanks so much! This looks really promising. Just want to check that I am understanding everything correctly, so have tried running this:
library(tidyverse)
library(brms)
#> Loading required package: Rcpp
#> Loading 'brms' package (version 2.21.0). Useful instructions
#> can be found by typing help('brms'). A more detailed introduction
#> to the package is available through vignette('brms_overview').
#>
#> Attaching package: 'brms'
#> The following object is masked from 'package:stats':
#>
#> ar
library(posterior)
#> This is posterior version 1.5.0
#>
#> Attaching package: 'posterior'
#> The following objects are masked from 'package:stats':
#>
#> mad, sd, var
#> The following objects are masked from 'package:base':
#>
#> %in%, match
d <- tribble(~study, ~cases, ~population, ~region,
"A", 23, 4651, "AFR",
"B", 451, 76420, "AFR",
"C", 101, 12456, "WPR",
"D", 4, 391, "WPR",
"E", 66, 2318, "AFR") %>%
mutate(prev = cases/population,
prev100k = prev*100000)
d <- d %>%
mutate(adj_prev = c(0.0061, 0.0049, 0.0086, 0.021, 0.035),
adj_prev_ci_lo = c(0.0023, 0.0035, 0.060, 0.003, 0.017),
adj_prev_ci_hi = c(0.0062, 0.0063, 0.11, 0.067, 0.056))
#calculate the adjusted number of cases
d <- d %>%
mutate(adj_cases = round(adj_prev*population))
#calcuate standard error for adjusted prevalence from 95%CI
d <- d %>%
mutate(adj_se = (adj_prev_ci_hi-adj_prev_ci_lo)/3.92)
glimpse(d)
#> Rows: 5
#> Columns: 11
#> $ study <chr> "A", "B", "C", "D", "E"
#> $ cases <dbl> 23, 451, 101, 4, 66
#> $ population <dbl> 4651, 76420, 12456, 391, 2318
#> $ region <chr> "AFR", "AFR", "WPR", "WPR", "AFR"
#> $ prev <dbl> 0.004945173, 0.005901596, 0.008108542, 0.010230179, 0.0…
#> $ prev100k <dbl> 494.5173, 590.1596, 810.8542, 1023.0179, 2847.2821
#> $ adj_prev <dbl> 0.0061, 0.0049, 0.0086, 0.0210, 0.0350
#> $ adj_prev_ci_lo <dbl> 0.0023, 0.0035, 0.0600, 0.0030, 0.0170
#> $ adj_prev_ci_hi <dbl> 0.0062, 0.0063, 0.1100, 0.0670, 0.0560
#> $ adj_cases <dbl> 28, 374, 107, 8, 81
#> $ adj_se <dbl> 0.0009948980, 0.0007142857, 0.0127551020, 0.0163265306,…
#convert adjusted point estimate and standard error into mean and dispersion
d <- d %>%
mutate(derived_phi = (adj_prev/adj_se^2) - (adj_prev/adj_se)^2 - 1)
#fit the meta-analysis model
m1<- brm(formula = bf(adj_prev ~ 1 + (1|study), phi ~ 0 + offset(derived_phi)), data = d, family = Beta(link_phi = "identity"))
summary(m1)
#> Warning: There were 9 divergent transitions after warmup. Increasing
#> adapt_delta above 0.8 may help. See
#> http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
#> Family: beta
#> Links: mu = logit; phi = identity
#> Formula: adj_prev ~ 1 + (1 | study)
#> phi ~ 0 + offset(derived_phi)
#> Data: d (Number of observations: 5)
#> Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
#> total post-warmup draws = 4000
#>
#> Multilevel Hyperparameters:
#> ~study (Number of levels: 5)
#> Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
#> sd(Intercept) 1.20 0.57 0.46 2.74 1.01 799 932
#>
#> Regression Coefficients:
#> Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
#> Intercept -4.34 0.61 -5.53 -3.02 1.00 917 1125
#>
#> Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
#> and Tail_ESS are effective sample size measures, and Rhat is the potential
#> scale reduction factor on split chains (at convergence, Rhat = 1).
# Function to calculate the mean of the logit-normal distribution
mean_logit_normal <- function(mu, sigma) {
# Density function of X
dx <- function(x) dnorm(x, mean = mu, sd = sigma)
# Transformation function
transformation <- function(x) 1 / (1 + exp(-x))
# Compute mean using numerical integration
mean_Y <- integrate(function(x) transformation(x) * dx(x), lower = -Inf, upper = Inf)$value
return(mean_Y)
}
# Calculate the mean of the logit-normal distribution for each pair of mu and sigma
tibble(mu = m1 %>% as_draws_rvars() %>% pluck("Intercept") %>% draws_of() %>% as.vector(),
sigma = m1 %>% as_draws_rvars() %>% pluck("sd_study__Intercept") %>% draws_of() %>% as.vector()) %>%
mutate(mean_Y = map2_dbl(mu, sigma, mean_logit_normal, .progress = T)) ->
parameters
parameters$mean_Y %>% rvar()
#> rvar<4000>[1] mean ± sd:
#> [1] 0.034 ± 0.034
Created on 2024-04-24 with reprex v2.1.0
So everything runs successfully, but…
- Not 100% convinced I have calculated
derived_phi
correctly.
- posterior mean of 0.034 seems too high to be correct to me.
Thanks again for ongoing help - I am learning a lot!