knitr::opts_chunk$set(echo=FALSE,
                      warning=FALSE,message=FALSE,
                      fig.width=50,
                      fig.height=100)
load_all("../../gemtc/gemtc")
load_all("..")
library(dplyr)
filter <- dplyr::filter
library(ggplot2)
library(plotly)
library(stringr)
library(knitr)
library(meta)
source("theme.r")

clean_aetype <- function(aetype){
    aetype <- stringr::str_to_sentence(aetype)
    aetype[aetype=="Ggt increased"] <-"GGT increased"
    aetype[aetype=="Cpk increased"] <-"CPK increased"
    aetype[aetype=="Inr increased"] <-"INR increased"
    aetype[aetype=="Withdrawals because of aes"] <-"Withdrawals because of AEs"
    aetype
}
opts_chunk$set(fig.width=15, fig.height=20, echo=FALSE)
muffleError <- function(x,options) {}
knit_hooks$set(error=muffleError)
aecount <- 
  bpaearmtype %>%
  filter(!aetype %in% c("ANY ADVERSE EVENT", "SERIOUS ADVERSE EVENTS")) %>% 
  group_by(aetype) %>%
  summarise(N=sum(N), count=sum(count)) %>%
  mutate(prop = count/N) %>%
  mutate(aetype=factor(aetype, levels=unique(aetype)[order(prop)])) %>%
  mutate(aetype = clean_aetype(aetype)) %>% 
  mutate(pse = N*prop*(1-prop))

mares <- data.frame(aetype=unique(as.character(aecount$aetype)))
mares[,c("totn","totr","totncon","totrcon",
         "or","orl","oru", "rd","rdl","rdu",
         "nmeno", "nbone", "nmenopre", "nmenopost", "nbonenone", "nboneall",
         "meno.orp","bone.orp","meno.rdp","bone.rdp",
         "ormeno","ormenol","ormenou", "orbone","orbonel","orboneu", 
         "rdmeno","rdmenol","rdmenou", "rdbone","rdbonel","rdboneu", 
         "orbonenone","orbonenonel","orbonenoneu",  "orboneall","orbonealll","orboneallu",
         "ormenopre","ormenoprel","ormenopreu", "ormenopost","ormenopostl","ormenopostu", 
         "rdbonenone","rdbonenonel","rdbonenoneu",  "rdboneall","rdbonealll","rdboneallu",
         "rdmenopre","rdmenoprel","rdmenopreu", "rdmenopost","rdmenopostl","rdmenopostu",
         "totnmenopre", "totnmenopost", "totrmenopre", "totrmenopost",
         "totnbonenone", "totnboneall", "totrbonenone", "totrboneall",
         "totnconmenopre", "totnconmenopost", "totrconmenopre", "totrconmenopost",
         "totnconbonenone", "totnconboneall", "totrconbonenone", "totrconboneall"
         )] <- NA


