diff --git a/DESCRIPTION b/DESCRIPTION index 6ba4893c..097c3075 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: multinma Title: Bayesian Network Meta-Analysis of Individual and Aggregate Data -Version: 0.7.2.9002 +Version: 0.7.2.9003 Authors@R: person(given = c("David", "M."), family = "Phillippo", diff --git a/NEWS.md b/NEWS.md index c6aade97..71069b4d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ # multinma 0.7.2.9000 +* Feature: Networks with integration points can now be combined with +`combine_network()`, where previously these were discarded. One potential use +case is to specify different types of marginal distributions or correlation +structures for different AgD studies in the network, by setting these up +separately with `add_integration()` before combining with `combine_network()`. * Fix: Resolved a bug where trying to fit meta-regression models with discrete covariates would sometimes result in a misspecified and inestimable model, due to the inclusion of additional columns in the design matrix for the reference diff --git a/R/nma_data.R b/R/nma_data.R index 7516667e..ea2ee622 100644 --- a/R/nma_data.R +++ b/R/nma_data.R @@ -1202,6 +1202,38 @@ combine_network <- function(..., trt_ref) { if (o_ipd %in% c("ordered", "competing") && o_agd_arm %in% c("ordered", "competing")) check_multi_combine(purrr::map(c(ipd, agd_arm), ".r")) + # Check integration points + if (any(purrr::map_lgl(s, inherits, what = "mlnmr_data")) && + all(purrr::map_lgl(s, inherits, what = "mlnmr_data") | + (purrr::map_lgl(s, has_ipd) & !purrr::map_lgl(s, has_agd_arm) & !purrr::map_lgl(s, has_agd_contrast)))) { + + has_int <- TRUE + + s_int <- s[purrr::map_lgl(s, inherits, what = "mlnmr_data")] + + # Check int_names + l_int_names <- purrr::map(s_int, "int_names") + if (!all(purrr::map_lgl(l_int_names, ~identical(., l_int_names[[1]])))) { + abort("Cannot combine AgD sources with different sets of covariates with integration points.") + } else { + int_names <- l_int_names[[1]] + } + + # Check n_int + l_n_int <- purrr::map_dbl(s_int, "n_int") + if (!all(l_n_int == l_n_int[1])) { + abort("Cannot combine AgD sources with different numbers of integration points.") + } else { + n_int <- l_n_int[[1]] + } + + } else if (any(purrr::map_lgl(s, inherits, what = "mlnmr_data"))) { + message("Dropping integration points from combined network, some AgD sources do not have integration points.") + has_int <- FALSE + } else { + has_int <- FALSE + } + # Produce nma_data object ipd <- dplyr::bind_rows(ipd) agd_arm <- dplyr::bind_rows(agd_arm) @@ -1217,6 +1249,14 @@ combine_network <- function(..., trt_ref) { outcome = outcome), class = "nma_data") + # Integration data setup + if (has_int) { + out$n_int <- n_int + out$int_names <- int_names + + class(out) <- c("mlnmr_data", class(out)) + } + # If trt_ref not specified, mark treatments factor as default, calculate # current reference trt if (missing(trt_ref)) { diff --git a/tests/testthat/test-data_combine.R b/tests/testthat/test-data_combine.R index a4da27ff..13f25fd2 100644 --- a/tests/testthat/test-data_combine.R +++ b/tests/testthat/test-data_combine.R @@ -379,3 +379,71 @@ test_that("combine_network works combining survival outcomes from same type of i set_ipd(ndmm_agd, studyf, trtf, Surv = Surv(eventtime, status))$ipd) }) + +test_that("combine_network respects mlnma_data objects with integration points", { + + ipd_net <- set_ipd(plaque_psoriasis_ipd, study = studyc, trt = trtc, r = pasi75) + + agd_net1 <- set_agd_arm( + filter(plaque_psoriasis_agd, studyc %in% c("FEATURE", "FIXTURE", "JUNCTURE")), + study = studyc, trt = trtc, r = pasi75_r, n = pasi75_n + ) %>% + add_integration(durnpso = distr(qgamma, mean = durnpso_mean, sd = durnpso_sd), + weight = distr(qgamma, mean = weight_mean, sd = weight_sd), cor = diag(2)) + + agd_net2 <- set_agd_arm( + filter(plaque_psoriasis_agd, !studyc %in% c("FEATURE", "FIXTURE", "JUNCTURE")), + study = studyc, trt = trtc, r = pasi75_r, n = pasi75_n + ) + + agd_net3 <- set_agd_arm( + filter(plaque_psoriasis_agd, !studyc %in% c("FEATURE", "FIXTURE", "JUNCTURE")), + study = studyc, trt = trtc, r = pasi75_r, n = pasi75_n + ) %>% + add_integration(durnpso = distr(qgamma, mean = durnpso_mean, sd = durnpso_sd), + weight = distr(qgamma, mean = weight_mean, sd = weight_sd), cor = diag(2)) + + expect_s3_class(combine_network(agd_net1), + c("mlnmr_data", "nma_data"), exact = TRUE) + + expect_s3_class(combine_network(ipd_net, agd_net1), + c("mlnmr_data", "nma_data"), exact = TRUE) + + expect_s3_class(combine_network(ipd_net, agd_net1, agd_net3), + c("mlnmr_data", "nma_data"), exact = TRUE) + + expect_s3_class(combine_network(agd_net1, agd_net3), + c("mlnmr_data", "nma_data"), exact = TRUE) + + expect_s3_class( + expect_message(combine_network(agd_net1, agd_net2), + "Dropping integration points"), + "nma_data", exact = TRUE) + + expect_s3_class( + expect_message(combine_network(ipd_net, agd_net1, agd_net2), + "Dropping integration points"), + "nma_data", exact = TRUE) + + expect_s3_class(combine_network(ipd_net, agd_net2), "nma_data") + + agd_net4 <- set_agd_arm( + filter(plaque_psoriasis_agd, !studyc %in% c("FEATURE", "FIXTURE", "JUNCTURE")), + study = studyc, trt = trtc, r = pasi75_r, n = pasi75_n + ) %>% + add_integration(durnpso = distr(qgamma, mean = durnpso_mean, sd = durnpso_sd)) + + expect_error(combine_network(agd_net1, agd_net4), "different sets of covariates") + expect_error(combine_network(ipd_net, agd_net1, agd_net4), "different sets of covariates") + + agd_net5 <- set_agd_arm( + filter(plaque_psoriasis_agd, !studyc %in% c("FEATURE", "FIXTURE", "JUNCTURE")), + study = studyc, trt = trtc, r = pasi75_r, n = pasi75_n + ) %>% + add_integration(durnpso = distr(qgamma, mean = durnpso_mean, sd = durnpso_sd), + weight = distr(qgamma, mean = weight_mean, sd = weight_sd), cor = diag(2), + n_int = 8) + + expect_error(combine_network(agd_net1, agd_net5), "different numbers of integration points") + expect_error(combine_network(ipd_net, agd_net1, agd_net5), "different numbers of integration points") +})