aetypes_meta <- setdiff(mares$aetype, "Withdrawals because of AEs")
for (i in seq(along.with=aetypes_meta)){ 
    bpma <-
        bpaeriskdiff %>%
        mutate(aetype = clean_aetype(aetype)) %>% 
        filter(trtcon %in% c("100","101","103")) %>%
        filter(aetype==aetypes_meta[i]) %>%
        mutate(meno2 = ifelse(meno=="mixed", NA, as.character(meno)),
               meno2 = factor(meno2, levels=c("pre","post")),
               bonemeta2 = ifelse(bonemeta=="mixed", NA, as.character(bonemeta)),
               bonemeta2 = factor(bonemeta2, levels = c("none", "all")))
    if (nrow(bpma) > 0){
        mres <- metabin(count, N, rcon, ncon, studlab=study, data=bpma, sm="OR")
        mresrd <- metabin(count, N, rcon, ncon, studlab=study, data=bpma, sm="RD")

        mares[i,"nmeno"] <- sum(!is.na(bpma$meno2))
        mares[i,"nmenopre"] <- sum(bpma$meno2=="pre", na.rm=TRUE)
        mares[i,"nmenopost"] <- sum(bpma$meno2=="post", na.rm=TRUE)
        if (mares[i,"nmeno"] > 0){
            mrtry <- try(mregmeno <- metareg(mres,  ~ meno2))
            if (!inherits(mrtry, "try-error") && (length(coef(mrtry))>1)){
                orsmeno <- exp(coef(summary(mregmeno)))[c("meno2post"),c("estimate","ci.lb","ci.ub")]
                mares$meno.orp[i] <- mregmeno$QMp
                mares[i,c("ormeno","ormenol","ormenou")] <- orsmeno
                ormenopre <- unlist(unclass(predict(mrtry, newmods = 0))[c("pred","ci.lb","ci.ub")])
                ormenopost <- unlist(unclass(predict(mrtry, newmods = 1))[c("pred","ci.lb","ci.ub")])
                mares[i,c("ormenopre","ormenoprel","ormenopreu")] <- exp(ormenopre)
                mares[i,c("ormenopost","ormenopostl","ormenopostu")] <- exp(ormenopost)
            }
            mrtryd <- try(mregmeno <- metareg(mresrd,  ~ meno2))
            if (!inherits(mrtryd, "try-error") && (length(coef(mrtryd))>1)){
                rdsmeno <- coef(summary(mregmeno))[c("meno2post"),c("estimate","ci.lb","ci.ub")]
                mares$meno.rdp[i] <- mregmeno$QMp
                mares[i,c("rdmeno","rdmenol","rdmenou")] <- rdsmeno
                rdmenopre <- unlist(unclass(predict(mrtryd, newmods = 0))[c("pred","ci.lb","ci.ub")])
                rdmenopost <- unlist(unclass(predict(mrtryd, newmods = 1))[c("pred","ci.lb","ci.ub")])
                mares[i,c("rdmenopre","rdmenoprel","rdmenopreu")] <- rdmenopre 
                mares[i,c("rdmenopost","rdmenopostl","rdmenopostu")] <- rdmenopost
            }
        }

        mares[i,"nbone"] <- sum(!is.na(bpma$bonemeta2))
        mares[i,"nboneall"] <- sum(bpma$bonemeta2=="all", na.rm=TRUE)
        mares[i,"nbonenone"] <- sum(bpma$bonemeta2=="none", na.rm=TRUE)
        if (mares[i,"nbone"] > 0){
            mrtry <- try(mregbone <- metareg(mres,  ~ bonemeta2))
            if (!inherits(mrtry, "try-error") && (length(coef(mrtry))>1)){
                orsbone <- exp(coef(summary(mregbone)))[c("bonemeta2all"),c("estimate","ci.lb","ci.ub")]
                mares$bone.orp[i] <- mregbone$QMp
                mares[i,c("orbone","orbonel","orboneu")] <- orsbone
                orbonenone <- unlist(unclass(predict(mrtry, newmods = 0))[c("pred","ci.lb","ci.ub")])
                orboneall <- unlist(unclass(predict(mrtry, newmods = 1))[c("pred","ci.lb","ci.ub")])
                mares[i,c("orbonenone","orbonenonel","orbonenoneu")] <- exp(orbonenone)
                mares[i,c("orboneall","orbonealll","orboneallu")] <- exp(orboneall)
            }
            mrtryd <- try(mregbone <- metareg(mresrd,  ~ bonemeta2))
            if (!inherits(mrtryd, "try-error") && (length(coef(mrtryd))>1)){
                rdsbone <- coef(summary(mregbone))[c("bonemeta2all"),c("estimate","ci.lb","ci.ub")]
                mares$bone.rdp[i] <- mregbone$QMp
                mares[i,c("rdbone","rdbonel","rdboneu")] <- rdsbone
                rdbonenone <- unlist(unclass(predict(mrtryd, newmods = 0))[c("pred","ci.lb","ci.ub")])
                rdboneall <- unlist(unclass(predict(mrtryd, newmods = 1))[c("pred","ci.lb","ci.ub")])
                mares[i,c("rdbonenone","rdbonenonel","rdbonenoneu")] <- rdbonenone 
                mares[i,c("rdboneall","rdbonealll","rdboneallu")] <- rdboneall
            }
        }


        mares$totn[i] <- sum(bpma$N) 
        mares$totr[i] <- sum(bpma$count) 
        mares$totncon[i] <- sum(bpma$ncon) 
        mares$totrcon[i] <- sum(bpma$rcon)

        mares$totnmenopre[i] <- sum(bpma$N[bpma$meno2=="pre"],na.rm=TRUE)
        mares$totnmenopost[i] <- sum(bpma$N[bpma$meno2=="post"],na.rm=TRUE)
        mares$totrmenopre[i] <- sum(bpma$count[bpma$meno2=="pre"],na.rm=TRUE)
        mares$totrmenopost[i] <- sum(bpma$count[bpma$meno2=="post"],na.rm=TRUE)

        mares$totnbonenone[i] <- sum(bpma$N[bpma$bonemeta2=="none"],na.rm=TRUE)
        mares$totnboneall[i] <- sum(bpma$N[bpma$bonemeta2=="all"],na.rm=TRUE)
        mares$totrbonenone[i] <- sum(bpma$count[bpma$bonemeta2=="none"],na.rm=TRUE)
        mares$totrboneall[i] <- sum(bpma$count[bpma$bonemeta2=="all"],na.rm=TRUE)

        mares$totnconmenopre[i] <- sum(bpma$ncon[bpma$meno2=="pre"],na.rm=TRUE)
        mares$totnconmenopost[i] <- sum(bpma$ncon[bpma$meno2=="post"],na.rm=TRUE)
        mares$totrconmenopre[i] <- sum(bpma$rcon[bpma$meno2=="pre"],na.rm=TRUE)
        mares$totrconmenopost[i] <- sum(bpma$rcon[bpma$meno2=="post"],na.rm=TRUE)

        mares$totnconbonenone[i] <- sum(bpma$ncon[bpma$bonemeta2=="none"],na.rm=TRUE)
        mares$totnconboneall[i] <- sum(bpma$ncon[bpma$bonemeta2=="all"],na.rm=TRUE)
        mares$totrconbonenone[i] <- sum(bpma$rcon[bpma$bonemeta2=="none"],na.rm=TRUE)
        mares$totrconboneall[i] <- sum(bpma$rcon[bpma$bonemeta2=="all"],na.rm=TRUE)

        mares$totr[i] <- sum(bpma$count) 
        mares$totncon[i] <- sum(bpma$ncon) 
        mares$totrcon[i] <- sum(bpma$rcon)

        mares[i,c("or","orl","oru")] <- exp(unlist(mres[c("TE.fixed","lower.fixed","upper.fixed")]))
        mares[i,c("rd","rdl","rdu")] <- unlist(mresrd[c("TE.fixed","lower.fixed","upper.fixed")])
    } else
        mares[i,c("totn","totr","totncon","totrcon")] <- 0

}

# Filter to those for which the OR or RD is prac and stat sig for a subgroup 
# 1.5 for ORs, and 0.02 for RDs 

mares <- mares %>% mutate(
              statsigbonerd = bone.rdp < 0.05 & !is.na(bone.rdp),
              statsigboneor = bone.orp < 0.05 & !is.na(bone.orp),
              statsigmenord = meno.rdp < 0.05 & !is.na(meno.rdp),
              statsigmenoor = meno.orp < 0.05 & !is.na(meno.orp),
              sigbonenone = (rdbonenone > 0.02 & !is.na(rdbonenone) & statsigbonerd) | (orbonenone > 1.5 & !is.na(orbonenone) & statsigboneor),
              sigboneall = (rdboneall > 0.02 & !is.na(rdboneall) & statsigbonerd) | (orboneall > 1.5 & !is.na(orboneall) & statsigboneor),
              sigmenopre = (rdmenopre > 0.02 & !is.na(rdmenopre) & statsigmenord) | (ormenopre > 1.5 & !is.na(ormenopre) & statsigmenoor),
              sigmenopost = (rdmenopost > 0.02 & !is.na(rdmenopost) & statsigmenord) | (ormenopost > 1.5 & !is.na(ormenopost) & statsigmenoor),
              datamenopre =  sprintf("%s/%s vs %s/%s", totrmenopre, totnmenopre, totrconmenopre, totnconmenopre),
              datamenopost =  sprintf("%s/%s vs %s/%s", totrmenopost, totnmenopost, totrconmenopost, totnconmenopost),
              databonenone =  sprintf("%s/%s vs %s/%s", totrbonenone, totnbonenone, totrconbonenone, totnconbonenone),
              databoneall =  sprintf("%s/%s vs %s/%s", totrboneall, totnboneall, totrconboneall, totnconboneall), 
              orfmenopre = sprintf("%s (%s,%s)", round(ormenopre,2), round(ormenoprel,2), round(ormenopreu,2)),
              orfmenopost = sprintf("%s (%s,%s)", round(ormenopost,2), round(ormenopostl,2), round(ormenopostu,2)),
              rdfmenopre = sprintf("%s (%s,%s)", round(rdmenopre,2), round(rdmenoprel,2), round(rdmenopreu,2)),
              rdfmenopost = sprintf("%s (%s,%s)", round(rdmenopost,2), round(rdmenopostl,2), round(rdmenopostu,2)),
              orfbonenone = sprintf("%s (%s,%s)", round(orbonenone,2), round(orbonenonel,2), round(orbonenoneu,2)),
              orfboneall = sprintf("%s (%s,%s)", round(orboneall,2), round(orbonealll,2), round(orboneallu,2)),
              rdfbonenone = sprintf("%s (%s,%s)", round(rdbonenone,2), round(rdbonenonel,2), round(rdbonenoneu,2)),
              rdfboneall = sprintf("%s (%s,%s)", round(rdboneall,2), round(rdbonealll,2), round(rdboneallu,2)),
              nmenof = sprintf("%s/%s", nmenopre, nmenopost),  
              nbonef = sprintf("%s/%s", nbonenone, nboneall)
         )

To investigate whether the adverse effects of bisphosphonates were modified by menopausal status or by the presence of bone metastases, the previous meta-analyses of the studies with direct comparisons of a bisphosphonate with a non-bisphosphonate control were extended to fixed effects meta-regression analyses [ ref Viechtbauer, W. (2010). Conducting meta-analyses in R with the "metafor" package. Journal of Statistical Software, 36(3), 1-48. ]. The studies were categorised according to whether they included pre-menopausal, post-menopausal women or a mixture, and according to whether the participants had bone metastases (no participants, all participants or a mixture). The studies with a mixture of patient types were excluded, then the treatment effect (log odds ratio or risk difference) was modified with a linear regression term contrasting "all metastatic patients" or "all post-menopausal patients", with none.

The meta-regression results for all adverse events were filtered to include only those where the contrast in the treatment effect between subgroups was statistically significant, and the treatment effect on adverse event risk for the higher-risk subgroup was practically significant (odds ratio > 1.5 or risk difference > 2%). The remaining results are presented in the two tables below.

Menopausal status

The only significant subgroup contrast is for insomnia, though this result is likely to be unreliable as it is based on only 11 and 15 events in the two subgroups respectively. Moreover the estimated risk increase in post-menopausal women is only 2%.

options(width=150)

cnames <- c("",
            "Studies (none/all metastatic)",
            "Pre-menopausal", "Post-menopausal", 
            "Odds ratio", "Risk difference", "Odds ratio", "Risk difference",
            "OR", "RD")

library(kableExtra)
mares %>%
    filter(sigmenopre | sigmenopost) %>%
    mutate(meno.orp = round(meno.orp,2), meno.rdp=round(meno.rdp,2)) %>% 
    select(aetype, nmenof, datamenopre, datamenopost,
           orfmenopre, rdfmenopre, orfmenopost, rdfmenopost, meno.orp, meno.rdp) %>%
    kable(col.names = cnames)  %>%
    add_header_above(c(" " = 1, " " = 1,
                       "Total number of events / number of patients, treated vs control" = 2,
                       "Pre-menopausal" = 2, "Post-menopausal" = 2,
                       "p-value for subgroup contrast"=2))

Bone metastases

cnames[3:4] <- c("None metastatic", "All metastatic")
mares %>%
    filter(sigbonenone | sigboneall) %>%
    mutate(bone.orp = round(bone.orp,2), bone.rdp=round(bone.rdp,2)) %>% 
    select(aetype, nbonef, databonenone, databoneall, orfbonenone, rdfbonenone, orfboneall, rdfboneall, bone.orp, bone.rdp) %>%
    kable(col.names=cnames) %>%
    add_header_above(c(" " = 1, " " = 1,
                       "Total number of events / number of patients, treated vs control" = 2,
                       "None metastatic" = 2, "All metastatic" = 2,
                       "p-value for subgroup contrast" = 2))

Absolute risks for selected events

events_base <- c("increased bone pain", "HYPOCALCEMIA", "FATIGUE")
brisk0 <- baseres %>%
filter(aetype %in% events_base,
       patient == "Cancer") %>%
arrange(match(aetype, events_base)) %>% 
pull(p)

events_meta <- c("Increased bone pain", "Hypocalcemia", "Fatigue")
maresbrisk <- mares %>%
    filter(aetype %in% events_meta) %>%
    select(aetype, orbonenone, orbonenonel, orbonenoneu,
           orboneall, orbonealll, orboneallu) %>%
    arrange(match(aetype, events_meta)) %>% 
    mutate(brisk = brisk0) %>%
    mutate(
        trisknone = plogis(qlogis(brisk) + log(orbonenone)),
        trisknonel = plogis(qlogis(brisk) + log(orbonenonel)),
        trisknoneu = plogis(qlogis(brisk) + log(orbonenoneu)),
        triskall = plogis(qlogis(brisk) + log(orboneall)),
        triskalll = plogis(qlogis(brisk) + log(orbonealll)),
        triskallu = plogis(qlogis(brisk) + log(orboneallu)),
        treatedrisknone = sprintf("%s (%s,%s)", 100*round(trisknone,2),
                             100*round(trisknonel,2), 100*round(trisknoneu,2)),
        treatedriskall = sprintf("%s (%s,%s)", 100*round(triskall,2),
                            100*round(triskalll,2), 100*round(triskallu,2))
    )
maresbrisk %>%
    select(aetype, treatedrisknone, treatedriskall) %>%
    arrange(match(aetype, events_meta))

## increased bone pain, nonmeta 
## OR 1.53 (1.26,1.85) RD 0.02 (0,0.04)
## treated (from RD) 13%(11%,17%)
## plogis(log(0.11/(1-0.11)) + log(c(1.53, 1.26, 1.85)))
## plogis(log(0.113/(1-0.113)) + log(c(1.525, 1.269, 1.848)))
## treated (from OR) 15% (12%, 18%))
## 
## hypocalc, metast
## baseline 4%
## OR 2.14 (1.19,3.85)  RD 0.06 (0.03,0.08)
## plogis(log(0.04/(1-0.04)) + log(c(2.14, 1.19, 3.85)))
## treated (from RD) 10% (7%, 12%)
## treated (from OR)  8% (4%, 14%) 
## 
## fatigue, metast,
## baseline 10%
## OR 1.69 (1.24,2.29)  RD 0.11 (0.06,0.17)
## plogis(log(0.1/(1-0.1)) + log(c(1.69, 1.24, 2.29)))
## treated (from RD) 21% (16%, 27%) 
## treated (from OR) 16% (12%, 20% )
##


chjackson/adverse documentation built on June 16, 2022, 4:53 p.m.