Pretransplant natural antibody levels identify a subset of deceased donor kidney transplant recipients that benefit from infliximab induction
Statistical report
Authors and affiliations
Vojtech Petr1,2, Filip Tichanek1, Samuel L. Liu3, Felix Poppelaars2, Brandon Renner2, Jennifer Laskowski2, Shrey Purohit2, Ming Zhao3, Diana Jalal4,5, Peter S. Heeger6,#, Joshua M. Thurman2,#
1 Institute for Clinical and Experimental Medicine, Prague, Czech Republic
2 Department of Medicine, University of Colorado School of Medicine, Anschutz Medical Campus, Aurora, CO, USA
3 Feinberg Cardiovascular and Renal Research Institute, Northwestern University, Chicago, IL, USA
4 Department of Medicine, Carver College of Medicine, University of Iowa, IA, USA
5 Iowa City VA HCS, Iowa City, IA, USA
6 Departments of Medicine, Surgery and Biomedical Sciences, Cedars Sinai Medical Center, Los Angeles, CA, USA
# Co-senior authors, contributed equally
This is a statistical report of the study titled Pretransplant natural antibody levels identify a subset of deceased donor kidney transplant recipients that benefit from infliximab induction that has been published in the American Journal of Transplantation[1].
When using this code or data, cite the original publication:
V. Petr, F. Tichanek, S.L. Liu, F. Poppelaars, B. Renner, J. Laskowski, S. Purohit, M. Zhao, D. Jalal, P.S. Heeger, J.M. Thurman, Pretransplant natural antibody levels identify a subset of deceased donor kidney transplant recipients that benefit from infliximab induction, American Journal of Transplantation (2025). https://doi.org/10.1016/j.ajt.2025.06.003.
BibTeX entry is provided in a CITATION.bib file
Original GitHub repository: https://github.com/filip-tichanek/infliximab_nAb
1 Statistical modelling description
1.1 Full version
Analyses were performed in R (version 4.4.3) [2] and GraphPad Prism (version 10.2.3). Continuous variables are reported as medians with interquartile ranges and categorical variables as counts and percentages. Group comparisons were conducted using the Mann–Whitney test, and correlations were assessed via Spearman’s rank correlation.
Unadjusted effects of covariates (including nAb and their interaction with infliximab) were estimated using complete-case logistic regression for binary outcomes (DGF, infection, and BKV infection) and linear models for eGFR.
For outcome–nAb combinations where the 95% confidence interval of the interaction term did not include the null effect, we fit multivariable Bayesian models with a non-linear interaction between log\(_2\)-transformed nAb levels and infliximab using penalized B-splines with 5 knots (separately for each treatment group). Logistic Bayesian regression was used for binary outcomes, while Bayesian robust regression (Student’s t-distribution) was used for eGFR. Covariates were prespecified based on their well-documented association with kidney transplant outcomes and included donor and recipient sex, HLA mismatch count, KDPI, perfusion event, recipient age, and cold ischemia time.
Missing data (35 for HLA mismatch, 21 for perfusion event, 3 for cold ischemia time) were handled via multiple imputation (80 datasets) using the ‘mice’ package [3]. Binary variables were imputed via logistic regression, and numeric variables via predictive mean matching. Bayesian models were run using the ‘brms’ package [4] with Hamiltonian Monte Carlo sampling (4 chains, 2000 iterations including 1900 warm-ups per each of 80 imputed datasets, yielding 32,000 post-warmup samples). Posterior distributions were summarized by the median (point estimate) and the 2.5th and 97.5th percentiles (95% credible interval, 95% CrI).
Priors for fixed effects were Gaussian, centered at 0 (\(\mu = 0\)), with \(\sigma\) defined as follows:
In logistic model (binary outcomes):
\(\sigma = 4\) for binary predictors
\(\sigma = \frac{2}{\text{SD}(\text{predictor})}\) for numeric predictors
For robust regression (eGFR):
\(\sigma = 4 \times \text{SD}(\text{eGFR})\) for binary predictors
\(\sigma = \frac{2 \times \text{SD}(\text{eGFR})}{\text{SD}(\text{predictor})}\) for numeric predictors
Non-linear effects used Student’s t priors:
Baseline spline: \(df = 3, \mu = 0, \sigma = 0.6\)
Treatment-specific spline: \(df = 3, \mu = 0, \sigma = 0.3\)
Posterior estimates for infliximab effects were obtained at the 5th, 25th, 50th, 75th, and 95th percentiles of nAb levels. We quantified the modulation of infliximab treatment by comparing the posterior distributions of the treatment effect at the 5th and 95th percentiles of nAb levels. For each posterior sample, we computed the ratio of odds ratios (OR at 95th percentile / OR at 5th percentile) in logistic models and the difference in treatment effects (\(\beta_{\text{infliximab}}|\text{nAbs}=95^\text{th}\) – \(\beta_{\text{infliximab}}|\text{nAbs}=5^\text{th}\)) in robust regression for eGFR.
Mediation analysis was performed to assess whether infliximab affected eGFR and whether this effect was mediated through DGF. Analyses were conducted separately for individuals with below- and above-median aCL IgG levels.
Because the highest aCL IgG levels were only observed in the control group, we performed a sensitivity analysis by restricting the dataset to patients with aCL IgG levels within the range observed in the infliximab group.
Another sensitivitu
1.2 Short version (manuscript)
All analyses were conducted in R (version 4.4.3). Continuous variables are reported as medians with interquartile ranges, and categorical variables as percentages. Spearman’s rank correlation assessed associations.
Unadjusted analyses used logistic regression for binary outcomes (DGF, infection, and BKV infection) and linear models for eGFR, both based on complete cases. When the 95% confidence interval of the interaction term between nAb and infliximab did not include the null effect, multivariable Bayesian models with non-linear interactions (using group-specific B splines) were fitted to using the ‘brms’ R package. These models employed logistic regression for binary outcomes and robust (Student’s t) regression for eGFR, with multiple imputation (80 datasets) for missing data.
Pre-specified covariates included donor and recipient sex, HLA mismatch count, KDPI, perfusion event, recipient age, and cold ischemia time. Posterior distributions were summarized by medians with 95% credible intervals (CrI). To evaluate infliximab treatment effects across different nAb levels, we obtained posterior distributions at the 5th, 25th, 50th, 75th, and 95th percentiles of these levels. To quantify how strongly nAb levels modulate the infliximab effect, we compared infliximab estimates at the 95th and 5th percentiles, reporting the ratio of odds ratios for binary outcomes and the difference in treatment effects for eGFR.
Bayesian mediation analysis was used to assess whether infliximab’s effect on eGFR is mediated through DGF, stratified by above- vs. below-median aCL IgG levels. A sensitivity analysis was performed by restricting the dataset to patients with aCL IgG levels within the range observed in the infliximab group.
A full description of the statistical modeling methods, including prior specifications and posterior sampling details, is provided in the Supplementary Methods and online with the code (https://filip-tichanek.github.io/infliximab_nAb).
2 Initiation
Packages
Open code
if (TRUE) {rm(list = ls() )}
if (TRUE) {
suppressWarnings(suppressMessages({
library(tidyverse)
library(stringr)
library(stringi)
library(ggpubr)
library(emmeans)
library(gtsummary)
library(skimr)
library(car)
library(RJDBC)
library(sjPlot)
library(flextable)
library(openxlsx)
library(mgcv)
library(pROC)
library(cowplot)
library(boot)
library(glmnet)
library(brms)
library(projpred)
library(janitor)
library(arm)
library(corrplot)
library(lubridate)
library(kableExtra)
library(ggdist)
library(bayesplot)
library(coxed)
library(quantreg)
library(ggbeeswarm)
library(mgcv)
library(mice)
library(MASS)
library(bayestestR)
# Functions clashes
select <- dplyr::select
rename <- dplyr::rename
mutate <- dplyr::mutate
recode <- dplyr::recode
summarize <- dplyr::summarize
count <- dplyr::count
# Simple math functions
logit <-function(x){log(x/(1-x))}
inv_logit <- function(x){exp(x)/(1+exp(x))}
}))
}Functions
Open code
run <- function(expr, path, reuse = TRUE) {
fit <- NULL
if (reuse) {
path <- paste0(path, ".Rds")
fit <- suppressWarnings(try(readRDS(path), silent = TRUE))
if (inherits(fit, "try-error")) {
fit <- NULL
}
}
if (is.null(fit)) {
fit <- eval(substitute(expr))
if (reuse && !is.null(path) && nzchar(path)) {
saveRDS(fit, file = path)
}
}
return(fit)
}Setting seeds and scipen
Open code
set.seed(2025)
options(scipen = 999)3 Data
Upload data a create relevant variables. Alternative data are the same, but also contains newly-calculated eGFR (based not only on the central but also local measurements) used for some sensitivity analyses
Open code
data3 <- read.xlsx(
"gitignore/data/dataset_updated_4_2024_ver2.xlsx")
data3 <- data3 %>%
mutate(
GPE_dep_log2 = log2(GPE_dep),
MPE_dep_log2 = log2(MPE_dep),
GPE_ind_log2 = log2(GPE_ind),
MPE_ind_log2 = log2(MPE_ind),
graft_failure = if_else(!is.na(later) & later == 'graft_loss', 1, 0)
) %>%
mutate(
GPL_BC_log2 = log2(GPL_BC),
MPL_BC_log2 = log2(MPL_BC),
GFR_MDRD_3 =if_else(graft_failure == 1, 10, GFR_MDRD_2)
) %>%
mutate(CIT = CIT / 60) %>%
mutate(treatment_group = if_else(
infliximab == 1, "infiximab", "placebo"
))There are two variables that are expected to affect the outcomes but include many missing values. Look which variables are correlated with these variables (perfusion_event and HLA_MM) so these may be helpful for the imputation.
Open code
safe_cor <- function(x, y) {
if (sd(x, na.rm = TRUE) == 0 || sd(y, na.rm = TRUE) == 0) {
NA_real_
} else {
cor(x, y, use = "pairwise.complete.obs", method = 'pearson')
}
}
df <- data3 %>%
select(where(is.numeric))
res <- tibble(
variable = names(df),
cor_perfusion = map_dbl(variable, ~ safe_cor(df[[.x]], df$perfusion_event)),
cor_hla = map_dbl(variable, ~ safe_cor(df[[.x]], df$HLA_MM)),
n_na = map_int(variable, ~ sum(is.na(df[[.x]])))
) %>%
mutate(max_abs_cor = pmax(abs(cor_perfusion), abs(cor_hla), na.rm = TRUE)) %>%
arrange(desc(max_abs_cor))
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero
kableExtra::kable(res %>% filter(n_na<10, max_abs_cor>0.1))| variable | cor_perfusion | cor_hla | n_na | max_abs_cor |
|---|---|---|---|---|
| HLAMMGE3 | 0.1521796 | 0.7388502 | 0 | 0.7388502 |
| BKV_viremia_time | 0.2740103 | -0.0162880 | 0 | 0.2740103 |
| GFR_CKD | -0.1605158 | -0.2709311 | 2 | 0.2709311 |
| race_2 | 0.2353864 | -0.1944819 | 0 | 0.2353864 |
| GFR_MDRD | -0.1685550 | -0.2334869 | 2 | 0.2334869 |
| GPE_ind | 0.2170082 | 0.0316690 | 1 | 0.2170082 |
| race_donor_2 | 0.2131970 | -0.0264465 | 0 | 0.2131970 |
| GFR_MDRD_2 | -0.1706397 | -0.2099583 | 2 | 0.2099583 |
| age_donor | 0.1486748 | 0.1994518 | 1 | 0.1994518 |
| GFR_MDRD_3 | -0.1658982 | -0.1955132 | 2 | 0.1955132 |
| CIT | 0.1903365 | -0.1393050 | 3 | 0.1903365 |
| CMV_IgG_rec | -0.0818317 | 0.1860303 | 0 | 0.1860303 |
| de_novo_DSA | 0.0807407 | 0.1769103 | 2 | 0.1769103 |
| KDPI | 0.0744357 | 0.1750746 | 0 | 0.1750746 |
| donor_type | -0.1691540 | 0.0328450 | 0 | 0.1691540 |
| GPE_ind_log2 | 0.1687633 | 0.0447728 | 1 | 0.1687633 |
| ID_subject | 0.1620089 | -0.1226652 | 0 | 0.1620089 |
| MPE_dep | -0.1584339 | 0.0166590 | 1 | 0.1584339 |
| MPL_BC | -0.1555197 | -0.0622218 | 0 | 0.1555197 |
| MPL_BC_log2 | -0.1518460 | -0.0367600 | 0 | 0.1518460 |
| GPL_BC_log2 | -0.1480250 | -0.1102327 | 0 | 0.1480250 |
| RRT_preTx | -0.0024901 | -0.1451204 | 0 | 0.1451204 |
| MPE_dep_log2 | -0.1448089 | 0.0124194 | 1 | 0.1448089 |
| GPL_BC | -0.1132365 | -0.1437448 | 0 | 0.1437448 |
| CMV_IgG_donor | 0.0710178 | 0.1437226 | 1 | 0.1437226 |
| GPL | -0.1130782 | -0.1432358 | 0 | 0.1432358 |
| male_sex | 0.1431312 | 0.0824554 | 0 | 0.1431312 |
| MPL | -0.1421092 | -0.0587360 | 0 | 0.1421092 |
| WIT | 0.1409576 | -0.0638921 | 7 | 0.1409576 |
| DGF | -0.0424969 | 0.1340953 | 0 | 0.1340953 |
| male_sex_donor | -0.0485702 | -0.1333746 | 0 | 0.1333746 |
| dc_graftloss_event_24mo | -0.1301364 | -0.0487302 | 0 | 0.1301364 |
| infliximab | 0.0591993 | 0.1247757 | 0 | 0.1247757 |
| MPE_ind | -0.1246244 | -0.0598818 | 1 | 0.1246244 |
| GFR_days | 0.1222818 | 0.0609560 | 2 | 0.1222818 |
| rec_age | -0.0243711 | 0.1218259 | 0 | 0.1218259 |
| preformed_DSA | -0.1142633 | -0.0309393 | 2 | 0.1142633 |
| MPE_ind_log2 | -0.1014825 | -0.0061797 | 1 | 0.1014825 |
3.1 Summary tables
Who will be deleted?
Open code
data3 %>%
filter(is.na(GFR_MDRD) |
is.na(GPE_dep) |
is.na(MPE_dep)
) %>% select(ID_subject, terminated_days, GFR_MDRD_2, GPE_ind)
## ID_subject terminated_days GFR_MDRD_2 GPE_ind
## 1 3027 6 NA 0.0790
## 2 23007 0 NA 0.0975
## 3 57019 NA 54.28 NA
data3 <- data3 %>%
filter(!is.na(GFR_MDRD),
!is.na(GPE_dep),
!is.na(MPE_dep)
)
dim(data3)
## [1] 177 1133.1.1 Demography
Open code
data3 %>%
filter(!is.na(GFR_MDRD_2),
!is.na(GPE_dep),
!is.na(MPE_dep)) %>%
select(male_sex, rec_age, race_2, race_1, ethnicity, treatment_group, CKD_cause_2, RRT_preTx, RRT_months, RRT_type, male_sex_donor, age_donor, race_donor_2, race_donor_1, donor_cause_narrow, donor_cause_anoxia, donor_cause_CVA, donor_type, ATG, standard_triple, HLA_MM, KDPI, WIT, CIT, perfusion_event, perfusion_time, preformed_DSA) %>%
tbl_summary(by = treatment_group, type = list(HLA_MM ~ "continuous")) %>%
add_p() %>%
add_overall()
## The following warnings were returned during `add_p()`:
## ! For variable `perfusion_time` (`treatment_group`) and "estimate",
## "statistic", "p.value", "conf.low", and "conf.high" statistics: cannot
## compute exact p-value with ties
## ! For variable `perfusion_time` (`treatment_group`) and "estimate",
## "statistic", "p.value", "conf.low", and "conf.high" statistics: cannot
## compute exact confidence intervals with tiesCharacteristic |
Overall |
infiximab |
placebo |
p-value 2 |
|---|---|---|---|---|
| male_sex | 109 (62%) | 59 (68%) | 50 (56%) | 0.094 |
| rec_age | 54 (45, 61) | 54 (46, 61) | 55 (45, 62) | >0.9 |
| race_2 | 72 (41%) | 35 (40%) | 37 (41%) | >0.9 |
| race_1 | 0.9 | |||
| American Indian or Alaska Native | 1 (0.6%) | 1 (1.1%) | 0 (0%) | |
| Asian | 9 (5.1%) | 5 (5.7%) | 4 (4.4%) | |
| Black or African American | 73 (41%) | 34 (39%) | 39 (43%) | |
| Native Hawaiian or Other Pacific Islander | 3 (1.7%) | 1 (1.1%) | 2 (2.2%) | |
| Unknown or Not Reported | 19 (11%) | 11 (13%) | 8 (8.9%) | |
| White | 72 (41%) | 35 (40%) | 37 (41%) | |
| ethnicity | 0.2 | |||
| Hispanic or Latino | 25 (14%) | 15 (17%) | 10 (11%) | |
| Not Hispanic or Latino | 152 (86%) | 72 (83%) | 80 (89%) | |
| CKD_cause_2 | 0.3 | |||
| 1 | 44 (25%) | 23 (26%) | 21 (23%) | |
| 2 | 42 (24%) | 22 (25%) | 20 (22%) | |
| 3 | 58 (33%) | 27 (31%) | 31 (34%) | |
| 4 | 18 (10%) | 11 (13%) | 7 (7.8%) | |
| 5 | 15 (8.5%) | 4 (4.6%) | 11 (12%) | |
| RRT_preTx | 162 (92%) | 80 (92%) | 82 (91%) | 0.8 |
| RRT_months | 62 (36, 95) | 63 (37, 92) | 62 (36, 96) | >0.9 |
| Unknown | 15 | 7 | 8 | |
| RRT_type | 132 (81%) | 64 (80%) | 68 (83%) | 0.6 |
| Unknown | 15 | 7 | 8 | |
| male_sex_donor | 98 (55%) | 43 (49%) | 55 (61%) | 0.12 |
| age_donor | 43 (32, 50) | 44 (32, 50) | 42 (30, 50) | 0.5 |
| Unknown | 1 | 1 | 0 | |
| race_donor_2 | 109 (62%) | 59 (68%) | 50 (56%) | 0.094 |
| race_donor_1 | 0.033 | |||
| American Indian or Alaska Native | 2 (1.1%) | 0 (0%) | 2 (2.2%) | |
| Asian | 9 (5.1%) | 2 (2.3%) | 7 (7.8%) | |
| Black or African American | 30 (17%) | 10 (11%) | 20 (22%) | |
| Native Hawaiian or Other Pacific Islander | 1 (0.6%) | 0 (0%) | 1 (1.1%) | |
| Unknown or Not Reported | 26 (15%) | 16 (18%) | 10 (11%) | |
| White | 109 (62%) | 59 (68%) | 50 (56%) | |
| donor_cause_narrow | >0.9 | |||
| Anoxia | 82 (46%) | 38 (44%) | 44 (49%) | |
| Cardiovascular | 5 (2.8%) | 2 (2.3%) | 3 (3.3%) | |
| Cerebrovascular Accident | 42 (24%) | 22 (25%) | 20 (22%) | |
| CNS-Other | 1 (0.6%) | 0 (0%) | 1 (1.1%) | |
| Drug Overdose | 2 (1.1%) | 1 (1.1%) | 1 (1.1%) | |
| Head Trauma | 38 (21%) | 21 (24%) | 17 (19%) | |
| Infection | 2 (1.1%) | 1 (1.1%) | 1 (1.1%) | |
| Other | 2 (1.1%) | 1 (1.1%) | 1 (1.1%) | |
| Respiratory Failure | 3 (1.7%) | 1 (1.1%) | 2 (2.2%) | |
| donor_cause_anoxia | 82 (46%) | 38 (44%) | 44 (49%) | 0.5 |
| donor_cause_CVA | 42 (24%) | 22 (25%) | 20 (22%) | 0.6 |
| donor_type | 133 (75%) | 64 (74%) | 69 (77%) | 0.6 |
| ATG | 176 (99%) | 87 (100%) | 89 (99%) | >0.9 |
| standard_triple | 158 (89%) | 76 (87%) | 82 (91%) | 0.4 |
| HLA_MM | 5.00 (4.00, 5.00) | 5.00 (4.00, 6.00) | 4.00 (3.50, 5.00) | 0.080 |
| Unknown | 35 | 17 | 18 | |
| KDPI | 53 (37, 71) | 53 (32, 71) | 51 (39, 74) | 0.4 |
| WIT | 33 (27, 42) | 33 (27, 42) | 33 (27, 40) | 0.9 |
| Unknown | 6 | 3 | 3 | |
| CIT | 15 (10, 21) | 16 (10, 21) | 15 (10, 20) | 0.8 |
| Unknown | 3 | 3 | 0 | |
| perfusion_event | 63 (40%) | 34 (44%) | 29 (37%) | 0.4 |
| Unknown | 21 | 9 | 12 | |
| perfusion_time | 11.0 (8.0, 15.0) | 12.0 (8.0, 15.0) | 11.0 (6.0, 16.0) | 0.5 |
| Unknown | 144 | 68 | 76 | |
| preformed_DSA | 5 (2.8%) | 2 (2.3%) | 3 (3.3%) | >0.9 |
| 1
n (%); Median (Q1, Q3) |
||||
| 2
Pearson’s Chi-squared test; Wilcoxon rank sum test; Fisher’s exact test |
||||
3.1.2 Demography stratified treatment and aCL IgG groups
Open code
sum_data <- data3 %>%
filter(!is.na(GFR_MDRD_2),
!is.na(GPE_dep),
!is.na(MPE_dep)) %>%
dplyr::select(
DGF, infection_any, GFR_MDRD, GFR_MDRD_2, GFR_MDRD_3, BKV_event_2,
GPL_BC,
MPL_BC,
GPE_dep,
GPE_ind,
MPE_dep,
MPE_ind,
male_sex,
HLA_MM,
male_sex_donor,
KDPI,
perfusion_event,
CIT,
infliximab,
rec_age,
race_2, race_1, ethnicity, CKD_cause_2, RRT_preTx, RRT_months, RRT_type, age_donor,
race_donor_2, race_donor_1, donor_cause_narrow, donor_cause_anoxia, donor_cause_CVA,
donor_type, ATG, standard_triple, WIT, perfusion_event, perfusion_time, preformed_DSA) %>%
mutate(aCL_IgG_category = if_else(GPL_BC < median(data3$GPL_BC, na.rm =TRUE),
'low aCL IgG', 'high aCL'
),
treatment = if_else(infliximab == 1, 'IFX', 'PCO')
) %>%
mutate(category = interaction(treatment, aCL_IgG_category))
sum_data %>% select(-c(infliximab, aCL_IgG_category, GPL_BC:MPE_ind)) %>%
gtsummary::tbl_summary(by = category,
type = list(HLA_MM ~ "continuous")) %>%
add_p() %>%
add_overall()
## The following errors were returned during `add_p()`:
## ✖ For variable `CKD_cause_2` (`category`) and "estimate", "p.value",
## "conf.low", and "conf.high" statistics: FEXACT error 7(location). LDSTP=18630
## is too small for this problem, (pastp=88.6719, ipn_0:=ipoin[itp=242]=2837,
## stp[ipn_0]=84.7176). Increase workspace or consider using
## 'simulate.p.value=TRUE'
## ✖ For variable `donor_cause_narrow` (`category`) and "estimate", "p.value",
## "conf.low", and "conf.high" statistics: FEXACT error 6. LDKEY=621 is too
## small for this problem, (ii := key2[itp=427] = 3378662, ldstp=18630) Try
## increasing the size of the workspace and possibly 'mult'
## ✖ For variable `race_donor_1` (`category`) and "estimate", "p.value",
## "conf.low", and "conf.high" statistics: FEXACT error 7(location). LDSTP=18630
## is too small for this problem, (pastp=38.0864, ipn_0:=ipoin[itp=606]=5057,
## stp[ipn_0]=37.1156). Increase workspace or consider using
## 'simulate.p.value=TRUE'Characteristic |
Overall |
IFX.high aCL |
PCO.high aCL |
IFX.low aCL IgG |
PCO.low aCL IgG |
p-value 2 |
|---|---|---|---|---|---|---|
| DGF | 60 (34%) | 19 (46%) | 14 (29%) | 9 (20%) | 18 (43%) | 0.029 |
| infection_any | 75 (42%) | 17 (41%) | 17 (35%) | 21 (46%) | 20 (48%) | 0.7 |
| GFR_MDRD | 50 (39, 65) | 45 (35, 51) | 58 (44, 69) | 56 (40, 68) | 47 (35, 58) | 0.020 |
| GFR_MDRD_2 | 50 (38, 65) | 46 (38, 54) | 56 (42, 67) | 56 (39, 70) | 44 (35, 62) | 0.056 |
| GFR_MDRD_3 | 50 (38, 65) | 46 (38, 54) | 56 (42, 67) | 56 (39, 70) | 44 (35, 62) | 0.057 |
| BKV_event_2 | 38 (21%) | 12 (29%) | 5 (10%) | 13 (28%) | 8 (19%) | 0.10 |
| male_sex | 109 (62%) | 26 (63%) | 26 (54%) | 33 (72%) | 24 (57%) | 0.3 |
| HLA_MM | 5.00 (4.00, 5.00) | 5.00 (4.00, 5.00) | 4.00 (4.00, 5.00) | 5.00 (4.00, 6.00) | 4.00 (3.00, 6.00) | 0.14 |
| Unknown | 35 | 8 | 11 | 9 | 7 | |
| male_sex_donor | 98 (55%) | 19 (46%) | 30 (63%) | 24 (52%) | 25 (60%) | 0.4 |
| KDPI | 53 (37, 71) | 49 (29, 66) | 51 (37, 74) | 54 (35, 72) | 51 (40, 74) | 0.6 |
| perfusion_event | 63 (40%) | 15 (41%) | 14 (31%) | 19 (46%) | 15 (45%) | 0.5 |
| Unknown | 21 | 4 | 3 | 5 | 9 | |
| CIT | 15 (10, 21) | 17 (10, 21) | 16 (10, 22) | 14 (10, 20) | 14 (10, 20) | 0.7 |
| Unknown | 3 | 1 | 0 | 2 | 0 | |
| rec_age | 54 (45, 61) | 53 (45, 60) | 55 (45, 62) | 56 (48, 63) | 54 (45, 62) | 0.8 |
| race_2 | 72 (41%) | 16 (39%) | 18 (38%) | 19 (41%) | 19 (45%) | 0.9 |
| race_1 | 0.8 | |||||
| American Indian or Alaska Native | 1 (0.6%) | 0 (0%) | 0 (0%) | 1 (2.2%) | 0 (0%) | |
| Asian | 9 (5.1%) | 1 (2.4%) | 3 (6.3%) | 4 (8.7%) | 1 (2.4%) | |
| Black or African American | 73 (41%) | 18 (44%) | 22 (46%) | 16 (35%) | 17 (40%) | |
| Native Hawaiian or Other Pacific Islander | 3 (1.7%) | 1 (2.4%) | 0 (0%) | 0 (0%) | 2 (4.8%) | |
| Unknown or Not Reported | 19 (11%) | 5 (12%) | 5 (10%) | 6 (13%) | 3 (7.1%) | |
| White | 72 (41%) | 16 (39%) | 18 (38%) | 19 (41%) | 19 (45%) | |
| ethnicity | 0.4 | |||||
| Hispanic or Latino | 25 (14%) | 8 (20%) | 7 (15%) | 7 (15%) | 3 (7.1%) | |
| Not Hispanic or Latino | 152 (86%) | 33 (80%) | 41 (85%) | 39 (85%) | 39 (93%) | |
| CKD_cause_2 | ||||||
| 1 | 44 (25%) | 10 (24%) | 11 (23%) | 13 (28%) | 10 (24%) | |
| 2 | 42 (24%) | 9 (22%) | 9 (19%) | 13 (28%) | 11 (26%) | |
| 3 | 58 (33%) | 13 (32%) | 16 (33%) | 14 (30%) | 15 (36%) | |
| 4 | 18 (10%) | 5 (12%) | 5 (10%) | 6 (13%) | 2 (4.8%) | |
| 5 | 15 (8.5%) | 4 (9.8%) | 7 (15%) | 0 (0%) | 4 (9.5%) | |
| RRT_preTx | 162 (92%) | 41 (100%) | 40 (83%) | 39 (85%) | 42 (100%) | <0.001 |
| RRT_months | 62 (36, 95) | 73 (49, 105) | 60 (39, 80) | 51 (36, 81) | 69 (34, 115) | 0.3 |
| Unknown | 15 | 0 | 8 | 7 | 0 | |
| RRT_type | 132 (81%) | 37 (90%) | 34 (85%) | 27 (69%) | 34 (81%) | 0.10 |
| Unknown | 15 | 0 | 8 | 7 | 0 | |
| age_donor | 43 (32, 50) | 38 (32, 48) | 42 (25, 50) | 45 (34, 50) | 42 (33, 52) | 0.6 |
| Unknown | 1 | 0 | 0 | 1 | 0 | |
| race_donor_2 | 109 (62%) | 28 (68%) | 27 (56%) | 31 (67%) | 23 (55%) | 0.4 |
| race_donor_1 | ||||||
| American Indian or Alaska Native | 2 (1.1%) | 0 (0%) | 1 (2.1%) | 0 (0%) | 1 (2.4%) | |
| Asian | 9 (5.1%) | 1 (2.4%) | 3 (6.3%) | 1 (2.2%) | 4 (9.5%) | |
| Black or African American | 30 (17%) | 3 (7.3%) | 10 (21%) | 7 (15%) | 10 (24%) | |
| Native Hawaiian or Other Pacific Islander | 1 (0.6%) | 0 (0%) | 0 (0%) | 0 (0%) | 1 (2.4%) | |
| Unknown or Not Reported | 26 (15%) | 9 (22%) | 7 (15%) | 7 (15%) | 3 (7.1%) | |
| White | 109 (62%) | 28 (68%) | 27 (56%) | 31 (67%) | 23 (55%) | |
| donor_cause_narrow | ||||||
| Anoxia | 82 (46%) | 18 (44%) | 24 (50%) | 20 (43%) | 20 (48%) | |
| Cardiovascular | 5 (2.8%) | 1 (2.4%) | 2 (4.2%) | 1 (2.2%) | 1 (2.4%) | |
| Cerebrovascular Accident | 42 (24%) | 7 (17%) | 10 (21%) | 15 (33%) | 10 (24%) | |
| CNS-Other | 1 (0.6%) | 0 (0%) | 0 (0%) | 0 (0%) | 1 (2.4%) | |
| Drug Overdose | 2 (1.1%) | 0 (0%) | 0 (0%) | 1 (2.2%) | 1 (2.4%) | |
| Head Trauma | 38 (21%) | 14 (34%) | 9 (19%) | 7 (15%) | 8 (19%) | |
| Infection | 2 (1.1%) | 1 (2.4%) | 1 (2.1%) | 0 (0%) | 0 (0%) | |
| Other | 2 (1.1%) | 0 (0%) | 1 (2.1%) | 1 (2.2%) | 0 (0%) | |
| Respiratory Failure | 3 (1.7%) | 0 (0%) | 1 (2.1%) | 1 (2.2%) | 1 (2.4%) | |
| donor_cause_anoxia | 82 (46%) | 18 (44%) | 24 (50%) | 20 (43%) | 20 (48%) | >0.9 |
| donor_cause_CVA | 42 (24%) | 7 (17%) | 10 (21%) | 15 (33%) | 10 (24%) | 0.4 |
| donor_type | 133 (75%) | 27 (66%) | 36 (75%) | 37 (80%) | 33 (79%) | 0.4 |
| ATG | 176 (99%) | 41 (100%) | 48 (100%) | 46 (100%) | 41 (98%) | 0.5 |
| standard_triple | 158 (89%) | 34 (83%) | 44 (92%) | 42 (91%) | 38 (90%) | 0.6 |
| WIT | 33 (27, 42) | 32 (25, 42) | 32 (26, 38) | 35 (28, 43) | 37 (29, 47) | 0.2 |
| Unknown | 6 | 1 | 1 | 2 | 2 | |
| perfusion_time | 11.0 (8.0, 15.0) | 14.0 (12.0, 16.0) | 16.0 (11.0, 16.0) | 11.0 (5.0, 14.0) | 8.0 (5.0, 11.0) | 0.030 |
| Unknown | 144 | 32 | 41 | 36 | 35 | |
| preformed_DSA | 5 (2.8%) | 2 (4.9%) | 2 (4.2%) | 0 (0%) | 1 (2.4%) | 0.5 |
| treatment | <0.001 | |||||
| IFX | 87 (49%) | 41 (100%) | 0 (0%) | 46 (100%) | 0 (0%) | |
| PCO | 90 (51%) | 0 (0%) | 48 (100%) | 0 (0%) | 42 (100%) | |
| 1
n (%); Median (Q1, Q3) |
||||||
| 2
Pearson’s Chi-squared test; Kruskal-Wallis rank sum test; Fisher’s exact test |
||||||
3.1.3 Outcomes by treatment arm
Open code
sum_data %>% select(treatment, DGF:BKV_event_2) %>%
gtsummary::tbl_summary(by = treatment) %>%
add_p() %>%
add_overall()Characteristic |
Overall |
IFX |
PCO |
p-value 2 |
|---|---|---|---|---|
| DGF | 60 (34%) | 28 (32%) | 32 (36%) | 0.6 |
| infection_any | 75 (42%) | 38 (44%) | 37 (41%) | 0.7 |
| GFR_MDRD | 50 (39, 65) | 50 (39, 62) | 51 (39, 66) | 0.3 |
| GFR_MDRD_2 | 50 (38, 65) | 50 (39, 65) | 51 (38, 66) | 0.5 |
| GFR_MDRD_3 | 50 (38, 65) | 50 (39, 65) | 51 (38, 66) | 0.6 |
| BKV_event_2 | 38 (21%) | 25 (29%) | 13 (14%) | 0.021 |
| 1
n (%); Median (Q1, Q3) |
||||
| 2
Pearson’s Chi-squared test; Wilcoxon rank sum test |
||||
3.1.4 Outcomes by treatment arm and DGF
Open code
sum_data %>% select(treatment, DGF:BKV_event_2) %>%
mutate(group = paste0('DGF', DGF, ', ', treatment)) %>%
gtsummary::tbl_summary(by = group) %>%
add_p() %>%
add_overall()Characteristic |
Overall |
DGF0, IFX |
DGF0, PCO |
DGF1, IFX |
DGF1, PCO |
p-value 2 |
|---|---|---|---|---|---|---|
| treatment | <0.001 | |||||
| IFX | 87 (49%) | 59 (100%) | 0 (0%) | 28 (100%) | 0 (0%) | |
| PCO | 90 (51%) | 0 (0%) | 58 (100%) | 0 (0%) | 32 (100%) | |
| DGF | 60 (34%) | 0 (0%) | 0 (0%) | 28 (100%) | 32 (100%) | <0.001 |
| infection_any | 75 (42%) | 26 (44%) | 22 (38%) | 12 (43%) | 15 (47%) | 0.8 |
| GFR_MDRD | 50 (39, 65) | 56 (41, 67) | 58 (43, 74) | 40 (27, 48) | 44 (30, 51) | <0.001 |
| GFR_MDRD_2 | 50 (38, 65) | 55 (41, 67) | 58 (42, 71) | 40 (28, 50) | 42 (30, 52) | <0.001 |
| GFR_MDRD_3 | 50 (38, 65) | 55 (41, 67) | 58 (42, 71) | 40 (28, 50) | 42 (30, 52) | <0.001 |
| BKV_event_2 | 38 (21%) | 16 (27%) | 7 (12%) | 9 (32%) | 6 (19%) | 0.10 |
| 1
n (%); Median (Q1, Q3) |
||||||
| 2
Pearson’s Chi-squared test; Kruskal-Wallis rank sum test |
||||||
3.1.5 Antigens
3.1.5.1 In general
Open code
data3 %>%
filter(
!is.na(GFR_MDRD_2),
!is.na(GPE_dep_log2),
!is.na(MPE_dep_log2)
) %>%
select(
treatment_group,
GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep
) %>%
tbl_summary(by = treatment_group) %>%
add_p() %>%
add_overall()Characteristic |
Overall |
infiximab |
placebo |
p-value 2 |
|---|---|---|---|---|
| GPL_BC | 0.93 (0.60, 1.80) | 0.87 (0.56, 1.55) | 0.96 (0.65, 2.08) | 0.3 |
| MPL_BC | 4 (2, 8) | 3 (2, 6) | 5 (2, 10) | 0.005 |
| MPE_ind | 0.11 (0.09, 0.15) | 0.11 (0.09, 0.15) | 0.12 (0.09, 0.15) | 0.6 |
| MPE_dep | 0.18 (0.13, 0.25) | 0.18 (0.12, 0.25) | 0.19 (0.14, 0.26) | 0.4 |
| GPE_ind | 0.11 (0.09, 0.15) | 0.12 (0.10, 0.15) | 0.11 (0.09, 0.15) | 0.7 |
| GPE_dep | 0.19 (0.16, 0.25) | 0.19 (0.15, 0.26) | 0.19 (0.16, 0.24) | 0.3 |
| 1
Median (Q1, Q3) |
||||
| 2
Wilcoxon rank sum test |
||||
3.1.5.2 Only these with DGF
Open code
data3 %>%
filter(!is.na(GFR_MDRD_3),
!is.na(GPE_dep_log2),
!is.na(MPE_dep_log2)) %>%
filter(DGF == 1) %>%
select(treatment_group,
GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep) %>%
tbl_summary(by = treatment_group) %>%
add_p() %>%
add_overall()
## The following warnings were returned during `add_p()`:
## ! For variable `GPE_dep` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## p-value with ties
## ! For variable `GPE_dep` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## confidence intervals with ties
## ! For variable `GPE_ind` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## p-value with ties
## ! For variable `GPE_ind` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## confidence intervals with ties
## ! For variable `MPE_dep` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## p-value with ties
## ! For variable `MPE_dep` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## confidence intervals with ties
## ! For variable `MPE_ind` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## p-value with ties
## ! For variable `MPE_ind` (`treatment_group`) and "estimate", "statistic",
## "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
## confidence intervals with tiesCharacteristic |
Overall |
infiximab |
placebo |
p-value 2 |
|---|---|---|---|---|
| GPL_BC | 0.96 (0.59, 2.55) | 1.15 (0.75, 3.32) | 0.80 (0.57, 1.87) | 0.2 |
| MPL_BC | 6 (3, 9) | 6 (3, 8) | 6 (3, 12) | 0.8 |
| MPE_ind | 0.11 (0.09, 0.15) | 0.11 (0.09, 0.17) | 0.11 (0.09, 0.14) | >0.9 |
| MPE_dep | 0.17 (0.13, 0.25) | 0.22 (0.14, 0.26) | 0.16 (0.12, 0.25) | 0.4 |
| GPE_ind | 0.12 (0.09, 0.15) | 0.13 (0.10, 0.15) | 0.11 (0.09, 0.15) | 0.3 |
| GPE_dep | 0.20 (0.15, 0.28) | 0.20 (0.16, 0.27) | 0.18 (0.13, 0.30) | 0.5 |
| 1
Median (Q1, Q3) |
||||
| 2
Wilcoxon rank sum exact test; Wilcoxon rank sum test |
||||
3.1.5.3 Only these without DGF
Open code
data3 %>%
filter(!is.na(GFR_MDRD_2),
!is.na(GPE_dep_log2),
!is.na(MPE_dep_log2)) %>%
filter(DGF == 0) %>%
select(treatment_group,
GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep) %>%
tbl_summary(by = treatment_group) %>%
add_p() %>%
add_overall()Characteristic |
Overall |
infiximab |
placebo |
p-value 2 |
|---|---|---|---|---|
| GPL_BC | 0.89 (0.61, 1.66) | 0.79 (0.53, 1.28) | 1.09 (0.70, 2.09) | 0.018 |
| MPL_BC | 3.5 (2.0, 6.6) | 2.6 (1.8, 4.7) | 4.6 (2.5, 9.1) | <0.001 |
| MPE_ind | 0.11 (0.09, 0.15) | 0.11 (0.09, 0.15) | 0.12 (0.09, 0.16) | 0.5 |
| MPE_dep | 0.19 (0.13, 0.25) | 0.17 (0.12, 0.23) | 0.20 (0.15, 0.26) | 0.072 |
| GPE_ind | 0.11 (0.09, 0.15) | 0.11 (0.09, 0.15) | 0.11 (0.10, 0.17) | 0.8 |
| GPE_dep | 0.19 (0.16, 0.25) | 0.19 (0.15, 0.26) | 0.19 (0.16, 0.22) | 0.6 |
| 1
Median (Q1, Q3) |
||||
| 2
Wilcoxon rank sum test |
||||
3.2 Antigens data distributions
Open code
data_hist <- data3 %>%
filter(!is.na(GFR_MDRD_2),
!is.na(GPE_dep_log2),
!is.na(MPE_dep_log2)) %>%
mutate(infliximab = if_else(infliximab == 1, 'IFX', 'PCO'))
p1 <- data_hist %>%
ggplot(aes(x = GPL_BC)) +
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p2 <- data_hist %>%
ggplot(aes(x = GPL_BC_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p3 <- data_hist %>%
ggplot(aes(x = MPL_BC))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p4 <- data_hist %>%
ggplot(aes(x = MPL_BC_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p5 <- data_hist %>%
ggplot(aes(x = MPE_ind))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p6 <- data_hist %>%
ggplot(aes(x = MPE_ind_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p7 <- data_hist %>%
ggplot(aes(x = MPE_dep))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p8 <- data_hist %>%
ggplot(aes(x = MPE_dep_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p9 <- data_hist %>%
ggplot(aes(x = GPE_ind))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p10 <- data_hist %>%
ggplot(aes(x = GPE_ind_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p11 <- data_hist %>%
ggplot(aes(x = GPE_dep))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
p12 <- data_hist %>%
ggplot(aes(x = GPE_dep_log2))+
geom_histogram() +
facet_wrap(~ infliximab, nrow = 2)
plot_grid(p1,p2,p3,p4, p5, p6, p7, p8, p9, p10, p11, p12, nrow = 3)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.4 Data - models-relevant
4.1 Define the model-relevant data
Note that eGFR based on the central measurement (GFR_MDRD) will be used for imputation, as it shows stronger correlations with variables containing missing values than either the combined local and central eGFR (GFR_MDRD_2) or the combined version with values set to 10 in cases of graft failure within the 2-year follow-up (GFR_MDRD_3)
Open code
data_model_priorImpute <- data3 %>%
dplyr::select(
# outcomes
DGF, infection_any, GFR_MDRD, GFR_MDRD_2, GFR_MDRD_3, BKV_event_2,
# antigens
GPL_BC_log2,
MPL_BC_log2,
GPE_dep_log2,
GPE_ind_log2,
MPE_dep_log2,
MPE_ind_log2,
# other covariates
male_sex,
HLA_MM,
male_sex_donor,
KDPI,
perfusion_event,
CIT,
infliximab,
rec_age,
# variables for imputation only
HLAMMGE3,
BKV_viremia_time,
race_2,
race_donor_2,
age_donor,
CMV_IgG_rec,
de_novo_DSA,
donor_type
) %>%
filter(!is.na(GFR_MDRD_2),
!is.na(GPE_dep_log2),
!is.na(MPE_dep_log2))
data_model_priorImpute %>% summary()
## DGF infection_any GFR_MDRD GFR_MDRD_2
## Min. :0.000 Min. :0.0000 Min. : 8.44 Min. : 4.30
## 1st Qu.:0.000 1st Qu.:0.0000 1st Qu.: 39.07 1st Qu.: 38.10
## Median :0.000 Median :0.0000 Median : 49.88 Median : 49.90
## Mean :0.339 Mean :0.4237 Mean : 51.90 Mean : 52.04
## 3rd Qu.:1.000 3rd Qu.:1.0000 3rd Qu.: 64.98 3rd Qu.: 64.98
## Max. :1.000 Max. :1.0000 Max. :123.48 Max. :123.48
##
## GFR_MDRD_3 BKV_event_2 GPL_BC_log2 MPL_BC_log2
## Min. : 4.30 Min. :0.0000 Min. :-3.8616 Min. :-5.533
## 1st Qu.: 38.10 1st Qu.:0.0000 1st Qu.:-0.7449 1st Qu.: 1.093
## Median : 49.90 Median :0.0000 Median :-0.1046 Median : 2.043
## Mean : 51.72 Mean :0.2147 Mean : 0.1147 Mean : 1.996
## 3rd Qu.: 64.98 3rd Qu.:0.0000 3rd Qu.: 0.8505 3rd Qu.: 2.942
## Max. :123.48 Max. :1.0000 Max. : 4.9498 Max. : 5.417
##
## GPE_dep_log2 GPE_ind_log2 MPE_dep_log2 MPE_ind_log2
## Min. :-3.6439 Min. :-3.86775 Min. :-3.60823 Min. :-3.8997
## 1st Qu.:-2.6666 1st Qu.:-3.41120 1st Qu.:-2.92686 1st Qu.:-3.4501
## Median :-2.3921 Median :-3.16488 Median :-2.45799 Median :-3.1520
## Mean :-2.2821 Mean :-2.92303 Mean :-2.40099 Mean :-3.0307
## 3rd Qu.:-2.0058 3rd Qu.:-2.70840 3rd Qu.:-1.99712 3rd Qu.:-2.7037
## Max. : 0.4163 Max. :-0.03283 Max. : 0.05866 Max. :-0.5724
##
## male_sex HLA_MM male_sex_donor KDPI
## Min. :0.0000 Min. :0.000 Min. :0.0000 Min. :20.00
## 1st Qu.:0.0000 1st Qu.:4.000 1st Qu.:0.0000 1st Qu.:37.00
## Median :1.0000 Median :5.000 Median :1.0000 Median :53.00
## Mean :0.6158 Mean :4.373 Mean :0.5537 Mean :53.77
## 3rd Qu.:1.0000 3rd Qu.:5.000 3rd Qu.:1.0000 3rd Qu.:71.00
## Max. :1.0000 Max. :6.000 Max. :1.0000 Max. :93.00
## NA's :35
## perfusion_event CIT infliximab rec_age
## Min. :0.0000 Min. : 3.267 Min. :0.0000 Min. :27.00
## 1st Qu.:0.0000 1st Qu.:10.267 1st Qu.:0.0000 1st Qu.:45.00
## Median :0.0000 Median :15.325 Median :0.0000 Median :54.00
## Mean :0.4038 Mean :15.920 Mean :0.4915 Mean :53.15
## 3rd Qu.:1.0000 3rd Qu.:20.508 3rd Qu.:1.0000 3rd Qu.:61.00
## Max. :1.0000 Max. :50.133 Max. :1.0000 Max. :73.00
## NA's :21 NA's :3
## HLAMMGE3 BKV_viremia_time race_2 race_donor_2
## Min. :0.0000 Min. : 22.0 Min. :0.0000 Min. :0.0000
## 1st Qu.:1.0000 1st Qu.: 196.0 1st Qu.:0.0000 1st Qu.:0.0000
## Median :1.0000 Median : 735.0 Median :0.0000 Median :1.0000
## Mean :0.8475 Mean : 693.9 Mean :0.4068 Mean :0.6158
## 3rd Qu.:1.0000 3rd Qu.: 952.0 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1854.0 Max. :1.0000 Max. :1.0000
##
## age_donor CMV_IgG_rec de_novo_DSA donor_type
## Min. : 4.00 Min. :0.000 Min. :0.00000 Min. :0.0000
## 1st Qu.:31.75 1st Qu.:0.000 1st Qu.:0.00000 1st Qu.:1.0000
## Median :42.50 Median :1.000 Median :0.00000 Median :1.0000
## Mean :40.33 Mean :0.661 Mean :0.06215 Mean :0.7514
## 3rd Qu.:50.00 3rd Qu.:1.000 3rd Qu.:0.00000 3rd Qu.:1.0000
## Max. :69.00 Max. :1.000 Max. :1.00000 Max. :1.0000
## NA's :1
## Get mean values
mmale_sex <- mean(data_model_priorImpute$male_sex, na.rm = TRUE)
mmale_sex_donor <- mean(data_model_priorImpute$male_sex_donor, na.rm = TRUE)
mperfusion_event <- mean(data_model_priorImpute$perfusion_event, na.rm = TRUE)
mrec_age <- mean(data_model_priorImpute$rec_age, na.rm = TRUE)
mKDPI <- mean(data_model_priorImpute$KDPI, na.rm = TRUE)
mCIT <- mean(data_model_priorImpute$CIT, na.rm = TRUE)
mHLA_MM <- mean(data_model_priorImpute$HLA_MM, na.rm = TRUE)
mDGF <- mean(data_model_priorImpute$DGF, na.rm = TRUE)4.2 Explore data
Open code
skim(data_model_priorImpute)| Name | data_model_priorImpute |
| Number of rows | 177 |
| Number of columns | 28 |
| _______________________ | |
| Column type frequency: | |
| numeric | 28 |
| ________________________ | |
| Group variables | None |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| DGF | 0 | 1.00 | 0.34 | 0.47 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▅ |
| infection_any | 0 | 1.00 | 0.42 | 0.50 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▆ |
| GFR_MDRD | 0 | 1.00 | 51.90 | 20.26 | 8.44 | 39.07 | 49.88 | 64.98 | 123.48 | ▃▇▆▂▁ |
| GFR_MDRD_2 | 0 | 1.00 | 52.04 | 20.66 | 4.30 | 38.10 | 49.90 | 64.98 | 123.48 | ▂▇▇▂▁ |
| GFR_MDRD_3 | 0 | 1.00 | 51.72 | 21.17 | 4.30 | 38.10 | 49.90 | 64.98 | 123.48 | ▂▇▇▂▁ |
| BKV_event_2 | 0 | 1.00 | 0.21 | 0.41 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | ▇▁▁▁▂ |
| GPL_BC_log2 | 0 | 1.00 | 0.11 | 1.42 | -3.86 | -0.74 | -0.10 | 0.85 | 4.95 | ▁▇▇▃▁ |
| MPL_BC_log2 | 0 | 1.00 | 2.00 | 1.56 | -5.53 | 1.09 | 2.04 | 2.94 | 5.42 | ▁▁▃▇▃ |
| GPE_dep_log2 | 0 | 1.00 | -2.28 | 0.65 | -3.64 | -2.67 | -2.39 | -2.01 | 0.42 | ▂▇▂▁▁ |
| GPE_ind_log2 | 0 | 1.00 | -2.92 | 0.73 | -3.87 | -3.41 | -3.16 | -2.71 | -0.03 | ▇▅▁▁▁ |
| MPE_dep_log2 | 0 | 1.00 | -2.40 | 0.67 | -3.61 | -2.93 | -2.46 | -2.00 | 0.06 | ▆▇▆▁▁ |
| MPE_ind_log2 | 0 | 1.00 | -3.03 | 0.57 | -3.90 | -3.45 | -3.15 | -2.70 | -0.57 | ▇▇▃▁▁ |
| male_sex | 0 | 1.00 | 0.62 | 0.49 | 0.00 | 0.00 | 1.00 | 1.00 | 1.00 | ▅▁▁▁▇ |
| HLA_MM | 35 | 0.80 | 4.37 | 1.45 | 0.00 | 4.00 | 5.00 | 5.00 | 6.00 | ▁▁▂▃▇ |
| male_sex_donor | 0 | 1.00 | 0.55 | 0.50 | 0.00 | 0.00 | 1.00 | 1.00 | 1.00 | ▆▁▁▁▇ |
| KDPI | 0 | 1.00 | 53.77 | 20.60 | 20.00 | 37.00 | 53.00 | 71.00 | 93.00 | ▇▇▆▆▅ |
| perfusion_event | 21 | 0.88 | 0.40 | 0.49 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▆ |
| CIT | 3 | 0.98 | 15.92 | 7.14 | 3.27 | 10.27 | 15.32 | 20.51 | 50.13 | ▆▇▃▁▁ |
| infliximab | 0 | 1.00 | 0.49 | 0.50 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▇ |
| rec_age | 0 | 1.00 | 53.15 | 10.49 | 27.00 | 45.00 | 54.00 | 61.00 | 73.00 | ▂▅▆▇▅ |
| HLAMMGE3 | 0 | 1.00 | 0.85 | 0.36 | 0.00 | 1.00 | 1.00 | 1.00 | 1.00 | ▂▁▁▁▇ |
| BKV_viremia_time | 0 | 1.00 | 693.92 | 471.35 | 22.00 | 196.00 | 735.00 | 952.00 | 1854.00 | ▇▇▅▃▁ |
| race_2 | 0 | 1.00 | 0.41 | 0.49 | 0.00 | 0.00 | 0.00 | 1.00 | 1.00 | ▇▁▁▁▆ |
| race_donor_2 | 0 | 1.00 | 0.62 | 0.49 | 0.00 | 0.00 | 1.00 | 1.00 | 1.00 | ▅▁▁▁▇ |
| age_donor | 1 | 0.99 | 40.33 | 14.23 | 4.00 | 31.75 | 42.50 | 50.00 | 69.00 | ▂▃▇▇▃ |
| CMV_IgG_rec | 0 | 1.00 | 0.66 | 0.47 | 0.00 | 0.00 | 1.00 | 1.00 | 1.00 | ▅▁▁▁▇ |
| de_novo_DSA | 0 | 1.00 | 0.06 | 0.24 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | ▇▁▁▁▁ |
| donor_type | 0 | 1.00 | 0.75 | 0.43 | 0.00 | 1.00 | 1.00 | 1.00 | 1.00 | ▂▁▁▁▇ |
4.3 Variables correlations
Is the missingness correlated with outcomes?
Open code
df2_corr <- data_model_priorImpute %>% mutate(
NA_perfusion_event = if_else(is.na(perfusion_event), 1, 0),
NA_HLA_MM = if_else(is.na(HLA_MM), 1, 0)
)
m1 <- glm(NA_perfusion_event ~ DGF, family = 'binomial', data = df2_corr)
summary(m1)
##
## Call:
## glm(formula = NA_perfusion_event ~ DGF, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.9169 0.2765 -6.932 0.00000000000415 ***
## DGF -0.2803 0.5115 -0.548 0.584
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.62 on 175 degrees of freedom
## AIC: 132.62
##
## Number of Fisher Scoring iterations: 4
m2 <- glm(NA_perfusion_event ~ infection_any, family = 'binomial', data = df2_corr)
summary(m2)
##
## Call:
## glm(formula = NA_perfusion_event ~ infection_any, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.01490 0.30731 -6.556 0.0000000000551 ***
## infection_any 0.02247 0.46979 0.048 0.962
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.93 on 175 degrees of freedom
## AIC: 132.93
##
## Number of Fisher Scoring iterations: 4
m3 <- glm(NA_perfusion_event ~ BKV_event_2, family = 'binomial', data = df2_corr)
summary(m2)
##
## Call:
## glm(formula = NA_perfusion_event ~ infection_any, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.01490 0.30731 -6.556 0.0000000000551 ***
## infection_any 0.02247 0.46979 0.048 0.962
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.93 on 175 degrees of freedom
## AIC: 132.93
##
## Number of Fisher Scoring iterations: 4
m4 <- glm(NA_perfusion_event ~ GFR_MDRD_3, family = 'binomial', data = df2_corr)
summary(m4)
##
## Call:
## glm(formula = NA_perfusion_event ~ GFR_MDRD_3, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.770427 0.608599 -2.909 0.00363 **
## GFR_MDRD_3 -0.004611 0.011209 -0.411 0.68080
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.76 on 175 degrees of freedom
## AIC: 132.76
##
## Number of Fisher Scoring iterations: 4
m5 <- glm(NA_perfusion_event ~ GFR_MDRD_2, family = 'binomial', data = df2_corr)
summary(m5)
##
## Call:
## glm(formula = NA_perfusion_event ~ GFR_MDRD_2, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.890831 0.629648 -3.003 0.00267 **
## GFR_MDRD_2 -0.002215 0.011400 -0.194 0.84592
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.89 on 175 degrees of freedom
## AIC: 132.89
##
## Number of Fisher Scoring iterations: 4
m6 <- glm(NA_perfusion_event ~ GFR_MDRD, family = 'binomial', data = df2_corr)
summary(m6)
##
## Call:
## glm(formula = NA_perfusion_event ~ GFR_MDRD, family = "binomial",
## data = df2_corr)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.533940 0.655266 -3.867 0.00011 ***
## GFR_MDRD 0.009888 0.011130 0.888 0.37433
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 128.93 on 176 degrees of freedom
## Residual deviance: 128.16 on 175 degrees of freedom
## AIC: 132.16
##
## Number of Fisher Scoring iterations: 4How much are variables inter-correlated?
Open code
corrplot(cor(df2_corr, use = "pairwise.complete.obs", method = 'spearman'),
method = 'square')
## Warning in cor(df2_corr, use = "pairwise.complete.obs", method = "spearman"):
## the standard deviation is zero
## Warning in cor(df2_corr, use = "pairwise.complete.obs", method = "spearman"):
## the standard deviation is zero
path <- "gitignore/figures/sup_figure_1"
if (!file.exists(path)) {
pdf(path, width = 12, height = 12)
corrplot(cor(df2_corr, use = "pairwise.complete.obs", method = 'spearman'),
method = 'square')
dev.off()
}4.4 Multiple imputation
Open code
set.seed(2025)
data_model_priorImpute <- data_model_priorImpute %>%
select(
-c(GFR_MDRD_2, GFR_MDRD_3)
)
init <- mice(data_model_priorImpute, maxit = 0)
init$method["perfusion_event"] <- "logreg"
data_imputed <- run(
expr = mice(
data_model_priorImpute,
method = init$method,
m = 80
),
path = "gitignore/run/data_imputed"
)
## connect data not used for imputation (imputed clinically)
imp_list <- complete(data_imputed, action = "all")
mean(data3$GFR_MDRD == imp_list[[1]]$GFR_MDRD)
## [1] 1
imp_long <- complete(data_imputed, action = "long", include = TRUE)
imp_list <- map(imp_list, ~
bind_cols(
.x,
data3 %>% select(
terminated_days, graft_failure, death_event,
GFR_MDRD_2, GFR_MDRD_3, GFR_days_2
)
)
)
imp_long <- imap_dfr(imp_list, ~
mutate(.x,
.imp = as.integer(.y),
.id = row_number()
)
)
orig_stub <- data_model_priorImpute %>% mutate(.imp = 0, .id = row_number())
imp_long <- bind_rows(orig_stub, imp_long)
data_imputed <- as.mids(imp_long)
## Get the 1st imputed dataset
data_first <- complete(data_imputed, 'all')[1]$`1`
## update data prior imputation
data_model_priorImpute <- data_model_priorImpute %>%
mutate(
GFR_MDRD_3 = data3$GFR_MDRD_3,
GFR_MDRD_2 = data3$GFR_MDRD_2
)4.4.1 Do we treat graft failure well?
We need to explore whether these with the graft failure within the 2-years period have clearly smaller eGFR
Open code
par(mfrow = c(1, 3))
plot(data_first$GFR_MDRD ~ factor(data_first$graft_failure))
plot(data_first$GFR_MDRD_2 ~ factor(data_first$graft_failure))
plot(data_first$GFR_MDRD_3 ~ factor(data_first$graft_failure))5 Data points of nAB levels
Open code
plotac <- "figure_1"
path <- "gitignore/figures"
cole <- c(
"#E89C20", "#803800",
"#4C60FF", "#001070"
)
data_model_priorImpute <- data_model_priorImpute %>%
mutate(
group = factor(if_else(infliximab == 1, "infliximab", "control")),
Group = case_when(
infliximab == 1 & DGF == 0 ~ "IFX_DGF-",
infliximab == 1 & DGF == 1 ~ "IFX_DGF+",
infliximab == 0 & DGF == 0 ~ "ctrl_DGF-",
infliximab == 0 & DGF == 1 ~ "ctrl_DGF+",
)
)
p1 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = GPL_BC_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
labs(
y = expression(log[2] ~ "(aCL IgG [" * mu * "g/ml])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
p2 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = MPL_BC_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
labs(
y = expression(log[2] ~ "(aCL IgM [" * mu * "g/ml])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
data_model_priorImpute <- data_model_priorImpute %>%
mutate(
group = factor(if_else(infliximab == 1, "infliximab", "control")),
Group = case_when(
infliximab == 1 & infection_any == 0 ~ "IFX_non-infected",
infliximab == 1 & infection_any == 1 ~ "IFX_infected",
infliximab == 0 & infection_any == 0 ~ "ctrl_non-infected",
infliximab == 0 & infection_any == 1 ~ "ctrl_infected",
)
)
p3 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = GPE_dep_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
# theme(axis.text.x = element_blank()) +
labs(
y = expression(log[2] ~ "(aPE IgG dep [OD])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
p4 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = GPE_ind_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
# theme(axis.text.x = element_blank()) +
labs(
y = expression(log[2] ~ "(aPE IgG ind [OD])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
p5 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = MPE_dep_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
# theme(axis.text.x = element_blank()) +
labs(
y = expression(log[2] ~ "(aPE IgM dep [OD])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
p6 <- data_model_priorImpute %>%
ggplot(aes(x = Group, y = MPE_ind_log2, color = Group)) +
geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
scale_color_manual(values = cole) +
# theme(axis.text.x = element_blank()) +
labs(
y = expression(log[2] ~ "(aPE IgM ind [OD])"),
x = NULL
) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none"
)
assign(
plotac,
cowplot::plot_grid(p1, p2, p3, p4, p5, p6,
labels = c("A", "B", "C", "D", "E", "F"),
ncol = 2, nrow = , rel_heights = c(1, 1.1, 1.1)
)
)
if (!file.exists(paste0(path, "/", plotac))) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 6,
height = 10
)
}
get(plotac)6 Unadjsuted effects
Definition of function
Open code
univar_mod <- function(dat,
outcome,
predictors,
family = "logistic",
level = 0.95,
rounding = 2
) {
N <- vector("double", length(predictors))
OR <- vector("double", length(predictors))
CI_L <- vector("double", length(predictors))
CI_U <- vector("double", length(predictors))
predictor <- vector("double", length(predictors))
for (i in 1:length(predictors)) {
data <- dat %>% dplyr::select(outcome,
all_of(unlist(strsplit(predictors[i], "\\*"))))
data <- na.omit(data)
N[i] <- nrow(data)
formula <- paste0(outcome, " ~ ", predictors[i])
if (family == "logistic") {
suppressMessages(suppressWarnings({
model <- glm(formula, data = data, family = "binomial"(link = "logit"))
OR[i] <- exp(coef(model)[length(coef(model))])
CI_L[i] <- exp(confint(model, level = level)[length(coef(model)), ])[1]
CI_U[i] <- exp(confint(model, level = level)[length(coef(model)), ])[2]
predictor[i] <- names(coef(model)[length(coef(model))])
result <- data.frame(
predictor,
OR = paste0(round(OR, rounding), ' [',round(CI_L, rounding), ', ',
round(CI_U, rounding),']'),
N
)
}))
} else if (family == "gaussian") {
suppressMessages(suppressWarnings({
model <- lm(formula, data = data)
OR[i] <- coef(model)[length(coef(model))]
CI_L[i] <- confint(model, level = level)[length(coef(model)), ][1]
CI_U[i] <- confint(model, level = level)[length(coef(model)), ][2]
predictor[i] <- names(coef(model)[length(coef(model))])
result <- data.frame(
predictor,
effect = paste0(round(OR, rounding), ' [',round(CI_L, rounding), ', ',
round(CI_U, rounding),']'),
N
)
}))
} else {
stop("incorrect family specification", call. = FALSE)
}
}
return(result)
}
preds <- c(
"infliximab",
"GPL_BC_log2", "MPL_BC_log2",
"GPE_dep_log2", "GPE_ind_log2",
"MPE_dep_log2", "MPE_ind_log2",
"male_sex", "HLA_MM", "male_sex_donor", "KDPI",
"perfusion_event", "CIT", "rec_age", "DGF",
"infliximab*GPL_BC_log2", "infliximab*MPL_BC_log2",
"infliximab*GPE_dep_log2", "infliximab*GPE_ind_log2",
"infliximab*MPE_dep_log2", "infliximab*MPE_ind_log2"
)
preds_DGF <- c(
"infliximab",
"GPL_BC_log2", "MPL_BC_log2",
"GPE_dep_log2", "GPE_ind_log2",
"MPE_dep_log2", "MPE_ind_log2",
"male_sex", "HLA_MM", "male_sex_donor", "KDPI",
"perfusion_event", "CIT", "rec_age",
"infliximab*GPL_BC_log2", "infliximab*MPL_BC_log2",
"infliximab*GPE_dep_log2", "infliximab*GPE_ind_log2",
"infliximab*MPE_dep_log2", "infliximab*MPE_ind_log2"
)6.1 DGF
Open code
kableExtra::kable(
univar_mod(dat = data_model_priorImpute,
outcome = 'DGF',
predictors = preds_DGF,
family = 'logistic',
rounding = 2
) %>% rename(
`(R)OR` = `OR`
)
)
## Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
## ℹ Please use `all_of()` or `any_of()` instead.
## # Was:
## data %>% select(outcome)
##
## # Now:
## data %>% select(all_of(outcome))
##
## See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.(R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
| predictor | (R)OR | N |
|---|---|---|
| infliximab | 0.86 [0.46, 1.6] | 177 |
| GPL_BC_log2 | 1.08 [0.86, 1.34] | 177 |
| MPL_BC_log2 | 1.2 [0.98, 1.5] | 177 |
| GPE_dep_log2 | 1 [0.61, 1.61] | 177 |
| GPE_ind_log2 | 1.02 [0.66, 1.55] | 177 |
| MPE_dep_log2 | 1.08 [0.67, 1.73] | 177 |
| MPE_ind_log2 | 0.96 [0.54, 1.64] | 177 |
| male_sex | 2.2 [1.13, 4.43] | 177 |
| HLA_MM | 1.25 [0.97, 1.65] | 142 |
| male_sex_donor | 1.08 [0.58, 2.04] | 177 |
| KDPI | 1.01 [0.99, 1.02] | 177 |
| perfusion_event | 0.91 [0.46, 1.78] | 156 |
| CIT | 1.07 [1.02, 1.12] | 174 |
| rec_age | 0.99 [0.96, 1.02] | 177 |
| infliximab:GPL_BC_log2 | 1.84 [1.15, 3.02] | 177 |
| infliximab:MPL_BC_log2 | 1.52 [0.97, 2.43] | 177 |
| infliximab:GPE_dep_log2 | 1 [0.38, 2.62] | 177 |
| infliximab:GPE_ind_log2 | 1.04 [0.43, 2.45] | 177 |
| infliximab:MPE_dep_log2 | 2.32 [0.89, 6.21] | 177 |
| infliximab:MPE_ind_log2 | 1.59 [0.52, 5.04] | 177 |
6.2 GFR
Open code
kableExtra::kable(
univar_mod(dat = data_model_priorImpute,
outcome = 'GFR_MDRD_3',
predictors = preds,
family = 'gaussian',
rounding = 1
)
)Effect [95% confidennce interval] is shown and represents the estimated change in eGFR per one-unit increase in the predictor. For interaction terms, the effect quantifies the difference in the infliximab effect on eGFR at a given natural antibody (nAb) level vs its effect when the nAb level is halved. A 95% confidence interval including 0 suggests no significant modification of the infliximab effect by nAb levels. N: number of observations.
| predictor | effect | N |
|---|---|---|
| infliximab | -2.7 [-9, 3.6] | 177 |
| GPL_BC_log2 | 0.9 [-1.4, 3.1] | 177 |
| MPL_BC_log2 | -0.3 [-2.4, 1.7] | 177 |
| GPE_dep_log2 | 1.2 [-3.6, 6] | 177 |
| GPE_ind_log2 | -3.3 [-7.6, 0.9] | 177 |
| MPE_dep_log2 | 3.1 [-1.6, 7.8] | 177 |
| MPE_ind_log2 | 0.8 [-4.7, 6.3] | 177 |
| male_sex | 0 [-6.5, 6.5] | 177 |
| HLA_MM | -2.8 [-5.2, -0.5] | 142 |
| male_sex_donor | 4.5 [-1.8, 10.8] | 177 |
| KDPI | -0.3 [-0.4, -0.1] | 177 |
| perfusion_event | -7 [-13.7, -0.4] | 156 |
| CIT | 0.2 [-0.2, 0.7] | 174 |
| rec_age | -0.1 [-0.4, 0.2] | 177 |
| DGF | -14 [-20.3, -7.7] | 177 |
| infliximab:GPL_BC_log2 | -5.4 [-9.9, -0.8] | 177 |
| infliximab:MPL_BC_log2 | -3.7 [-7.8, 0.4] | 177 |
| infliximab:GPE_dep_log2 | 0.8 [-8.9, 10.5] | 177 |
| infliximab:GPE_ind_log2 | 3 [-5.7, 11.6] | 177 |
| infliximab:MPE_dep_log2 | -4.3 [-13.9, 5.3] | 177 |
| infliximab:MPE_ind_log2 | 1.9 [-9.3, 13.1] | 177 |
6.3 Infection
Open code
kableExtra::kable(
univar_mod(dat = data_model_priorImpute,
outcome = 'infection_any',
predictors = preds,
family = 'logistic'
)%>% rename(
`(R)OR` = `OR`
)
)(R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
| predictor | (R)OR | N |
|---|---|---|
| infliximab | 1.11 [0.61, 2.02] | 177 |
| GPL_BC_log2 | 0.91 [0.73, 1.12] | 177 |
| MPL_BC_log2 | 0.94 [0.77, 1.14] | 177 |
| GPE_dep_log2 | 0.68 [0.42, 1.09] | 177 |
| GPE_ind_log2 | 0.66 [0.41, 1.02] | 177 |
| MPE_dep_log2 | 0.84 [0.53, 1.32] | 177 |
| MPE_ind_log2 | 1.09 [0.64, 1.84] | 177 |
| male_sex | 0.98 [0.53, 1.82] | 177 |
| HLA_MM | 0.88 [0.69, 1.11] | 142 |
| male_sex_donor | 0.87 [0.48, 1.58] | 177 |
| KDPI | 1.02 [1, 1.04] | 177 |
| perfusion_event | 0.75 [0.39, 1.43] | 156 |
| CIT | 0.93 [0.89, 0.98] | 174 |
| rec_age | 1 [0.97, 1.02] | 177 |
| DGF | 1.18 [0.63, 2.2] | 177 |
| infliximab:GPL_BC_log2 | 1.23 [0.79, 1.92] | 177 |
| infliximab:MPL_BC_log2 | 1.22 [0.82, 1.83] | 177 |
| infliximab:GPE_dep_log2 | 0.35 [0.12, 0.94] | 177 |
| infliximab:GPE_ind_log2 | 0.31 [0.1, 0.83] | 177 |
| infliximab:MPE_dep_log2 | 0.49 [0.19, 1.23] | 177 |
| infliximab:MPE_ind_log2 | 1 [0.35, 2.9] | 177 |
6.4 BKV
Open code
kableExtra::kable(
univar_mod(dat = data_model_priorImpute,
outcome = 'BKV_event_2',
predictors = preds,
family = 'logistic',
rounding = 2
) %>% rename(
`(R)OR` = `OR`)
)(R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
| predictor | (R)OR | N |
|---|---|---|
| infliximab | 2.39 [1.15, 5.18] | 177 |
| GPL_BC_log2 | 0.83 [0.63, 1.07] | 177 |
| MPL_BC_log2 | 1.12 [0.89, 1.44] | 177 |
| GPE_dep_log2 | 0.72 [0.39, 1.27] | 177 |
| GPE_ind_log2 | 1.01 [0.59, 1.6] | 177 |
| MPE_dep_log2 | 1.13 [0.66, 1.93] | 177 |
| MPE_ind_log2 | 1.22 [0.65, 2.2] | 177 |
| male_sex | 1.71 [0.8, 3.84] | 177 |
| HLA_MM | 1.12 [0.84, 1.55] | 142 |
| male_sex_donor | 0.38 [0.18, 0.79] | 177 |
| KDPI | 0.99 [0.98, 1.01] | 177 |
| perfusion_event | 1.28 [0.57, 2.82] | 156 |
| CIT | 0.95 [0.89, 1] | 174 |
| rec_age | 1.03 [0.99, 1.06] | 177 |
| DGF | 1.36 [0.64, 2.84] | 177 |
| infliximab:GPL_BC_log2 | 1.34 [0.77, 2.41] | 177 |
| infliximab:MPL_BC_log2 | 1.1 [0.65, 1.86] | 177 |
| infliximab:GPE_dep_log2 | 1.57 [0.44, 6.14] | 177 |
| infliximab:GPE_ind_log2 | 0.49 [0.17, 1.33] | 177 |
| infliximab:MPE_dep_log2 | 1 [0.31, 3.22] | 177 |
| infliximab:MPE_ind_log2 | 1.37 [0.4, 5.26] | 177 |
7 DGF models
7.1 DGF by GPL_BC
7.1.1 Priors
Open code
# function to get prior
create_prior <- function(var, sigma, class = "b", coef = NULL) {
set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = coef)
}
scaling_unit <- 17.1.1.1 Main effects model
Open code
priors_main <- c(
create_prior("GPL_BC_log2",
2 / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
coef = "GPL_BC_log2"
),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4,
coef = "male_sex"
),
create_prior("perfusion_event",
4,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"
),
create_prior("infliximab",
4,
coef = "infliximab"
),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
class = "Intercept"
)
)7.1.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4,
coef = "male_sex"),
create_prior("perfusion_event",
4,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"),
create_prior("infliximab",
4,
coef = "infliximab"),
set_prior("student_t(3, 0, 0.6)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 0.3)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
class = "Intercept")
)7.1.2 Models
7.1.2.1 Main effects models
Open code
model_dgf_GPL_BC_main <- run(
expr = brm_multiple(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
GPL_BC_log2,
family = bernoulli(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_GPL_BC_main",
reuse = TRUE
)
summary(model_dgf_GPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -0.75 0.48 -1.70 0.18 1.01 18087 26121
## male_sex 0.81 0.38 0.07 1.58 1.01 35270 27169
## Irec_ageM50 -0.02 0.02 -0.05 0.01 1.01 35275 27008
## male_sex_donor 0.10 0.37 -0.62 0.83 1.01 35510 27598
## IKDPIM50 0.01 0.01 -0.01 0.02 1.01 36654 26896
## ICITM15 0.08 0.03 0.02 0.13 1.02 11475 27045
## IHLA_MMM5 0.26 0.13 0.01 0.53 1.06 3602 18106
## perfusion_event -0.65 0.40 -1.45 0.13 1.06 3524 13012
## infliximab -0.33 0.35 -1.04 0.37 1.01 37331 27918
## GPL_BC_log2 0.05 0.13 -0.20 0.29 1.01 37266 27873
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_GPL_BC_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 1.41170525720746) b GPL_BC_log2
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.667829372575656, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_dgf_GPL_BC_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 2.25 | 1.07 | 4.87 |
| Irec_ageM50 | 0.98 | 0.95 | 1.01 |
| male_sex_donor | 1.11 | 0.54 | 2.28 |
| IKDPIM50 | 1.01 | 0.99 | 1.02 |
| ICITM15 | 1.08 | 1.02 | 1.14 |
| IHLA_MMM5 | 1.30 | 1.01 | 1.70 |
| perfusion_event | 0.52 | 0.23 | 1.14 |
| infliximab | 0.72 | 0.35 | 1.45 |
| GPL_BC_log2 | 1.05 | 0.81 | 1.34 |
7.1.2.2 Non-linear interaction model
Open code
model_dgf_GPL_BC_interaction_NL <- run(
expr = brm_multiple(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = bernoulli(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_GPL_BC_interaction_NL",
reuse = TRUE
)
summary(model_dgf_GPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 0.83 0.61 0.05 2.95 1.02
## sds(sGPL_BC_log2infliximab_1) 0.23 0.21 0.01 1.16 1.01
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 14045 12820
## sds(sGPL_BC_log2infliximab_1) 27968 14350
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept -0.88 0.49 -1.87 0.07 1.02 14612
## male_sex 0.97 0.40 0.20 1.80 1.01 35062
## Irec_ageM50 -0.02 0.02 -0.06 0.01 1.01 34006
## male_sex_donor 0.29 0.39 -0.47 1.06 1.01 34337
## IKDPIM50 0.01 0.01 -0.01 0.03 1.01 34534
## ICITM15 0.08 0.03 0.03 0.14 1.02 8750
## IHLA_MMM5 0.31 0.14 0.05 0.60 1.06 3297
## perfusion_event -0.75 0.43 -1.61 0.07 1.08 2768
## infliximab 0.02 3.90 -7.66 7.65 1.02 12394
## sGPL_BC_log2_1 -1.27 1.52 -4.37 2.91 1.01 19570
## sGPL_BC_log2:infliximab_1 2.30 2.41 -2.36 7.02 1.02 13785
## sGPL_BC_log2:infliximab_2 -2.66 1.62 -5.80 0.53 1.01 14601
## Tail_ESS
## Intercept 29212
## male_sex 26720
## Irec_ageM50 27092
## male_sex_donor 26886
## IKDPIM50 27506
## ICITM15 25453
## IHLA_MMM5 11332
## perfusion_event 9621
## infliximab 18177
## sGPL_BC_log2_1 15385
## sGPL_BC_log2:infliximab_1 20359
## sGPL_BC_log2:infliximab_2 22043
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_GPL_BC_interaction_NL)
## prior class
## (flat) b
## normal(0, 0.280307006032291) b
## normal(0, 1.38219051128263) b
## normal(0, 0.0970980394231448) b
## normal(0, 4) b
## normal(0, 0.190589762164436) b
## normal(0, 4) b
## normal(0, 4) b
## normal(0, 4) b
## (flat) b
## (flat) b
## (flat) b
## normal(-0.667829372575656, 10) Intercept
## student_t(3, 0, 2.5) sds
## student_t(3, 0, 0.6) sds
## student_t(3, 0, 0.3) sds
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## user
## user
tr2 <- round(exp(fixef(model_dgf_GPL_BC_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)
antibody_seq <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
`male_sex` = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get odds ratio for infliximab effect across antibody values
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
exp((log(prediction$p95) - log(prediction$p05))/scaling_unit),
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| (R)OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 2.64 | 1.23 | 6.02 |
| Irec_ageM50 | 0.98 | 0.94 | 1.01 |
| male_sex_donor | 1.34 | 0.62 | 2.88 |
| IKDPIM50 | 1.01 | 0.99 | 1.03 |
| ICITM15 | 1.09 | 1.03 | 1.15 |
| IHLA_MMM5 | 1.36 | 1.05 | 1.83 |
| perfusion_event | 0.47 | 0.20 | 1.07 |
| infliximab:GPL_BC_log2 | 46.56 | 4.36 | 610.02 |
7.1.3 Visualisation
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_dgf_GPL_BC_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control"))) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 1),
breaks = c(seq(0, 1, by = 0.2))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), y = "DGF risk") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text = element_text(size = 10),
axis.title = element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 0),
aes(x = GPL_BC_log2),
sides = "b",
color = "black",
linewidth = 0.12,
inherit.aes = FALSE
) +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 1),
aes(x = GPL_BC_log2),
sides = "t",
color = "black",
linewidth = 0.12,
inherit.aes = FALSE
) +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", linewidth = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.801668 2.531821
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (logit(tr[, c(ncol(tr)/2)]) - logit(tr[, c(1)]))
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = exp(b_GPL_BC_log2),
infliximab = exp(b_GPL_BC_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% 0.1 2.0
## 97.5% 1.1 91.2
## 50% 0.3 12.3
## 0.1% 0.0 0.7
## 99.9% 2.5 346.3
xpos <- 323
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect (OR) of aCL IgG increase (p05 to p95) on DGF',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(1/600, 1800)) +
scale_x_continuous(transform = 'log2',
breaks = c(1/512, 1/64, 1/8, 1, 8, 64, 512),
labels = c("1/512", "1/64", "1/8", "1", "8", "64", "512")) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -1.8016683 -0.7449060 -0.1046076 0.8504991 2.5318211
2**antibody_seq
## 5% 25% 50% 75% 95%
## 0.2868427 0.5967067 0.9300579 1.8031246 5.7830122
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## p05 p25 p50 p75 p95
## 2.5% 0.03 0.13 0.27 0.60 1.38
## 97.5% 0.49 0.80 1.25 3.22 30.32
## 50% 0.13 0.34 0.59 1.37 6.24
## 0.1% 0.01 0.07 0.17 0.37 0.60
## 99.9% 1.02 1.28 1.93 5.41 82.13
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on DGF risk (odds ratio)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(1/300, 1150)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
scale_x_continuous(transform = 'log2',
breaks = c(xseq),
labels = c("1/64", "1/8", "1", "8", "64", '512')) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Odds ratio: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Odds ratio: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Odds ratio: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 7.1.3.1 Figure merged
Open code
plotac <- 'figure_2'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}7.2 DGF by MPL_BC
7.2.1 Priors
7.2.1.1 Main effects model
Open code
priors_main <- c(
create_prior("IMPL_BC_log2M2",
2 / sd(data_model_priorImpute$MPL_BC_log2, na.rm = TRUE),
coef = "IMPL_BC_log2M2"
),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4,
coef = "male_sex"
),
create_prior("perfusion_event",
4,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"
),
create_prior("infliximab",
4,
coef = "infliximab"
),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
class = "Intercept"
)
)7.2.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4,
coef = "male_sex"),
create_prior("perfusion_event",
4,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"),
create_prior("infliximab",
4,
coef = "infliximab"),
set_prior("student_t(3, 0, 0.6)", class = "sds",
coef = 's(I(MPL_BC_log2 - 2), bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 0.3)", class = "sds",
coef = 's(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
class = "Intercept")
)7.2.2 Models
7.2.2.1 Main effects models
Open code
set.seed(2025)
model_dgf_MPL_BC_main <- run(
expr = brm_multiple(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
I(MPL_BC_log2 - 2),
family = bernoulli(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_MPL_BC_main",
reuse = TRUE
)
summary(model_dgf_MPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(MPL_BC_log2 - 2)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -0.88 0.48 -1.85 0.05 1.02 14414 25568
## male_sex 0.89 0.39 0.14 1.69 1.01 35387 28013
## Irec_ageM50 -0.02 0.02 -0.06 0.01 1.01 37218 27652
## male_sex_donor 0.14 0.37 -0.59 0.87 1.01 36459 27773
## IKDPIM50 0.01 0.01 -0.01 0.02 1.01 36554 27839
## ICITM15 0.07 0.03 0.02 0.13 1.02 11114 26679
## IHLA_MMM5 0.25 0.13 -0.00 0.52 1.06 3433 12047
## perfusion_event -0.61 0.41 -1.45 0.19 1.07 3180 11578
## infliximab -0.24 0.36 -0.97 0.48 1.01 35927 27005
## IMPL_BC_log2M2 0.20 0.12 -0.04 0.44 1.01 35829 26440
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_MPL_BC_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 1.27934317633706) b IMPL_BC_log2M2
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.667829372575656, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_dgf_MPL_BC_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgM (MPL_BC_log2), on delayed graft function (DGF), without interaction terms. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 2.44 | 1.15 | 5.40 |
| Irec_ageM50 | 0.98 | 0.95 | 1.01 |
| male_sex_donor | 1.15 | 0.56 | 2.40 |
| IKDPIM50 | 1.01 | 0.99 | 1.02 |
| ICITM15 | 1.08 | 1.02 | 1.14 |
| IHLA_MMM5 | 1.28 | 1.00 | 1.69 |
| perfusion_event | 0.55 | 0.23 | 1.21 |
| infliximab | 0.79 | 0.38 | 1.61 |
| IMPL_BC_log2M2 | 1.22 | 0.96 | 1.56 |
7.2.2.2 Non-linear interaction model
Open code
set.seed(2025)
model_dgf_MPL_BC_interaction_NL <- run(
expr = brm_multiple(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(I(MPL_BC_log2-2), bs = 'ps', k = 5) +
s(I(MPL_BC_log2-2), by = infliximab, bs = 'ps', k = 5),
family = bernoulli(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_MPL_BC_interaction_NL",
reuse = TRUE
)
summary(model_dgf_MPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(MPL_BC_log2 - 2), bs = "ps", k = 5) + s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIMPL_BC_log2M2_1) 0.42 0.38 0.02 1.87 1.01
## sds(sIMPL_BC_log2M2infliximab_1) 0.22 0.20 0.01 1.07 1.00
## Bulk_ESS Tail_ESS
## sds(sIMPL_BC_log2M2_1) 22288 15370
## sds(sIMPL_BC_log2M2infliximab_1) 31518 16326
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept -0.88 0.49 -1.86 0.05 1.02 18653
## male_sex 0.90 0.39 0.14 1.70 1.01 36356
## Irec_ageM50 -0.03 0.02 -0.06 0.01 1.01 34817
## male_sex_donor 0.23 0.38 -0.51 1.00 1.01 36879
## IKDPIM50 0.01 0.01 -0.01 0.02 1.01 35932
## ICITM15 0.07 0.03 0.02 0.13 1.02 15639
## IHLA_MMM5 0.25 0.13 0.00 0.53 1.06 3408
## perfusion_event -0.58 0.42 -1.42 0.23 1.08 2747
## infliximab -0.08 3.95 -7.77 7.71 1.02 12781
## sIMPL_BC_log2M2_1 0.36 1.27 -2.13 3.27 1.01 23892
## sIMPL_BC_log2M2:infliximab_1 1.13 2.95 -4.69 6.87 1.02 13362
## sIMPL_BC_log2M2:infliximab_2 -1.55 1.23 -4.00 0.82 1.01 16755
## Tail_ESS
## Intercept 28581
## male_sex 25744
## Irec_ageM50 26590
## male_sex_donor 27123
## IKDPIM50 27389
## ICITM15 24626
## IHLA_MMM5 11220
## perfusion_event 9277
## infliximab 17925
## sIMPL_BC_log2M2_1 20627
## sIMPL_BC_log2M2:infliximab_1 18672
## sIMPL_BC_log2M2:infliximab_2 23546
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_MPL_BC_interaction_NL)
## prior class
## (flat) b
## normal(0, 0.280307006032291) b
## normal(0, 1.38219051128263) b
## normal(0, 0.0970980394231448) b
## normal(0, 4) b
## normal(0, 0.190589762164436) b
## normal(0, 4) b
## normal(0, 4) b
## normal(0, 4) b
## (flat) b
## (flat) b
## (flat) b
## normal(-0.667829372575656, 10) Intercept
## student_t(3, 0, 2.5) sds
## student_t(3, 0, 0.6) sds
## student_t(3, 0, 0.3) sds
## coef group resp dpar nlpar
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sIMPL_BC_log2M2_1
## sIMPL_BC_log2M2:infliximab_1
## sIMPL_BC_log2M2:infliximab_2
##
##
## s(I(MPL_BC_log2 - 2), bs = "ps", k = 5)
## s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## 0 default
## 0 user
## 0 user
tr2 <- round(exp(fixef(model_dgf_MPL_BC_interaction_NL, robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)
antibody_seq <- quantile(data_model_priorImpute$MPL_BC_log2, probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_MPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get odds ratio for infliximab effect across antibody values
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_MPL_BC_log2_int <- quantile(exp((log(prediction$p95) - log(prediction$p05))/scaling_unit),
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_MPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:MPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)MPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| (R)OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 2.47 | 1.14 | 5.49 |
| Irec_ageM50 | 0.98 | 0.94 | 1.01 |
| male_sex_donor | 1.26 | 0.60 | 2.71 |
| IKDPIM50 | 1.01 | 0.99 | 1.02 |
| ICITM15 | 1.08 | 1.02 | 1.14 |
| IHLA_MMM5 | 1.29 | 1.00 | 1.70 |
| perfusion_event | 0.56 | 0.24 | 1.26 |
| infliximab:MPL_BC_log2 | 12.18 | 1.07 | 165.59 |
7.2.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$MPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_dgf_MPL_BC_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
MPL_BC_log2 = data_prediction$MPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control"))) %>%
ggplot(aes(x = MPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 1),
breaks = c(seq(0, 1, by = 0.2))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
labs(x = expression(log[2]~"(aCL IgM ["*mu*"g/ml])"), y = "DGF risk") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 0),
aes(x = MPL_BC_log2),
sides = "b",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 1),
aes(x = MPL_BC_log2),
sides = "t",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -0.3963058 4.5810923
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_MPL_BC_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)]))
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))
post_fix <- data.frame(
b_MPL_BC_log2 = tr_ctrl,
b_MPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = exp(b_MPL_BC_log2),
infliximab = exp(b_MPL_BC_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% 0.2 1.8
## 97.5% 4.8 82.4
## 50% 0.9 11.1
## 0.1% 0.1 0.7
## 99.9% 13.3 332.6
xpos <- 323
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect (OR) of aCL IgM (p05 to p95) on DGF",
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(1/600, 1800)) +
scale_x_continuous(transform = 'log2',
breaks = c(1/512, 1/64, 1/8, 1, 8, 64, 512),
labels = c("1/512", "1/64", "1/8", "1", "8", "64", "512")) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -0.3963058 1.0933124 2.0432905 2.9421729 4.5810923
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_MPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## p05 p25 p50 p75 p95
## 2.5% 0.05 0.19 0.37 0.52 0.66
## 97.5% 0.94 1.15 1.61 2.85 12.59
## 50% 0.23 0.48 0.77 1.22 2.79
## 0.1% 0.02 0.11 0.24 0.32 0.28
## 99.9% 2.07 1.85 2.43 4.75 31.56
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'MPL_BC_percentile') %>%
ggplot(aes(y = MPL_BC_percentile, x = value, fill = MPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on DGF risk (odds ratio)",
y = 'Percentile of aCL IgM value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(1/300, 1000)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
scale_x_continuous(transform = 'log2',
breaks = c(xseq),
labels = c("1/64", "1/8", "1", "8", "64", '512')) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Odds ratio: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Odds ratio: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Odds ratio: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 7.2.3.1 Figure merged
Open code
plotac <- 'sup_figure_3'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}8 Infection models
8.1 Infection by GPE_dep
8.1.1 Priors
8.1.1.1 Main effects model
Open code
priors_main <- c(
create_prior("IGPE_dep_log2P2",
2 / sd(data_model_priorImpute$GPE_dep_log2, na.rm = TRUE),
coef = "IGPE_dep_log2P2"
),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4,
coef = "male_sex"
),
create_prior("perfusion_event",
4,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"
),
create_prior("infliximab",
4,
coef = "infliximab"
),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
class = "Intercept"
)
)8.1.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4,
coef = "male_sex"),
create_prior("perfusion_event",
4,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"),
create_prior("infliximab",
4,
coef = "infliximab"),
set_prior("student_t(3, 0, 0.6)", class = "sds",
coef = 's(I(GPE_dep_log2 + 2), bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 0.3)", class = "sds",
coef = 's(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
class = "Intercept")
)8.1.2 Models
8.1.2.1 Main effects models
Open code
model_infection_any_GPE_dep_main <- run(
expr = brm_multiple(
infection_any ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
I(GPE_dep_log2 + 2),
family = bernoulli(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_infection_any_GPE_dep_main",
reuse = TRUE
)
summary(model_infection_any_GPE_dep_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(GPE_dep_log2 + 2)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -1.20 0.47 -2.17 -0.30 1.03 8357 25111
## male_sex 0.28 0.36 -0.43 1.01 1.01 35581 26492
## Irec_ageM50 -0.03 0.02 -0.06 0.01 1.01 34812 27578
## male_sex_donor 0.22 0.36 -0.48 0.92 1.01 35747 27955
## IKDPIM50 0.03 0.01 0.02 0.05 1.00 31156 26870
## ICITM15 -0.10 0.03 -0.16 -0.04 1.01 21925 27001
## IHLA_MMM5 -0.27 0.13 -0.53 -0.04 1.05 3743 18243
## perfusion_event -0.04 0.40 -0.83 0.74 1.07 2925 12861
## infliximab 0.40 0.35 -0.27 1.09 1.01 36151 28346
## IGPE_dep_log2P2 -0.55 0.28 -1.11 -0.02 1.01 35008 27707
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_infection_any_GPE_dep_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 3.05433848490195) b IGPE_dep_log2P2
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.307484699747961, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_infection_any_GPE_dep_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)infliximab treatment and log2-transformed co-factor-dependent phosphatidylethanolamine IgG (GPE_dep_log2), on infection risk, without interaction terms. The odds ratio (OR) represents the estimated change in the odds of infection per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.32 | 0.65 | 2.76 |
| Irec_ageM50 | 0.97 | 0.94 | 1.01 |
| male_sex_donor | 1.24 | 0.62 | 2.51 |
| IKDPIM50 | 1.03 | 1.02 | 1.05 |
| ICITM15 | 0.91 | 0.86 | 0.96 |
| IHLA_MMM5 | 0.76 | 0.59 | 0.97 |
| perfusion_event | 0.96 | 0.44 | 2.09 |
| infliximab | 1.49 | 0.77 | 2.97 |
| IGPE_dep_log2P2 | 0.58 | 0.33 | 0.98 |
8.1.2.2 Non-linear interaction model
Open code
model_infection_any_GPE_dep_interaction_NL <- run(
expr = brm_multiple(
infection_any ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(I(GPE_dep_log2+2), bs = 'ps', k = 5) +
s(I(GPE_dep_log2+2), by = infliximab, bs = 'ps', k = 5),
family = bernoulli(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_infection_any_GPE_dep_interaction_NL",
reuse = TRUE
)
summary(model_infection_any_GPE_dep_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Warning: There were 1 divergent transitions after warmup. Increasing
## adapt_delta above 0.95 may help. See
## http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
## Family: bernoulli
## Links: mu = logit
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(GPE_dep_log2 + 2), bs = "ps", k = 5) + s(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIGPE_dep_log2P2_1) 0.39 0.36 0.02 1.78 1.01
## sds(sIGPE_dep_log2P2infliximab_1) 0.22 0.21 0.01 1.20 1.00
## Bulk_ESS Tail_ESS
## sds(sIGPE_dep_log2P2_1) 23011 16212
## sds(sIGPE_dep_log2P2infliximab_1) 29739 16611
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept -0.96 0.47 -1.89 -0.05 1.02
## male_sex 0.20 0.37 -0.53 0.93 1.01
## Irec_ageM50 -0.03 0.02 -0.06 0.01 1.01
## male_sex_donor 0.15 0.36 -0.57 0.87 1.01
## IKDPIM50 0.03 0.01 0.01 0.05 1.01
## ICITM15 -0.10 0.03 -0.16 -0.04 1.01
## IHLA_MMM5 -0.27 0.12 -0.53 -0.03 1.05
## perfusion_event 0.02 0.41 -0.77 0.83 1.07
## infliximab 0.01 3.96 -7.77 7.88 1.02
## sIGPE_dep_log2P2_1 -0.01 1.21 -2.46 2.72 1.01
## sIGPE_dep_log2P2:infliximab_1 -1.54 2.40 -6.31 3.14 1.02
## sIGPE_dep_log2P2:infliximab_2 1.73 1.92 -2.01 5.47 1.01
## Bulk_ESS Tail_ESS
## Intercept 10823 27696
## male_sex 35504 26209
## Irec_ageM50 34966 27068
## male_sex_donor 36837 27583
## IKDPIM50 33808 25857
## ICITM15 17002 25866
## IHLA_MMM5 3867 19114
## perfusion_event 2911 11736
## infliximab 12595 17936
## sIGPE_dep_log2P2_1 24856 21147
## sIGPE_dep_log2P2:infliximab_1 14000 20327
## sIGPE_dep_log2P2:infliximab_2 14554 20883
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_infection_any_GPE_dep_interaction_NL)
## prior class
## (flat) b
## normal(0, 0.280307006032291) b
## normal(0, 1.38219051128263) b
## normal(0, 0.0970980394231448) b
## normal(0, 4) b
## normal(0, 0.190589762164436) b
## normal(0, 4) b
## normal(0, 4) b
## normal(0, 4) b
## (flat) b
## (flat) b
## (flat) b
## normal(-0.307484699747961, 10) Intercept
## student_t(3, 0, 2.5) sds
## student_t(3, 0, 0.6) sds
## student_t(3, 0, 0.3) sds
## coef group resp dpar
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sIGPE_dep_log2P2_1
## sIGPE_dep_log2P2:infliximab_1
## sIGPE_dep_log2P2:infliximab_2
##
##
## s(I(GPE_dep_log2 + 2), bs = "ps", k = 5)
## s(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5)
## nlpar lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## 0 default
## 0 user
## 0 user
tr2 <- round(exp(fixef(model_infection_any_GPE_dep_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)]), 3)
antibody_seq <- quantile(data_model_priorImpute$GPE_dep_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_dep_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_dep_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get odds ratio for infliximab effect across antibody values
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPE_dep_log2_int <- quantile(
exp((log(prediction$p95) - log(prediction$p05))/scaling_unit),
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPE_dep_log2_int, 3))
row.names(tr2)[8] <- 'infliximab:GPE_dep_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)GPE_dep_log2) and infliximab treatment on infection risk, while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of aPE-dep IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| (R)OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.220 | 0.590 | 2.539 |
| Irec_ageM50 | 0.972 | 0.938 | 1.006 |
| male_sex_donor | 1.166 | 0.568 | 2.392 |
| IKDPIM50 | 1.034 | 1.015 | 1.054 |
| ICITM15 | 0.905 | 0.851 | 0.957 |
| IHLA_MMM5 | 0.763 | 0.589 | 0.969 |
| perfusion_event | 1.018 | 0.463 | 2.299 |
| infliximab:GPE_dep_log2 | 0.097 | 0.008 | 0.995 |
8.1.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$GPE_dep_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_dep_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_infection_any_GPE_dep_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPE_dep_log2 = data_prediction$GPE_dep_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control"))) %>%
ggplot(aes(x = GPE_dep_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 1),
breaks = c(seq(0, 1, by = 0.2))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
labs(x = expression(log[2]~"(aPE IgG dep [OD])"), y = "Infection risk") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 0),
aes(x = GPE_dep_log2),
sides = "b",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 1),
aes(x = GPE_dep_log2),
sides = "t",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -3.134163 -1.039488
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_dep_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_dep_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)]))
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))
post_fix <- data.frame(
b_GPE_dep_log2 = tr_ctrl,
b_GPE_dep_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = exp(b_GPE_dep_log2),
infliximab = exp(b_GPE_dep_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## control infliximab
## 2.5% 0.18 0.01
## 97.5% 4.70 0.48
## 50% 0.91 0.09
## 0.1% 0.07 0.00
## 99.9% 12.90 1.23
xpos <- 323
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect (OR) of aPE IgG dep increase (p05 to p95) on infection',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(1/600, 1800)) +
scale_x_continuous(transform = 'log2',
breaks = c(1/512, 1/64, 1/8, 1, 8, 64, 512),
labels = c("1/512", "1/64", "1/8", "1", "8", "64", "512")) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -3.134163 -2.666576 -2.392137 -2.005782 -1.039488
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_dep_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_dep_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>% round(3)
CIS
## p05 p25 p50 p75 p95
## 2.5% 1.147 1.005 0.824 0.492 0.066
## 97.5% 12.692 5.193 3.466 2.425 1.754
## 50% 3.731 2.260 1.676 1.097 0.361
## 0.1% 0.588 0.657 0.561 0.310 0.023
## 99.9% 24.985 8.400 5.455 3.839 4.295
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPE_dep_percentile') %>%
ggplot(aes(y = GPE_dep_percentile, x = value, fill = GPE_dep_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on infection risk (odds ratio)",
y = 'Percentile of aPE IgG dep value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(1/300, 1000)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
scale_x_continuous(transform = 'log2',
breaks = c(xseq),
labels = c("1/64", "1/8", "1", "8", "64", '512')) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Odds ratio: ", round(CIS[3,5], 2)),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Odds ratio: ", round(CIS[3,4], 2)),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Odds ratio: ", round(CIS[3,3], 2)),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Odds ratio: ", round(CIS[3,2],2 )),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Odds ratio: ", round(CIS[3,1], 2)),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", round(CIS[1,5], 2), ", ",
round(CIS[2,5], 2), "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", round(CIS[1,4], 2), ", ",
round(CIS[2,4], 2), "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", round(CIS[1,3], 2), ", ",
round(CIS[2,3], 2), "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", round(CIS[2,2], 2), "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", round(CIS[1,1], 2), ", ",
round(CIS[2,1], 2), "]"),
color = cole[1] ) 8.1.3.1 Figure merged
Open code
plotac <- 'sup_figure_10'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}8.2 Infection by GPE_ind
8.2.1 Priors
8.2.1.1 Main effects model
Open code
priors_main <- c(
create_prior("IGPE_ind_log2P3",
2 / sd(data_model_priorImpute$GPE_ind_log2, na.rm = TRUE),
coef = "IGPE_ind_log2P3"
),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4,
coef = "male_sex"
),
create_prior("perfusion_event",
4,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"
),
create_prior("infliximab",
4,
coef = "infliximab"
),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
class = "Intercept"
)
)8.2.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4,
coef = "male_sex"),
create_prior("perfusion_event",
4,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"),
create_prior("infliximab",
4,
coef = "infliximab"),
set_prior("student_t(3, 0, 0.6)", class = "sds",
coef = 's(I(GPE_ind_log2 + 3), bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 0.3)", class = "sds",
coef = 's(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
class = "Intercept")
)8.2.2 Models
8.2.2.1 Main effects models
Open code
model_infection_any_GPE_ind_main <- run(
expr = brm_multiple(
infection_any ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
I(GPE_ind_log2 + 3),
family = bernoulli(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_infection_any_GPE_ind_main",
reuse = TRUE
)
summary(model_infection_any_GPE_ind_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(GPE_ind_log2 + 3)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -0.98 0.45 -1.90 -0.12 1.02 11019 25593
## male_sex 0.27 0.36 -0.44 1.00 1.01 37004 28448
## Irec_ageM50 -0.02 0.02 -0.06 0.01 1.01 35806 28429
## male_sex_donor 0.21 0.36 -0.48 0.92 1.01 36893 27040
## IKDPIM50 0.03 0.01 0.01 0.05 1.01 33713 27071
## ICITM15 -0.09 0.03 -0.15 -0.04 1.01 20286 25862
## IHLA_MMM5 -0.27 0.12 -0.52 -0.03 1.05 4283 14455
## perfusion_event -0.00 0.40 -0.79 0.80 1.07 2779 11061
## infliximab 0.33 0.35 -0.34 1.03 1.01 35569 27304
## IGPE_ind_log2P3 -0.42 0.25 -0.94 0.04 1.01 39171 26823
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_infection_any_GPE_ind_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 2.72256264350783) b IGPE_ind_log2P3
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.307484699747961, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_infection_any_GPE_ind_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)infliximab treatment and log2-transformed co-factor-independent phosphatidylethanolamine IgG (GPE_ind_log2), on infection risk, without interaction terms. The odds ratio (OR) represents the estimated change in the odds of infection per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.32 | 0.64 | 2.71 |
| Irec_ageM50 | 0.98 | 0.94 | 1.01 |
| male_sex_donor | 1.23 | 0.62 | 2.51 |
| IKDPIM50 | 1.03 | 1.01 | 1.05 |
| ICITM15 | 0.91 | 0.86 | 0.96 |
| IHLA_MMM5 | 0.77 | 0.59 | 0.97 |
| perfusion_event | 1.00 | 0.45 | 2.23 |
| infliximab | 1.39 | 0.71 | 2.79 |
| IGPE_ind_log2P3 | 0.66 | 0.39 | 1.05 |
8.2.2.2 Non-linear interaction model
Open code
model_infection_any_GPE_ind_interaction_NL <- run(
expr = brm_multiple(
infection_any ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(I(GPE_ind_log2+3), bs = 'ps', k = 5) +
s(I(GPE_ind_log2+3), by = infliximab, bs = 'ps', k = 5),
family = bernoulli(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_infection_any_GPE_ind_interaction_NL",
reuse = TRUE
)
summary(model_infection_any_GPE_ind_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: bernoulli
## Links: mu = logit
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(GPE_ind_log2 + 3), bs = "ps", k = 5) + s(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIGPE_ind_log2P3_1) 0.36 0.33 0.02 1.69 1.01
## sds(sIGPE_ind_log2P3infliximab_1) 0.22 0.21 0.01 1.14 1.00
## Bulk_ESS Tail_ESS
## sds(sIGPE_ind_log2P3_1) 20777 16750
## sds(sIGPE_ind_log2P3infliximab_1) 29345 15825
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept -1.01 0.47 -1.96 -0.12 1.03
## male_sex 0.23 0.37 -0.49 0.97 1.01
## Irec_ageM50 -0.02 0.02 -0.06 0.01 1.01
## male_sex_donor 0.20 0.36 -0.51 0.91 1.01
## IKDPIM50 0.03 0.01 0.01 0.05 1.01
## ICITM15 -0.10 0.03 -0.16 -0.04 1.01
## IHLA_MMM5 -0.27 0.13 -0.54 -0.03 1.05
## perfusion_event 0.06 0.42 -0.77 0.89 1.07
## infliximab 0.02 3.94 -7.59 7.86 1.02
## sIGPE_ind_log2P3_1 -0.00 0.94 -2.19 1.95 1.01
## sIGPE_ind_log2P3:infliximab_1 -1.90 2.38 -6.69 2.67 1.02
## sIGPE_ind_log2P3:infliximab_2 2.02 2.37 -2.61 6.62 1.02
## Bulk_ESS Tail_ESS
## Intercept 9152 25359
## male_sex 35120 26888
## Irec_ageM50 33206 26289
## male_sex_donor 34551 26083
## IKDPIM50 32183 26588
## ICITM15 16827 25092
## IHLA_MMM5 3866 13123
## perfusion_event 2824 11080
## infliximab 12055 17429
## sIGPE_ind_log2P3_1 25340 18221
## sIGPE_ind_log2P3:infliximab_1 13678 20478
## sIGPE_ind_log2P3:infliximab_2 13739 20092
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_infection_any_GPE_ind_interaction_NL)
## prior class
## (flat) b
## normal(0, 0.280307006032291) b
## normal(0, 1.38219051128263) b
## normal(0, 0.0970980394231448) b
## normal(0, 4) b
## normal(0, 0.190589762164436) b
## normal(0, 4) b
## normal(0, 4) b
## normal(0, 4) b
## (flat) b
## (flat) b
## (flat) b
## normal(-0.307484699747961, 10) Intercept
## student_t(3, 0, 2.5) sds
## student_t(3, 0, 0.6) sds
## student_t(3, 0, 0.3) sds
## coef group resp dpar
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sIGPE_ind_log2P3_1
## sIGPE_ind_log2P3:infliximab_1
## sIGPE_ind_log2P3:infliximab_2
##
##
## s(I(GPE_ind_log2 + 3), bs = "ps", k = 5)
## s(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5)
## nlpar lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## 0 default
## 0 user
## 0 user
tr2 <- round(exp(fixef(model_infection_any_GPE_ind_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)
antibody_seq <- quantile(data_model_priorImpute$GPE_ind_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_ind_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_ind_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get odds ratio for infliximab effect across antibody values
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPE_ind_log2_int <- quantile(
exp((log(prediction$p95) - log(prediction$p05))/scaling_unit),
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPE_ind_log2_int, 4))
row.names(tr2)[8] <- 'infliximab:GPE_ind_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)GPE_ind_log2) and infliximab treatment on infection risk, while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of aPE-ind IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| (R)OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.2600 | 0.610 | 2.6400 |
| Irec_ageM50 | 0.9800 | 0.940 | 1.0100 |
| male_sex_donor | 1.2200 | 0.600 | 2.4900 |
| IKDPIM50 | 1.0300 | 1.010 | 1.0500 |
| ICITM15 | 0.9100 | 0.850 | 0.9600 |
| IHLA_MMM5 | 0.7600 | 0.590 | 0.9700 |
| perfusion_event | 1.0600 | 0.460 | 2.4300 |
| infliximab:GPE_ind_log2 | 0.0751 | 0.005 | 0.7543 |
8.2.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$GPE_ind_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_ind_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_infection_any_GPE_ind_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPE_ind_log2 = data_prediction$GPE_ind_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control"))) %>%
ggplot(aes(x = GPE_ind_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 1),
breaks = c(seq(0, 1, by = 0.2))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
labs(x = expression(log[2]~"(aPE IgG ind [OD])"), y = "Infection risk") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 0),
aes(x = GPE_ind_log2),
sides = "b",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_rug(
data = data_model_priorImpute %>% filter(DGF == 1),
aes(x = GPE_ind_log2),
sides = "t",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -3.654722 -1.490602
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_ind_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_ind_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)]))
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))
post_fix <- data.frame(
b_GPE_ind_log2 = tr_ctrl,
b_GPE_ind_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = exp(b_GPE_ind_log2),
infliximab = exp(b_GPE_ind_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## control infliximab
## 2.5% 0.23 0.01
## 97.5% 3.76 0.47
## 50% 0.96 0.07
## 0.1% 0.10 0.00
## 99.9% 8.11 1.19
xpos <- 323
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect (OR) of aPE IgG ind increase (p05 to p95) on infection',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(1/600, 1800)) +
scale_x_continuous(transform = 'log2',
breaks = c(1/512, 1/64, 1/8, 1, 8, 64, 512),
labels = c("1/512", "1/64", "1/8", "1", "8", "64", "512")) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -3.654722 -3.411195 -3.164884 -2.708396 -1.490602
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPE_ind_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_infection_any_GPE_ind_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## p05 p25 p50 p75 p95
## 2.5% 1.11 1.01 0.85 0.45 0.03
## 97.5% 9.08 5.56 3.68 2.26 1.33
## 50% 3.12 2.34 1.75 1.02 0.23
## 0.1% 0.63 0.65 0.57 0.27 0.01
## 99.9% 16.77 9.12 5.86 3.60 3.26
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPE_ind_percentile') %>%
ggplot(aes(y = GPE_ind_percentile, x = value, fill = GPE_ind_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on infection risk (odds ratio)",
y = 'Percentile of aPE IgG ind value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(1/300, 1000)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
scale_x_continuous(transform = 'log2',
breaks = c(xseq),
labels = c("1/64", "1/8", "1", "8", "64", '512')) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Odds ratio: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Odds ratio: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Odds ratio: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 8.2.3.1 Figure merged
Open code
plotac <- 'sup_figure_9'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}9 GFR models
9.1 by GPL_BC
9.1.1 Priors
Open code
GFR_sd <- sd(data_model_priorImpute$GFR_MDRD_3)
GFR_sd
## [1] 21.170999.1.1.1 Main effects model
Open code
priors_main <- c(
create_prior("GPL_BC_log2",
GFR_sd*(2*GFR_sd) / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
coef = "GPL_BC_log2"
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"
),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"
),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"
),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_3), ", 200)"),
class = "Intercept"
)
)9.1.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"),
set_prior("student_t(3, 0, 12)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 6)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_3), ", 200)"),
class = "Intercept")
)9.1.2 Models
9.1.2.1 Main effects models
Open code
model_GFR_MDRD_3_GPL_BC_main <- run(
expr = brm_multiple(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
GPL_BC_log2,
family = student(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPL_BC_main",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 53.13 4.10 45.10 61.27 1.01 16406 26395
## male_sex 1.79 3.27 -4.58 8.15 1.01 38414 27869
## Irec_ageM50 0.02 0.15 -0.28 0.32 1.01 37809 27823
## male_sex_donor 0.90 3.20 -5.44 7.24 1.01 38901 27640
## IKDPIM50 -0.24 0.08 -0.40 -0.09 1.01 36390 28400
## ICITM15 0.28 0.23 -0.17 0.72 1.02 9808 27230
## IHLA_MMM5 -0.74 1.09 -2.93 1.42 1.06 3247 11176
## perfusion_event -6.16 3.55 -13.10 0.87 1.06 3134 15250
## infliximab -2.12 3.18 -8.29 4.13 1.01 38526 28245
## GPL_BC_log2 0.26 1.11 -1.96 2.46 1.01 39429 27240
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.99 1.38 16.21 21.76 1.01 28098 22430
## nu 15.72 9.37 5.22 50.79 1.00 28333 25429
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_GPL_BC_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 632.741442420408) b GPL_BC_log2
## normal(0, 5.93437623501858) b ICITM15
## normal(0, 29.2623385998383) b IHLA_MMM5
## normal(0, 2.05566141844214) b IKDPIM50
## normal(0, 84.6839516288788) b infliximab
## normal(0, 4.03497355002315) b Irec_ageM50
## normal(0, 84.6839516288788) b male_sex
## normal(0, 84.6839516288788) b male_sex_donor
## normal(0, 84.6839516288788) b perfusion_event
## normal(51.7227118644068, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sigma
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
## 1 default
## 0 default
tr <- round(fixef(model_GFR_MDRD_3_GPL_BC_main, robust = TRUE)[-1, c(1,3,4)], 2)
colnames(tr)[1] <- 'Estimate'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on estimated glomerular filtration rate (eGFR), without interaction terms. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.79 | -4.58 | 8.15 |
| Irec_ageM50 | 0.02 | -0.28 | 0.32 |
| male_sex_donor | 0.90 | -5.44 | 7.24 |
| IKDPIM50 | -0.24 | -0.40 | -0.09 |
| ICITM15 | 0.28 | -0.17 | 0.72 |
| IHLA_MMM5 | -0.74 | -2.93 | 1.42 |
| perfusion_event | -6.16 | -13.10 | 0.87 |
| infliximab | -2.12 | -8.29 | 4.13 |
| GPL_BC_log2 | 0.26 | -1.96 | 2.46 |
9.1.2.2 Non-linear interaction model
Open code
model_GFR_MDRD_3_GPL_BC_interaction_NL <- run(
expr = brm_multiple(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = student(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPL_BC_interaction_NL",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Warning: There were 2 divergent transitions after warmup. Increasing
## adapt_delta above 0.95 may help. See
## http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 10.58 7.05 0.88 34.65 1.01
## sds(sGPL_BC_log2infliximab_1) 4.20 3.89 0.20 19.80 1.01
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 16287 11879
## sds(sGPL_BC_log2infliximab_1) 33049 17349
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept 54.18 4.05 46.38 62.11 1.01 18434
## male_sex 1.08 3.19 -5.20 7.36 1.01 47958
## Irec_ageM50 0.03 0.15 -0.27 0.32 1.01 45592
## male_sex_donor -0.61 3.23 -6.93 5.76 1.01 46094
## IKDPIM50 -0.25 0.08 -0.41 -0.09 1.01 43069
## ICITM15 0.28 0.22 -0.16 0.72 1.02 13311
## IHLA_MMM5 -0.91 1.08 -3.06 1.23 1.06 3272
## perfusion_event -5.86 3.48 -12.66 0.90 1.05 3684
## infliximab 0.18 81.74 -161.71 162.22 1.01 14656
## sGPL_BC_log2_1 15.85 14.73 -15.35 57.10 1.01 24674
## sGPL_BC_log2:infliximab_1 -16.62 46.80 -110.53 75.97 1.01 14735
## sGPL_BC_log2:infliximab_2 13.23 29.32 -45.55 71.28 1.01 14950
## Tail_ESS
## Intercept 29314
## male_sex 26709
## Irec_ageM50 26752
## male_sex_donor 27159
## IKDPIM50 27230
## ICITM15 26250
## IHLA_MMM5 13786
## perfusion_event 14214
## infliximab 19615
## sGPL_BC_log2_1 19574
## sGPL_BC_log2:infliximab_1 19281
## sGPL_BC_log2:infliximab_2 19912
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.49 1.39 15.60 21.23 1.01 30097 21798
## nu 15.01 9.04 4.92 49.64 1.00 33096 25294
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_GPL_BC_interaction_NL)
## prior class
## (flat) b
## normal(0, 5.93437623501858) b
## normal(0, 29.2623385998383) b
## normal(0, 2.05566141844214) b
## normal(0, 84.6839516288788) b
## normal(0, 4.03497355002315) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## (flat) b
## (flat) b
## (flat) b
## normal(51.7227118644068, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sds
## student_t(3, 0, 12) sds
## student_t(3, 0, 6) sds
## student_t(3, 0, 19.7) sigma
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 1
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## default
## user
## user
## default
tr2 <- round(fixef(model_GFR_MDRD_3_GPL_BC_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)
antibody_seq <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get Estimate for infliximab effect across antibody values
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
(prediction$p95 - prediction$p05)/scaling_unit,
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR), while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.08 | -5.20 | 7.36 |
| Irec_ageM50 | 0.03 | -0.27 | 0.32 |
| male_sex_donor | -0.61 | -6.93 | 5.76 |
| IKDPIM50 | -0.25 | -0.41 | -0.09 |
| ICITM15 | 0.28 | -0.16 | 0.72 |
| IHLA_MMM5 | -0.91 | -3.06 | 1.23 |
| perfusion_event | -5.86 | -12.66 | 0.90 |
| infliximab:GPL_BC_log2 | -23.24 | -42.13 | -4.18 |
9.1.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control")),
`Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 125),
breaks = c(seq(0, 125, by = 25))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
geom_point(data = data_model_priorImpute,
aes(x = GPL_BC_log2, y = GFR_MDRD_3, col = group, fill = group)) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"),
y = "GFR (mL/min/1.73 m²)") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size = 10),
axis.title=element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.801668 2.531821
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = b_GPL_BC_log2,
infliximab = b_GPL_BC_log2_infliximab) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% -1.9 -27.6
## 97.5% 22.6 1.7
## 50% 10.3 -12.9
## 0.1% -9.3 -36.1
## 99.9% 29.8 10.1
xpos <- 39.2
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect of aCL IgG increase (p05 to p95) on eGFR',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(-50, 52)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## p05 p25 p50 p75 p95
## 2.5% -3.3 -5.1 -7.7 -13.6 -28.9
## 97.5% 18.0 9.2 5.0 0.6 -3.3
## 50% 7.3 2.0 -1.3 -6.5 -15.9
## 0.1% -10.1 -9.6 -11.5 -17.3 -36.6
## 99.9% 24.0 13.2 8.6 4.3 3.4
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(-40, 40)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Estimate: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Estimate: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Estimate: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 9.1.3.1 Figure merged
Open code
plotac <- 'sup_figure_4'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}9.2 by GPL_BC - nonimputed failures
This sensitivity analysis aims to evaluate whether the results are consistent when the eGFR definition is modified — using the last available value before graft failure within two years of follow-up, instead of imputing a fixed value of 10 for all failures
9.2.1 Priors
Open code
GFR_sd <- sd(data_model_priorImpute$GFR_MDRD_2)
GFR_sd
## [1] 20.655039.2.1.1 Main effects model
Open code
priors_main <- c(
create_prior("GPL_BC_log2",
GFR_sd*(2*GFR_sd) / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
coef = "GPL_BC_log2"
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"
),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"
),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"
),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_2), ", 200)"),
class = "Intercept"
)
)9.2.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"),
set_prior("student_t(3, 0, 12)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 6)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_2), ", 200)"),
class = "Intercept")
)9.2.2 Models
9.2.2.1 Main effects models
Open code
model_GFR_MDRD_2_GPL_BC_main <- run(
expr = brm_multiple(
GFR_MDRD_2 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
GPL_BC_log2,
family = student(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_2_GPL_BC_main",
reuse = TRUE
)
summary(model_GFR_MDRD_2_GPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_2 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 53.49 4.03 45.64 61.41 1.02 15993 26757
## male_sex 1.88 3.18 -4.38 8.08 1.01 38010 26941
## Irec_ageM50 0.02 0.15 -0.27 0.30 1.01 36815 27819
## male_sex_donor 1.01 3.17 -5.20 7.19 1.01 37320 27500
## IKDPIM50 -0.24 0.08 -0.39 -0.09 1.00 35494 27775
## ICITM15 0.28 0.22 -0.15 0.72 1.02 10627 25966
## IHLA_MMM5 -0.76 1.08 -2.88 1.33 1.06 3338 17289
## perfusion_event -6.23 3.39 -12.97 0.51 1.06 3399 13342
## infliximab -2.48 3.08 -8.56 3.59 1.01 35765 27828
## GPL_BC_log2 0.12 1.10 -2.03 2.26 1.01 38197 27820
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.60 1.30 16.00 21.20 1.00 27749 23012
## nu 17.32 10.08 5.74 52.43 1.00 29322 25293
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_2_GPL_BC_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 602.276328897438) b GPL_BC_log2
## normal(0, 5.78975030085778) b ICITM15
## normal(0, 28.5491898394416) b IHLA_MMM5
## normal(0, 2.00556315348783) b IKDPIM50
## normal(0, 82.6201297329089) b infliximab
## normal(0, 3.93663771894749) b Irec_ageM50
## normal(0, 82.6201297329089) b male_sex
## normal(0, 82.6201297329089) b male_sex_donor
## normal(0, 82.6201297329089) b perfusion_event
## normal(52.0419774011299, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sigma
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
## 1 default
## 0 default
tr <- round(fixef(model_GFR_MDRD_2_GPL_BC_main, robust = TRUE)[-1, c(1,3,4)], 2)
colnames(tr)[1] <- 'Estimate'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on estimated glomerular filtration rate (eGFR; GFR_MDRD_2,). No imputation was applied in cases of graft failure, and no interaction terms were included. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.88 | -4.38 | 8.08 |
| Irec_ageM50 | 0.02 | -0.27 | 0.30 |
| male_sex_donor | 1.01 | -5.20 | 7.19 |
| IKDPIM50 | -0.24 | -0.39 | -0.09 |
| ICITM15 | 0.28 | -0.15 | 0.72 |
| IHLA_MMM5 | -0.76 | -2.88 | 1.33 |
| perfusion_event | -6.23 | -12.97 | 0.51 |
| infliximab | -2.48 | -8.56 | 3.59 |
| GPL_BC_log2 | 0.12 | -2.03 | 2.26 |
9.2.2.2 Non-linear interaction model
Open code
model_GFR_MDRD_2_GPL_BC_interaction_NL <- run(
expr = brm_multiple(
GFR_MDRD_2 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = student(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_2_GPL_BC_interaction_NL",
reuse = TRUE
)
summary(model_GFR_MDRD_2_GPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_2 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 10.47 6.87 1.01 34.89 1.01
## sds(sGPL_BC_log2infliximab_1) 4.17 3.86 0.20 19.45 1.00
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 16663 12838
## sds(sGPL_BC_log2infliximab_1) 34184 17036
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept 54.53 3.90 46.78 62.26 1.01 18178
## male_sex 1.18 3.07 -4.93 7.30 1.01 47019
## Irec_ageM50 0.02 0.15 -0.26 0.31 1.01 45913
## male_sex_donor -0.52 3.16 -6.67 5.73 1.01 47158
## IKDPIM50 -0.25 0.08 -0.41 -0.10 1.01 42963
## ICITM15 0.29 0.21 -0.14 0.71 1.02 11961
## IHLA_MMM5 -0.92 1.06 -3.03 1.17 1.06 3210
## perfusion_event -5.89 3.32 -12.43 0.68 1.05 4191
## infliximab -1.23 80.69 -159.19 157.37 1.01 14948
## sGPL_BC_log2_1 14.87 14.78 -15.57 55.53 1.01 24535
## sGPL_BC_log2:infliximab_1 -15.78 46.50 -106.59 74.82 1.01 15218
## sGPL_BC_log2:infliximab_2 12.64 28.58 -44.34 68.43 1.01 15240
## Tail_ESS
## Intercept 27334
## male_sex 26089
## Irec_ageM50 27422
## male_sex_donor 27864
## IKDPIM50 27758
## ICITM15 26006
## IHLA_MMM5 14291
## perfusion_event 21697
## infliximab 20385
## sGPL_BC_log2_1 19710
## sGPL_BC_log2:infliximab_1 21475
## sGPL_BC_log2:infliximab_2 21127
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.07 1.32 15.41 20.67 1.01 32835 24576
## nu 15.88 9.41 5.26 50.45 1.00 35140 26447
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_2_GPL_BC_interaction_NL)
## prior class
## (flat) b
## normal(0, 5.78975030085778) b
## normal(0, 28.5491898394416) b
## normal(0, 2.00556315348783) b
## normal(0, 82.6201297329089) b
## normal(0, 3.93663771894749) b
## normal(0, 82.6201297329089) b
## normal(0, 82.6201297329089) b
## normal(0, 82.6201297329089) b
## (flat) b
## (flat) b
## (flat) b
## normal(52.0419774011299, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sds
## student_t(3, 0, 12) sds
## student_t(3, 0, 6) sds
## student_t(3, 0, 19.7) sigma
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 1
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## default
## user
## user
## default
tr2 <- round(fixef(model_GFR_MDRD_2_GPL_BC_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)
antibody_seq <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_2_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get Estimate for infliximab effect across antibody values
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
(prediction$p95 - prediction$p05)/scaling_unit,
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (GFR_MDRD_2), while accounting for other covariates. No imputation was applied in cases of graft failure (the last eGFR value prior graft failure or death was used). Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.18 | -4.93 | 7.30 |
| Irec_ageM50 | 0.02 | -0.26 | 0.31 |
| male_sex_donor | -0.52 | -6.67 | 5.73 |
| IKDPIM50 | -0.25 | -0.41 | -0.10 |
| ICITM15 | 0.29 | -0.14 | 0.71 |
| IHLA_MMM5 | -0.92 | -3.03 | 1.17 |
| perfusion_event | -5.89 | -12.43 | 0.68 |
| infliximab:GPL_BC_log2 | -22.04 | -40.46 | -3.95 |
9.2.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_GFR_MDRD_2_GPL_BC_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control")),
`Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 125),
breaks = c(seq(0, 125, by = 25))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
geom_point(data = data_model_priorImpute,
aes(x = GPL_BC_log2, y = GFR_MDRD_2, col = group, fill = group)) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"),
y = "GFR (mL/min/1.73 m²)") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size = 10),
axis.title=element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.801668 2.531821
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_2_GPL_BC_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = b_GPL_BC_log2,
infliximab = b_GPL_BC_log2_infliximab) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% -2.7 -27.7
## 97.5% 20.8 1.3
## 50% 9.0 -13.1
## 0.1% -9.1 -36.6
## 99.9% 27.7 9.7
xpos <- 39.2
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect of aCL IgG increase (p05 to p95) on eGFR',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(-50, 52)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_2_GPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## p05 p25 p50 p75 p95
## 2.5% -3.9 -5.5 -8.0 -13.5 -28.2
## 97.5% 16.7 8.3 4.4 0.2 -3.5
## 50% 6.4 1.4 -1.8 -6.6 -15.7
## 0.1% -10.0 -9.6 -11.5 -17.7 -35.9
## 99.9% 22.8 12.4 8.1 4.3 3.5
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(-40, 40)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Estimate: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Estimate: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Estimate: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 9.2.3.1 Figure merged
Open code
plotac <- 'sup_figure_7'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}9.3 by MPL_BC
Open code
GFR_sd <- sd(data_model_priorImpute$GFR_MDRD_3)
GFR_sd
## [1] 21.170999.3.1 Priors
9.3.1.1 Main effects model
Open code
priors_main <- c(
create_prior("IMPL_BC_log2M2",
(2*GFR_sd) / sd(data_model_priorImpute$MPL_BC_log2, na.rm = TRUE),
coef = "IMPL_BC_log2M2"
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"
),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"
),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"
),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_3), ", 200)"),
class = "Intercept"
)
)9.3.1.2 Non-linear penalized interaction model
Open code
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"),
set_prior("student_t(3, 0, 12)", class = "sds",
coef = 's(I(MPL_BC_log2 - 2), bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 6)", class = "sds",
coef = 's(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_3), ", 200)"),
class = "Intercept")
)9.3.2 Models
9.3.2.1 Main effects models
Open code
model_GFR_MDRD_3_MPL_BC_main <- run(
expr = brm_multiple(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
I(MPL_BC_log2 - 2),
family = student(),
data = data_imputed,
prior = priors_main,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_MPL_BC_main",
reuse = TRUE
)
summary(model_GFR_MDRD_3_MPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(MPL_BC_log2 - 2)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 53.98 4.12 45.84 62.07 1.01 17881 26136
## male_sex 1.39 3.25 -5.09 7.91 1.01 38469 28129
## Irec_ageM50 0.02 0.15 -0.28 0.32 1.01 38402 27141
## male_sex_donor 0.66 3.21 -5.57 6.94 1.01 37506 27707
## IKDPIM50 -0.24 0.08 -0.39 -0.08 1.01 36437 27843
## ICITM15 0.31 0.22 -0.13 0.75 1.02 10533 25501
## IHLA_MMM5 -0.73 1.10 -2.89 1.43 1.06 3345 12707
## perfusion_event -6.70 3.50 -13.61 0.23 1.06 3314 12070
## infliximab -2.62 3.18 -8.94 3.67 1.01 37498 27533
## IMPL_BC_log2M2 -0.82 1.03 -2.82 1.23 1.01 36554 27952
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.91 1.39 16.08 21.65 1.01 27313 23629
## nu 15.11 9.07 5.10 49.59 1.00 29833 26721
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_MPL_BC_main)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 5.93437623501858) b ICITM15
## normal(0, 29.2623385998383) b IHLA_MMM5
## normal(0, 2.05566141844214) b IKDPIM50
## normal(0, 27.0849589154158) b IMPL_BC_log2M2
## normal(0, 84.6839516288788) b infliximab
## normal(0, 4.03497355002315) b Irec_ageM50
## normal(0, 84.6839516288788) b male_sex
## normal(0, 84.6839516288788) b male_sex_donor
## normal(0, 84.6839516288788) b perfusion_event
## normal(51.7227118644068, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sigma
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
## 1 default
## 0 default
tr <- round(fixef(model_GFR_MDRD_3_MPL_BC_main, robust = TRUE)[-1, c(1,3,4)], 2)
colnames(tr)[1] <- 'Estimate'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgM (MPL_BC_log2), on estimated glomerular filtration rate (eGFR), without interaction terms. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.39 | -5.09 | 7.91 |
| Irec_ageM50 | 0.02 | -0.28 | 0.32 |
| male_sex_donor | 0.66 | -5.57 | 6.94 |
| IKDPIM50 | -0.24 | -0.39 | -0.08 |
| ICITM15 | 0.31 | -0.13 | 0.75 |
| IHLA_MMM5 | -0.73 | -2.89 | 1.43 |
| perfusion_event | -6.70 | -13.61 | 0.23 |
| infliximab | -2.62 | -8.94 | 3.67 |
| IMPL_BC_log2M2 | -0.82 | -2.82 | 1.23 |
9.3.2.2 Non-linear interaction model
Open code
model_GFR_MDRD_3_MPL_BC_interaction_NL <- run(
expr = brm_multiple(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(I(MPL_BC_log2-2), bs = 'ps', k = 5) +
s(I(MPL_BC_log2-2), by = infliximab, bs = 'ps', k = 5),
family = student(),
data = data_imputed,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 2000, warmup = 1900,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_MPL_BC_interaction_NL",
reuse = TRUE
)
summary(model_GFR_MDRD_3_MPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(MPL_BC_log2 - 2), bs = "ps", k = 5) + s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)
## Data: data_imputed (Number of observations: 177)
## Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
## total post-warmup draws = 32000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIMPL_BC_log2M2_1) 5.47 5.12 0.27 26.04 1.01
## sds(sIMPL_BC_log2M2infliximab_1) 3.93 3.68 0.18 18.57 1.01
## Bulk_ESS Tail_ESS
## sds(sIMPL_BC_log2M2_1) 23473 17212
## sds(sIMPL_BC_log2M2infliximab_1) 30914 16767
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept 53.59 4.13 45.45 61.86 1.01 18394
## male_sex 1.61 3.25 -4.83 8.03 1.01 45915
## Irec_ageM50 0.02 0.15 -0.27 0.32 1.01 45146
## male_sex_donor 0.23 3.16 -6.09 6.54 1.01 47794
## IKDPIM50 -0.24 0.08 -0.39 -0.08 1.01 44970
## ICITM15 0.31 0.22 -0.13 0.75 1.02 11127
## IHLA_MMM5 -0.75 1.10 -2.96 1.40 1.06 3332
## perfusion_event -7.06 3.54 -13.99 -0.11 1.06 3438
## infliximab -0.02 81.30 -163.96 161.14 1.01 14172
## sIMPL_BC_log2M2_1 -6.36 11.82 -33.38 20.35 1.01 28050
## sIMPL_BC_log2M2:infliximab_1 -12.17 59.34 -129.21 106.48 1.01 14377
## sIMPL_BC_log2M2:infliximab_2 8.82 20.16 -30.85 48.72 1.01 14618
## Tail_ESS
## Intercept 28686
## male_sex 26098
## Irec_ageM50 26443
## male_sex_donor 26205
## IKDPIM50 28413
## ICITM15 27006
## IHLA_MMM5 17384
## perfusion_event 14352
## infliximab 18654
## sIMPL_BC_log2M2_1 21919
## sIMPL_BC_log2M2:infliximab_1 19452
## sIMPL_BC_log2M2:infliximab_2 20303
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.87 1.38 16.03 21.58 1.01 30872 23148
## nu 15.53 9.34 5.13 50.54 1.00 32611 27010
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_MPL_BC_interaction_NL)
## prior class
## (flat) b
## normal(0, 5.93437623501858) b
## normal(0, 29.2623385998383) b
## normal(0, 2.05566141844214) b
## normal(0, 84.6839516288788) b
## normal(0, 4.03497355002315) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## (flat) b
## (flat) b
## (flat) b
## normal(51.7227118644068, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.7) sds
## student_t(3, 0, 12) sds
## student_t(3, 0, 6) sds
## student_t(3, 0, 19.7) sigma
## coef group resp dpar nlpar
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sIMPL_BC_log2M2_1
## sIMPL_BC_log2M2:infliximab_1
## sIMPL_BC_log2M2:infliximab_2
##
##
##
## s(I(MPL_BC_log2 - 2), bs = "ps", k = 5)
## s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)
##
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## 1 default
## 0 default
## 0 user
## 0 user
## 0 default
tr2 <- round(fixef(model_GFR_MDRD_3_MPL_BC_interaction_NL,
robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)
antibody_seq <- quantile(data_model_priorImpute$MPL_BC_log2, probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_MPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get Estimate for infliximab effect across antibody values
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_MPL_BC_log2_int <- quantile((prediction$p95 - prediction$p05)/scaling_unit,
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_MPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:MPL_BC_log2'
kableExtra::kable(tr2)MPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR), while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:MPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgM, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.61 | -4.83 | 8.03 |
| Irec_ageM50 | 0.02 | -0.27 | 0.32 |
| male_sex_donor | 0.23 | -6.09 | 6.54 |
| IKDPIM50 | -0.24 | -0.39 | -0.08 |
| ICITM15 | 0.31 | -0.13 | 0.75 |
| IHLA_MMM5 | -0.75 | -2.96 | 1.40 |
| perfusion_event | -7.06 | -13.99 | -0.11 |
| infliximab:MPL_BC_log2 | -17.91 | -37.96 | 1.85 |
9.3.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_model_priorImpute$MPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_GFR_MDRD_3_MPL_BC_interaction_NL,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
MPL_BC_log2 = data_prediction$MPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control")),
`Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>%
ggplot(aes(x = MPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 125),
breaks = c(seq(0, 125, by = 25))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
geom_point(data = data_model_priorImpute,
aes(x = MPL_BC_log2, y = GFR_MDRD_3, col = group, fill = group)) +
labs(x = expression(log[2]~"(aCL IgM ["*mu*"g/ml])"), y = "GFR (mL/min/1.73 m²)") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -0.3963058 4.5810923
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_MPL_BC_interaction_NL,
newdata = data_prediction)
tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])
post_fix <- data.frame(
b_MPL_BC_log2 = tr_ctrl,
b_MPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = (b_MPL_BC_log2),
infliximab = (b_MPL_BC_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% -9.3 -28.1
## 97.5% 18.9 1.5
## 50% 4.7 -13.2
## 0.1% -17.8 -37.7
## 99.9% 27.1 9.4
xpos <- 39.2
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect of aCL IgM increase (p05 to p95) on eGFR',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(-50, 52)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -0.3963058 1.0933124 2.0432905 2.9421729 4.5810923
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`MPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_MPL_BC_interaction_NL,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## p05 p25 p50 p75 p95
## 2.5% -5.6 -6.5 -9.0 -13.4 -25.0
## 97.5% 17.1 8.0 3.7 1.4 0.2
## 50% 5.6 0.7 -2.7 -6.0 -12.3
## 0.1% -11.9 -10.7 -12.5 -17.5 -33.0
## 99.9% 23.7 12.7 7.6 5.8 7.2
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'MPL_BC_percentile') %>%
ggplot(aes(y = MPL_BC_percentile, x = value, fill = MPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)",
y = 'Percentile of aCL IgM value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(-40, 40)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Estimate: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Estimate: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Estimate: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 9.3.3.1 Figure merged
Open code
plotac <- 'sup_figure_5'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}10 Summarizing table
10.1 Logistic models
Open code
data_results_table_OR <- data.frame(
outcome = c('DGF', 'DGF', 'infection', 'infection'),
antibody = c('aCL IgG', 'aCL IgM', 'aPE-dep IgG', 'aPE-ind IgG'),
`OR_p05` = c('0.13 [0.03, 0.49]',
'0.23 [0.05, 0.94]',
'3.73 [1.15, 12.69]',
'3.12 [1.11, 9.08]'),
OR_p25 = c('0.34 [0.13, 0.80]',
'0.48 [0.19, 1.15]',
'2.26 [1.005, 5.19]',
'2.34 [1.01, 5.56]'),
OR_p50 = c('0.59 [0.27, 1.25]',
'0.77 [0.37, 1.61]',
'1.68 [0.82, 3.47]',
'1.75 [0.85, 3.68]'),
OR_p75 = c('1.37 [0.60, 3.22]',
'1.22 [0.52, 2.85]',
'1.10 [0.49, 2.42]',
'1.02 [0.45, 2.26]'),
OR_p95 = c('6.24 [1.38, 30.32]',
'2.79 [0.66, 12.59]',
'0.36 [0.07, 1.75]',
'0.23 [0.03, 1.33]'),
p95_per_p05_ROR = c('46.6 [4.4, 610.0]',
'12.8 [1.1, 166.6]',
'0.097 [0.008, 0.995]',
'0.08 [0.005, 0.75]'
)
)
kableExtra::kable(data_results_table_OR)antibody) levels and infliximab (IFX) treatment on the specified outcome. The antibody include anti-cardiolipin IgG or IgM (aCL IgG or IgM) and co-factor (ind)dependent anti-phosphatidylethanolamine (aPE-dep IgG and aPE-ind IgG respectively). IFX treatment effects (odds ratio [OR, infliximab vs. placebo]) are reported at the 5th, 25th, 50th, 75th, and 95th sample percentiles of nAb levels, each with [95% credible interval]. Interaction magnitudes are expressed as the ratio of odds ratios (ROR) for the IFX effect at the 95th vs. 5th percentile of the nAb level (p95_per_p05_ROR) with [95% credible intervals]
| outcome | antibody | OR_p05 | OR_p25 | OR_p50 | OR_p75 | OR_p95 | p95_per_p05_ROR |
|---|---|---|---|---|---|---|---|
| DGF | aCL IgG | 0.13 [0.03, 0.49] | 0.34 [0.13, 0.80] | 0.59 [0.27, 1.25] | 1.37 [0.60, 3.22] | 6.24 [1.38, 30.32] | 46.6 [4.4, 610.0] |
| DGF | aCL IgM | 0.23 [0.05, 0.94] | 0.48 [0.19, 1.15] | 0.77 [0.37, 1.61] | 1.22 [0.52, 2.85] | 2.79 [0.66, 12.59] | 12.8 [1.1, 166.6] |
| infection | aPE-dep IgG | 3.73 [1.15, 12.69] | 2.26 [1.005, 5.19] | 1.68 [0.82, 3.47] | 1.10 [0.49, 2.42] | 0.36 [0.07, 1.75] | 0.097 [0.008, 0.995] |
| infection | aPE-ind IgG | 3.12 [1.11, 9.08] | 2.34 [1.01, 5.56] | 1.75 [0.85, 3.68] | 1.02 [0.45, 2.26] | 0.23 [0.03, 1.33] | 0.08 [0.005, 0.75] |
10.2 Linear models (eGFR)
Open code
data_results_table_cont <- data.frame(
outcome = c('eGFR', 'eGFR', 'eGFR_last_prefail'),
antibody = c('aCL IgG', 'aCL IgM', 'aCL IgG'),
eff_p05 = c('7.3 [-3.3, 18.0]',
'5.6 [-5.6, 17.1]',
'6.4 [-3.9, 16.7]'),
eff_p25 = c('2.0 [-5.1, 9.2]',
'0.7 [-6.5, 8.0]',
'1.4 [-5.5, 8.3]'),
eff_p50 = c('-1.3 [-7.7, 5.0]',
'-2.7 [-9.0, 3.7]',
'-1.8 [-8.0, 4.4]'),
eff_p75 = c('-6.5 [-13.6, 0.6]',
'-6.0 [-13.4, 1.4]',
'-6.6 [-13.5, 0.2]'),
eff_p95 = c('-15.9 [-28.9, -3.3]',
'-12.3 [-25.0, 0.2]',
'-15.7 [-28.2, -3.5]'),
p95_p05_DE = c('-23.2 [-42.1, -4.2]',
'-17.9 [-38.0, 1.9]',
'-22.0 [-40.5, 4.0]')
)
kableExtra::kable(data_results_table_cont)antibody) levels and infliximab (IFX) treatment on the specified outcome (either eGFR with imputed values in cases of graft failure within two years of follow-up [eGFR], or based on the last pre-failure eGFR measurement within two years [eGFR_last_prefail]). The antibody include anti-cardiolipin (aCL) IgG or IgM. IFX treatment absolute effect (eff, infliximab minus placebo) are reported at the 5th, 25th, 50th, 75th, and 95th sample percentiles of nAb levels, each with [95% credible interval]. Interaction magnitudes are expressed as the difference in treatment effects at the 95th minus 5th percentile (p95_p05_DE) with [95% credible intervals]
| outcome | antibody | eff_p05 | eff_p25 | eff_p50 | eff_p75 | eff_p95 | p95_p05_DE |
|---|---|---|---|---|---|---|---|
| eGFR | aCL IgG | 7.3 [-3.3, 18.0] | 2.0 [-5.1, 9.2] | -1.3 [-7.7, 5.0] | -6.5 [-13.6, 0.6] | -15.9 [-28.9, -3.3] | -23.2 [-42.1, -4.2] |
| eGFR | aCL IgM | 5.6 [-5.6, 17.1] | 0.7 [-6.5, 8.0] | -2.7 [-9.0, 3.7] | -6.0 [-13.4, 1.4] | -12.3 [-25.0, 0.2] | -17.9 [-38.0, 1.9] |
| eGFR_last_prefail | aCL IgG | 6.4 [-3.9, 16.7] | 1.4 [-5.5, 8.3] | -1.8 [-8.0, 4.4] | -6.6 [-13.5, 0.2] | -15.7 [-28.2, -3.5] | -22.0 [-40.5, 4.0] |
11 GFR: Mediation and AB-subgroup analysis
11.1 Define the subgroups
Open code
GPL_median <- median(data_model_priorImpute$GPL_BC_log2)
GPL_median
## [1] -0.1046076
data_imputed_highGPL <- data.frame(subset(
data_first,
subset = data_first$GPL_BC_log2 >= GPL_median
))
data_imputed_lowGPL <- subset(
data_first,
subset = data_first$GPL_BC_log2 < GPL_median
)11.1.1 Priors
Open code
create_prior <- function(var, sigma, class = "b") {
set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = var)
}
GFR_sd <- sd(data_model_priorImpute$GFR_MDRD_3)
GFR_sd
## [1] 21.17099
priors_subset <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE)
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE)
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE)
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE)
),
create_prior("male_sex",
4*GFR_sd
),
create_prior("perfusion_event",
4*GFR_sd
),
create_prior("male_sex_donor",
4*GFR_sd
),
create_prior("infliximab",
4*GFR_sd
),
set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD_3), ", 200)"),
class = "Intercept"
)
)
create_prior <- function(var, sigma, class = "b", resp = 'GFR_MDRD_3') {
set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = var, resp = resp)
}
priors_mediation <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE)
),
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
resp = 'DGF'
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE)
),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
resp = 'DGF'
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE)
),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
resp = 'DGF'
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE)
),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
resp = 'DGF'
),
create_prior("male_sex",
4*GFR_sd
),
create_prior("male_sex",
4*GFR_sd,
resp = 'DGF'
),
create_prior("perfusion_event",
4*GFR_sd
),
create_prior("perfusion_event",
4*GFR_sd,
resp = 'DGF'
),
create_prior("male_sex_donor",
4*GFR_sd
),
create_prior("male_sex_donor",
4*GFR_sd,
resp = 'DGF'
),
create_prior("infliximab",
4*GFR_sd
),
create_prior("infliximab",
4*GFR_sd,
resp = 'DGF'
),
create_prior("DGF",
4*GFR_sd
)
)11.1.2 GPL subgroup models
Open code
model_GFR_MDRD_3_GPLsubset_low <- run(
expr = brm(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab,
family = student(),
data = data_imputed_lowGPL,
prior = priors_subset,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 6000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPLsubset_low",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPLsubset_low)
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab
## Data: data_imputed_lowGPL (Number of observations: 88)
## Draws: 4 chains, each with iter = 6000; warmup = 2000; thin = 1;
## total post-warmup draws = 16000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 52.46 6.73 39.41 65.62 1.00 13509 12065
## male_sex -0.09 5.11 -10.30 9.85 1.00 16331 11501
## Irec_ageM50 0.15 0.25 -0.33 0.64 1.00 14395 11553
## male_sex_donor -1.99 4.89 -11.49 7.64 1.00 17367 12459
## IKDPIM50 -0.19 0.13 -0.45 0.07 1.00 13350 12286
## ICITM15 0.34 0.37 -0.39 1.07 1.00 15730 12347
## IHLA_MMM5 -2.18 1.74 -5.60 1.23 1.00 14721 12734
## perfusion_event -9.86 5.01 -19.68 -0.08 1.00 16324 12384
## infliximab 6.69 4.93 -3.13 16.39 1.00 16223 11807
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 20.58 1.94 16.91 24.59 1.00 11642 9925
## nu 21.25 13.21 5.25 54.99 1.00 12313 10772
##
## Draws were sampled using sample(hmc). 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).
model_GFR_MDRD_3_GPLsubset_high <- run(
expr = brm(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
#GPL_BC_log2 +
infliximab,
family = student(),
data = data_imputed_highGPL,
prior = priors_subset,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 6000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPLsubset_high",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPLsubset_high)
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab
## Data: data_imputed_highGPL (Number of observations: 89)
## Draws: 4 chains, each with iter = 6000; warmup = 2000; thin = 1;
## total post-warmup draws = 16000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 55.29 4.70 46.08 64.60 1.00 15838 12336
## male_sex 2.39 4.19 -5.89 10.63 1.00 16915 12278
## Irec_ageM50 -0.12 0.19 -0.51 0.25 1.00 15773 11909
## male_sex_donor 2.09 4.33 -6.56 10.54 1.00 14250 11634
## IKDPIM50 -0.29 0.10 -0.49 -0.09 1.00 13747 12356
## ICITM15 0.22 0.27 -0.32 0.74 1.00 15390 12124
## IHLA_MMM5 -0.33 1.40 -3.09 2.39 1.00 16515 12259
## perfusion_event -3.22 4.50 -11.96 5.71 1.00 14330 12062
## infliximab -10.99 4.11 -19.06 -2.97 1.00 15817 11701
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 16.97 1.85 13.32 20.70 1.00 9173 7985
## nu 17.87 12.93 3.75 52.17 1.00 10702 9238
##
## Draws were sampled using sample(hmc). 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).11.1.3 Mediation
Prepare table
Open code
# Model for the mediator DGF
m1 <- bf(
DGF ~ scale(male_sex) +
scale(rec_age) +
scale(male_sex_donor) +
scale(KDPI) +
scale(CIT) +
scale(HLA_MM) +
scale(perfusion_event) +
infliximab,
family = bernoulli(link = "logit")
)
# Model for the outcome GFR
m2 <- bf(
GFR_MDRD_3 ~ scale(male_sex) +
scale(rec_age) +
scale(male_sex_donor) +
scale(KDPI) +
scale(CIT) +
scale(HLA_MM) +
scale(perfusion_event) +
infliximab +
DGF,
family = student()
)
## Joint model - Low GPL_BC
model_GFR_GPL_mediate_low <- run(
expr = brm(
m1 + m2 + set_rescor(FALSE),
data = data_imputed_lowGPL,
priors_mediation,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 6000, warmup = 2000,
control = list(adapt_delta = 0.95), refresh = 0),
path = "gitignore/run/model_GFR_2_GPL_mediate_low",
reuse = TRUE
)
## Joint model - high GPL_BC
model_GFR_GPL_mediate_high <- run(
expr = brm(
m1 + m2 + set_rescor(FALSE),
data = data_imputed_highGPL,
priors_mediation,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 6000, warmup = 2000,
control = list(adapt_delta = 0.95), refresh = 0),
path = "gitignore/run/model_GFR_2_GPL_mediate_high",
reuse = TRUE
)
post_fix_low <- as.data.frame(model_GFR_GPL_mediate_low) %>%
select(b_GFRMDRD3_Intercept, b_GFRMDRD3_infliximab, b_GFRMDRD3_DGF,
b_DGF_Intercept, b_DGF_infliximab) %>%
mutate(predicted_DGF_ctrl = inv_logit(b_DGF_Intercept),
predicted_DGF_infx = inv_logit(b_DGF_Intercept + b_DGF_infliximab)) %>%
mutate(
indirect_pred_ctrl = b_GFRMDRD3_Intercept +
(b_GFRMDRD3_infliximab * mean(data_imputed_lowGPL$infliximab) ) +
(b_GFRMDRD3_DGF * predicted_DGF_ctrl),
indirect_pred_infx = b_GFRMDRD3_Intercept +
(b_GFRMDRD3_infliximab * mean(data_imputed_lowGPL$infliximab) ) +
(b_GFRMDRD3_DGF * predicted_DGF_infx),
) %>%
mutate(
`Direct Effect (ADE)` = b_GFRMDRD3_infliximab,
`Indirect Effect (ACME)` = indirect_pred_infx - indirect_pred_ctrl,
`Mediator Effect` = b_GFRMDRD3_DGF,
`Total Effect` = (
(indirect_pred_infx - indirect_pred_ctrl) + b_GFRMDRD3_infliximab
)
) %>%
select(`Direct Effect (ADE)`:`Total Effect`)
med_eff_low <- sapply(
post_fix_low,
function(p) quantile(p, probs = c(0.5, 0.025, 0.975))
) %>% t()
post_fix_high <- as.data.frame(model_GFR_GPL_mediate_high) %>%
select(b_GFRMDRD3_Intercept, b_GFRMDRD3_infliximab, b_GFRMDRD3_DGF,
b_DGF_Intercept, b_DGF_infliximab) %>%
mutate(predicted_DGF_ctrl = inv_logit(b_DGF_Intercept),
predicted_DGF_infx = inv_logit(b_DGF_Intercept + b_DGF_infliximab)) %>%
mutate(
indirect_pred_ctrl = b_GFRMDRD3_Intercept +
(b_GFRMDRD3_infliximab * mean(data_imputed_highGPL$infliximab) ) +
(b_GFRMDRD3_DGF * predicted_DGF_ctrl),
indirect_pred_infx = b_GFRMDRD3_Intercept +
(b_GFRMDRD3_infliximab * mean(data_imputed_highGPL$infliximab) ) +
(b_GFRMDRD3_DGF * predicted_DGF_infx),
) %>%
mutate(
`Direct Effect (ADE)` = b_GFRMDRD3_infliximab,
`Indirect Effect (ACME)` = indirect_pred_infx - indirect_pred_ctrl,
`Mediator Effect` = b_GFRMDRD3_DGF,
`Total Effect` = (
(indirect_pred_infx - indirect_pred_ctrl) + b_GFRMDRD3_infliximab
)
) %>%
select(`Direct Effect (ADE)`:`Total Effect`)
med_eff_high <- sapply(
post_fix_high,
function(p) quantile(p, probs = c(0.5, 0.025, 0.975))
) %>% t()
mediation_effect <- data.frame(
effect = rownames(med_eff_low),
`Low_aCL` = paste0(
round(c(med_eff_low[, 1]), 1),
' [',
round(c(med_eff_low[, 2]), 1),
', ',
round(c(med_eff_low[, 3]), 1),
']'
),
`High_aCL` = paste0(
round(c(med_eff_high[, 1]), 1),
' [',
round(c(med_eff_high[, 2]), 1),
', ',
round(c(med_eff_high[, 3]), 1),
']'
)
)Print table
Open code
kableExtra::kable(mediation_effect)ADE [95% credible interval]) estimates the direct effect of infliximab on eGFR, controlling for the indirect pathway via DGF and other covariates. The Average Causal Mediation Effect (ACME [95% credible interval]) quantifies the indirect effect via DGF. The Mediator Effect represents the effect of DGF on eGFR, adjusting for infliximab and other covariates. The Total Effect captures the overall impact of infliximab on eGFR, combining both direct and indirect pathways.
| effect | Low_aCL | High_aCL |
|---|---|---|
| Direct Effect (ADE) | 1 [-8.4, 10.2] | -8.9 [-16.8, -1.1] |
| Indirect Effect (ACME) | 5.1 [1.3, 10.7] | -2.1 [-6.2, 0.2] |
| Mediator Effect | -17.8 [-27.6, -7.9] | -11.4 [-19.9, -2.7] |
| Total Effect | 6.4 [-3.3, 15.8] | -11.2 [-19.5, -3.2] |
12 Models without large GPL_BC
Open code
infl_max <- max(data_first[which(data_first$infliximab == 1), 'GPL_BC_log2']); infl_max
## [1] 2.740331
ctrl_max <- max(data_first[which(data_first$infliximab == 0), 'GPL_BC_log2']); ctrl_max
## [1] 4.949819
data_sens <- data_first %>% filter(GPL_BC_log2 <= infl_max) %>%
mutate(group = factor(if_else(infliximab == 1, 'infliximab', 'control')))12.1 DGF by GPL_BC
12.1.1 Priors
Open code
# function to get prior
create_prior <- function(var, sigma, class = "b", coef = NULL) {
set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = coef)
}
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
2 / sd(data_sens$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
2 / sd(data_sens$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
2 / sd(data_sens$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
2 / sd(data_sens$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4,
coef = "male_sex"),
create_prior("perfusion_event",
4,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"),
create_prior("infliximab",
4,
coef = "infliximab"),
set_prior("student_t(3, 0, 0.6)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 0.3)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", logit(mean(data_sens$DGF)), ", 10)"),
class = "Intercept")
)12.1.2 Model
Open code
model_dgf_GPL_BC_interaction_NL_sens <- run(
expr = brm(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = bernoulli(),
data = data_sens,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 5000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_GPL_BC_interaction_NL_sens",
reuse = TRUE
)
summary(model_dgf_GPL_BC_interaction_NL_sens, robust = TRUE)
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_sens (Number of observations: 170)
## Draws: 4 chains, each with iter = 5000; warmup = 2000; thin = 1;
## total post-warmup draws = 12000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 0.45 0.40 0.02 1.88 1.00
## sds(sGPL_BC_log2infliximab_1) 0.22 0.21 0.01 1.07 1.00
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 7041 5216
## sds(sGPL_BC_log2infliximab_1) 8954 5147
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept -1.23 0.49 -2.25 -0.26 1.00 11736
## male_sex 1.15 0.41 0.35 1.99 1.00 12193
## Irec_ageM50 -0.01 0.02 -0.05 0.03 1.00 11702
## male_sex_donor 0.31 0.40 -0.45 1.11 1.00 10843
## IKDPIM50 0.00 0.01 -0.02 0.02 1.00 10691
## ICITM15 0.09 0.03 0.03 0.15 1.00 10923
## IHLA_MMM5 0.25 0.14 -0.01 0.52 1.00 10410
## perfusion_event -0.39 0.39 -1.17 0.39 1.00 11052
## infliximab 0.06 3.89 -7.58 7.58 1.00 3997
## sGPL_BC_log2_1 2.05 1.19 -0.39 4.66 1.00 7724
## sGPL_BC_log2:infliximab_1 1.65 2.73 -3.57 6.90 1.00 4254
## sGPL_BC_log2:infliximab_2 -2.09 1.33 -4.69 0.48 1.00 4694
## Tail_ESS
## Intercept 9635
## male_sex 9580
## Irec_ageM50 9522
## male_sex_donor 8929
## IKDPIM50 8477
## ICITM15 8949
## IHLA_MMM5 8917
## perfusion_event 9013
## infliximab 5974
## sGPL_BC_log2_1 6425
## sGPL_BC_log2:infliximab_1 6490
## sGPL_BC_log2:infliximab_2 6814
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_GPL_BC_interaction_NL_sens)
## prior class
## (flat) b
## normal(0, 0.281193624307594) b
## normal(0, 1.32489040521642) b
## normal(0, 0.0974514024084987) b
## normal(0, 4) b
## normal(0, 0.194443540354437) b
## normal(0, 4) b
## normal(0, 4) b
## normal(0, 4) b
## (flat) b
## (flat) b
## (flat) b
## normal(-0.658055860748675, 10) Intercept
## student_t(3, 0, 2.5) sds
## student_t(3, 0, 0.6) sds
## student_t(3, 0, 0.3) sds
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## user
## user
tr2 <- round(exp(fixef(model_dgf_GPL_BC_interaction_NL_sens,
robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)
antibody_seq <- quantile(data_sens$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get odds ratio for infliximab effect across antibody values
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
exp((log(prediction$p95) - log(prediction$p05))/scaling_unit),
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates, restricting the dataset to patients with anti-cardiolipin IgG levels within the range observed in the infliximab group. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| (R)OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 3.16 | 1.43 | 7.31 |
| Irec_ageM50 | 0.99 | 0.95 | 1.03 |
| male_sex_donor | 1.36 | 0.64 | 3.04 |
| IKDPIM50 | 1.00 | 0.98 | 1.02 |
| ICITM15 | 1.09 | 1.03 | 1.16 |
| IHLA_MMM5 | 1.28 | 0.99 | 1.68 |
| perfusion_event | 0.68 | 0.31 | 1.47 |
| infliximab:GPL_BC_log2 | 49.76 | 4.11 | 715.86 |
12.1.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_sens$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_dgf_GPL_BC_interaction_NL_sens,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control"))) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 1),
breaks = c(seq(0, 1, by = 0.2))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), y = "DGF risk") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size=10),
axis.title=element_text(size=12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_rug(
data = data_sens %>% filter(DGF == 0),
aes(x = GPL_BC_log2),
sides = "b",
color = "black",
size = 0.12,
inherit.aes = FALSE
) +
geom_rug(
data = data_sens %>% filter(DGF == 1),
aes(x = GPL_BC_log2),
sides = "t",
color = "black",
linewidth = 0.12,
inherit.aes = FALSE
) +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.801712 2.071126
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)]))
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = exp(b_GPL_BC_log2),
infliximab = exp(b_GPL_BC_log2_infliximab)) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## control infliximab
## 2.5% 0.03 1.76
## 97.5% 1.05 53.51
## 50% 0.18 9.02
## 0.1% 0.01 0.64
## 99.9% 3.12 171.65
xpos <- 323
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect (OR) of aCL IgG increase (p05 to p95) on DGF',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(1/600, 1800)) +
scale_x_continuous(transform = 'log2',
breaks = c(1/512, 1/64, 1/8, 1, 8, 64, 512),
labels = c("1/512", "1/64", "1/8", "1", "8", "64", "512")) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
## 5% 25% 50% 75% 95%
## -1.8017117 -0.7949708 -0.1340217 0.6308746 2.0711263
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_dgf_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
(prediction_infliximab/(1-prediction_infliximab))/
(prediction_ctrl/(1-prediction_ctrl))
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(2)
CIS
## p05 p25 p50 p75 p95
## 2.5% 0.02 0.11 0.26 0.54 1.21
## 97.5% 0.46 0.74 1.23 2.93 27.34
## 50% 0.11 0.30 0.58 1.26 5.61
## 0.1% 0.01 0.06 0.16 0.33 0.50
## 99.9% 1.08 1.29 1.89 4.75 66.13
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on DGF risk (odds ratio)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(1/300, 1150)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
scale_x_continuous(transform = 'log2',
breaks = c(xseq),
labels = c("1/64", "1/8", "1", "8", "64", '512')) +
geom_vline(xintercept = 1, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Odds ratio: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Odds ratio: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Odds ratio: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Odds ratio: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Odds ratio: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 12.1.3.1 Figure merged
Open code
plotac <- "sup_figure_2"
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}12.2 GFR by GPL_BC
12.2.1 Prior
Open code
GFR_sd <- sd(data_model_priorImpute$GFR_MDRD_3)
GFR_sd
## [1] 21.17099
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_sens$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_sens$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_sens$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_sens$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"),
set_prior("student_t(3, 0, 12)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 6)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", mean(data_sens$GFR_MDRD_3), ", 200)"),
class = "Intercept")
)12.2.2 Model
Open code
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens <- run(
expr = brm(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = student(),
data = data_sens,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 5000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPL_BC_interaction_NL_sens",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens, robust = TRUE)
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_sens (Number of observations: 170)
## Draws: 4 chains, each with iter = 5000; warmup = 2000; thin = 1;
## total post-warmup draws = 12000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 11.20 6.61 1.62 34.72 1.00
## sds(sGPL_BC_log2infliximab_1) 3.88 3.51 0.18 16.96 1.00
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 6605 4667
## sds(sGPL_BC_log2infliximab_1) 9867 5840
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept 54.48 3.96 46.64 62.36 1.00 12007
## male_sex 0.41 3.26 -5.97 6.84 1.00 15848
## Irec_ageM50 0.04 0.15 -0.26 0.34 1.00 13956
## male_sex_donor -1.93 3.21 -8.21 4.26 1.00 12991
## IKDPIM50 -0.24 0.08 -0.40 -0.08 1.00 12943
## ICITM15 0.30 0.21 -0.12 0.73 1.00 13879
## IHLA_MMM5 -1.31 1.09 -3.48 0.81 1.00 14212
## perfusion_event -6.06 3.30 -12.45 0.55 1.00 14300
## infliximab -0.72 82.88 -163.16 159.97 1.00 5182
## sGPL_BC_log2_1 -15.58 14.08 -48.00 14.59 1.00 8623
## sGPL_BC_log2:infliximab_1 -7.88 56.44 -117.16 101.60 1.00 5192
## sGPL_BC_log2:infliximab_2 7.33 24.27 -39.34 54.80 1.00 5300
## Tail_ESS
## Intercept 9598
## male_sex 8660
## Irec_ageM50 8904
## male_sex_donor 9353
## IKDPIM50 8879
## ICITM15 8775
## IHLA_MMM5 8500
## perfusion_event 8473
## infliximab 6764
## sGPL_BC_log2_1 7794
## sGPL_BC_log2:infliximab_1 6742
## sGPL_BC_log2:infliximab_2 6973
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 18.48 1.33 15.82 21.18 1.00 9271 8073
## nu 16.67 9.85 5.57 51.30 1.00 10706 8564
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens)
## prior class
## (flat) b
## normal(0, 5.95314681980334) b
## normal(0, 28.0492387472281) b
## normal(0, 2.06314246193193) b
## normal(0, 84.6839516288788) b
## normal(0, 4.11656184148077) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## normal(0, 84.6839516288788) b
## (flat) b
## (flat) b
## (flat) b
## normal(51.1232941176471, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 19.5) sds
## student_t(3, 0, 12) sds
## student_t(3, 0, 6) sds
## student_t(3, 0, 19.5) sigma
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 1
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## default
## user
## user
## default
tr2 <- round(fixef(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens,
robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)
antibody_seq <- quantile(data_sens$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get Estimate for infliximab effect across antibody values
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
(prediction$p95 - prediction$p05)/scaling_unit,
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR), after excluding patients with anti-cardiolipin IgG levels above the maximum in the IFX group and while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 0.41 | -5.97 | 6.84 |
| Irec_ageM50 | 0.04 | -0.26 | 0.34 |
| male_sex_donor | -1.93 | -8.21 | 4.26 |
| IKDPIM50 | -0.24 | -0.40 | -0.08 |
| ICITM15 | 0.30 | -0.12 | 0.73 |
| IHLA_MMM5 | -1.31 | -3.48 | 0.81 |
| perfusion_event | -6.06 | -12.45 | 0.55 |
| infliximab:GPL_BC_log2 | -16.54 | -36.53 | 3.22 |
12.2.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_sens$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control")),
`Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 125),
breaks = c(seq(0, 125, by = 25))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
geom_point(data = data_sens,
aes(x = GPL_BC_log2, y = GFR_MDRD_3, col = group, fill = group)) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"),
y = "GFR (mL/min/1.73 m²)") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size = 10),
axis.title=element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.801712 2.071126
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = b_GPL_BC_log2,
infliximab = b_GPL_BC_log2_infliximab) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% -9.0 -23.8
## 97.5% 20.5 2.3
## 50% 5.7 -10.7
## 0.1% -18.8 -31.8
## 99.9% 30.6 9.0
xpos <- 39.2
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect of aCL IgG increase (p05 to p95) on eGFR',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(-50, 52)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## p05 p25 p50 p75 p95
## 2.5% -5.0 -5.6 -7.4 -11.4 -23.5
## 97.5% 17.4 9.4 5.5 2.7 2.4
## 50% 6.2 1.9 -0.9 -4.2 -10.3
## 0.1% -11.3 -10.4 -11.8 -16.0 -30.6
## 99.9% 23.9 13.8 9.1 6.9 10.2
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(-40, 40)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Estimate: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Estimate: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Estimate: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 12.2.3.1 Figure merged
Open code
plotac <- 'sup_figure_6'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}13 DGF Subgroup analysis by GPL_BC
We will use data divided to patients with under- and above-median value of aCL IgG (GPL_BC)
13.1 Define priors
Open code
priors_subset <- c(
create_prior("GPL_BC_log2",
2 / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
coef = "GPL_BC_log2"
),
create_prior("IHLA_MMM5",
2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"
),
create_prior("IKDPIM50",
2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
coef = "IKDPIM50"
),
create_prior("Irec_ageM50",
2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"
),
create_prior("ICITM15",
2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
coef = "ICITM15"
),
create_prior("male_sex",
4,
coef = "male_sex"
),
create_prior("perfusion_event",
4,
coef = "perfusion_event"
),
create_prior("male_sex_donor",
4,
coef = "male_sex_donor"
),
create_prior("infliximab",
4,
coef = "infliximab"
),
set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
class = "Intercept"
)
)13.2 Fit model for \(<\) median aCL IgG level
Open code
model_dgf_GPL_BC_lowGPLBC <- run(
expr = brm(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
GPL_BC_log2,
family = bernoulli(),
data = data_imputed_lowGPL,
prior = priors_subset,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 4000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_GPL_BC_lowGPLBC",
reuse = TRUE
)
summary(model_dgf_GPL_BC_lowGPLBC, robust = TRUE)
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2
## Data: data_imputed_lowGPL (Number of observations: 88)
## Draws: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
## total post-warmup draws = 8000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -1.15 0.88 -2.92 0.57 1.00 6103 5642
## male_sex 0.66 0.61 -0.50 1.88 1.00 7547 5709
## Irec_ageM50 -0.00 0.03 -0.05 0.05 1.00 7614 6063
## male_sex_donor 0.63 0.56 -0.53 1.77 1.00 7908 5889
## IKDPIM50 0.00 0.01 -0.03 0.03 1.00 6795 5914
## ICITM15 0.08 0.04 -0.00 0.16 1.00 7322 6440
## IHLA_MMM5 0.26 0.20 -0.12 0.67 1.00 6960 6236
## perfusion_event -0.43 0.58 -1.61 0.69 1.00 7869 6343
## infliximab -1.55 0.57 -2.74 -0.45 1.00 6379 5667
## GPL_BC_log2 -0.49 0.35 -1.22 0.18 1.00 7280 6096
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_GPL_BC_lowGPLBC)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 1.41170525720746) b GPL_BC_log2
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.667829372575656, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_dgf_GPL_BC_lowGPLBC, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms and including only patients with anti-cardiolipin IgG level below median. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| OR | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 1.94 | 0.61 | 6.59 |
| Irec_ageM50 | 1.00 | 0.95 | 1.05 |
| male_sex_donor | 1.87 | 0.59 | 5.88 |
| IKDPIM50 | 1.00 | 0.97 | 1.03 |
| ICITM15 | 1.08 | 1.00 | 1.18 |
| IHLA_MMM5 | 1.30 | 0.89 | 1.96 |
| perfusion_event | 0.65 | 0.20 | 2.00 |
| infliximab | 0.21 | 0.06 | 0.64 |
| GPL_BC_log2 | 0.61 | 0.29 | 1.20 |
13.3 Fit model for aCL \(\geq\) median
Open code
model_dgf_GPL_BC_highGPLBC <- run(
expr = brm(
DGF ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
GPL_BC_log2,
family = bernoulli(),
data = data_imputed_highGPL,
prior = priors_subset,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 4000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_dgf_GPL_BC_highGPLBC",
reuse = TRUE
)
summary(model_dgf_GPL_BC_highGPLBC, robust = TRUE)
## Family: bernoulli
## Links: mu = logit
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2
## Data: data_imputed_highGPL (Number of observations: 89)
## Draws: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
## total post-warmup draws = 8000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept -2.17 0.82 -3.90 -0.66 1.00 5958 5518
## male_sex 1.56 0.59 0.44 2.78 1.00 6964 5785
## Irec_ageM50 -0.04 0.02 -0.09 0.01 1.00 7544 6006
## male_sex_donor 0.31 0.58 -0.82 1.46 1.00 7261 6549
## IKDPIM50 0.02 0.01 -0.00 0.05 1.00 6958 6417
## ICITM15 0.08 0.04 0.01 0.16 1.00 7101 5523
## IHLA_MMM5 0.33 0.20 -0.05 0.74 1.00 6725 5730
## perfusion_event -0.96 0.61 -2.22 0.20 1.00 6888 5602
## infliximab 1.06 0.55 0.00 2.16 1.00 7743 6408
## GPL_BC_log2 0.33 0.25 -0.16 0.84 1.00 7068 6138
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_dgf_GPL_BC_highGPLBC)
## prior class coef group resp dpar nlpar
## (flat) b
## normal(0, 1.41170525720746) b GPL_BC_log2
## normal(0, 0.280307006032291) b ICITM15
## normal(0, 1.38219051128263) b IHLA_MMM5
## normal(0, 0.0970980394231448) b IKDPIM50
## normal(0, 4) b infliximab
## normal(0, 0.190589762164436) b Irec_ageM50
## normal(0, 4) b male_sex
## normal(0, 4) b male_sex_donor
## normal(0, 4) b perfusion_event
## normal(-0.667829372575656, 10) Intercept
## lb ub source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## user
## user
tr <- round(exp(fixef(model_dgf_GPL_BC_highGPLBC, robust = TRUE)[-1, c(1,3,4)]), 3)
colnames(tr)[1] <- 'Odds ratio'
kableExtra::kable(tr)infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms and including only patients with anti-cardiolipin IgG level at/above median. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Odds ratio | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | 4.754 | 1.548 | 16.143 |
| Irec_ageM50 | 0.964 | 0.918 | 1.012 |
| male_sex_donor | 1.361 | 0.440 | 4.314 |
| IKDPIM50 | 1.024 | 0.996 | 1.055 |
| ICITM15 | 1.083 | 1.008 | 1.179 |
| IHLA_MMM5 | 1.387 | 0.950 | 2.098 |
| perfusion_event | 0.382 | 0.108 | 1.218 |
| infliximab | 2.897 | 1.005 | 8.695 |
| GPL_BC_log2 | 1.397 | 0.855 | 2.324 |
14 Models eGFR with at least 480 days of FU with graft functioning
Open code
data_sens2 <- data_first %>%
filter(
GFR_days_2 >= 480 | death_event == 1 | graft_failure == 1
) %>%
mutate(group = factor(if_else(infliximab == 1, 'infliximab', 'control')))
dim(data_sens2)
## [1] 154 3314.1 by GPL_BC
14.1.1 Prior
Open code
GFR_sd <- sd(data_sens2$GFR_MDRD_3)
GFR_sd
## [1] 19.93074
priors_interaction_pnl <- c(
create_prior("Irec_ageM50",
(2*GFR_sd) / sd(data_sens2$rec_age, na.rm = TRUE),
coef = "Irec_ageM50"),
create_prior("IHLA_MMM5",
(2*GFR_sd) / sd(data_sens2$HLA_MM, na.rm = TRUE),
coef = "IHLA_MMM5"),
create_prior("IKDPIM50",
(2*GFR_sd) / sd(data_sens2$KDPI, na.rm = TRUE),
coef = "IKDPIM50"),
create_prior("ICITM15",
(2*GFR_sd) / sd(data_sens2$CIT, na.rm = TRUE),
coef = "ICITM15"),
create_prior("male_sex",
4*GFR_sd,
coef = "male_sex"),
create_prior("perfusion_event",
4*GFR_sd,
coef = "perfusion_event"),
create_prior("male_sex_donor",
4*GFR_sd,
coef = "male_sex_donor"),
create_prior("infliximab",
4*GFR_sd,
coef = "infliximab"),
set_prior("student_t(3, 0, 12)", class = "sds",
coef = 's(GPL_BC_log2, bs = "ps", k = 5)'),
set_prior("student_t(3, 0, 6)", class = "sds",
coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'),
set_prior(paste0("normal(", mean(data_sens2$GFR_MDRD_3), ", 200)"),
class = "Intercept")
)14.1.2 Model
Open code
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2 <- run(
expr = brm(
GFR_MDRD_3 ~
male_sex +
I(rec_age - 50) +
male_sex_donor +
I(KDPI - 50) +
I(CIT - 15) +
I(HLA_MM - 5) +
perfusion_event +
infliximab +
s(GPL_BC_log2, bs = 'ps', k = 5) +
s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
family = student(),
data = data_sens2,
prior = priors_interaction_pnl,
backend = "cmdstanr",
seed = 2025,
cores = 4, chains = 4,
iter = 5000, warmup = 2000,
control = list(adapt_delta = 0.95)
),
path = "gitignore/run/model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2",
reuse = TRUE
)
summary(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2, robust = TRUE)
## Family: student
## Links: mu = identity; sigma = identity; nu = identity
## Formula: GFR_MDRD_3 ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)
## Data: data_sens2 (Number of observations: 154)
## Draws: 4 chains, each with iter = 5000; warmup = 2000; thin = 1;
## total post-warmup draws = 12000
##
## Smoothing Spline Hyperparameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1) 12.04 7.29 1.37 36.66 1.00
## sds(sGPL_BC_log2infliximab_1) 4.12 3.89 0.17 19.70 1.00
## Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1) 5502 3578
## sds(sGPL_BC_log2infliximab_1) 10206 5052
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept 55.76 4.06 47.63 63.70 1.00 13224
## male_sex -1.06 3.33 -7.56 5.51 1.00 14555
## Irec_ageM50 0.05 0.15 -0.25 0.35 1.00 14540
## male_sex_donor -2.57 3.37 -9.26 4.05 1.00 13238
## IKDPIM50 -0.29 0.08 -0.45 -0.12 1.00 13489
## ICITM15 0.29 0.22 -0.15 0.71 1.00 14845
## IHLA_MMM5 -1.23 1.11 -3.43 0.90 1.00 13879
## perfusion_event -3.56 3.30 -10.19 2.95 1.00 14153
## infliximab -0.24 77.61 -152.88 148.64 1.00 5557
## sGPL_BC_log2_1 9.25 16.77 -26.48 50.93 1.00 9004
## sGPL_BC_log2:infliximab_1 -13.97 44.82 -100.82 73.77 1.00 5580
## sGPL_BC_log2:infliximab_2 9.71 28.48 -44.52 65.44 1.00 5760
## Tail_ESS
## Intercept 9055
## male_sex 7481
## Irec_ageM50 9607
## male_sex_donor 8737
## IKDPIM50 9901
## ICITM15 9479
## IHLA_MMM5 9397
## perfusion_event 9125
## infliximab 6824
## sGPL_BC_log2_1 6562
## sGPL_BC_log2:infliximab_1 6926
## sGPL_BC_log2:infliximab_2 6841
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 17.96 1.25 15.50 20.51 1.00 11959 8561
## nu 21.30 12.37 6.57 61.21 1.00 12525 7831
##
## Draws were sampled using sample(hmc). 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).
prior_summary(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2)
## prior class
## (flat) b
## normal(0, 5.48898844779997) b
## normal(0, 25.9053313823118) b
## normal(0, 1.95751635259431) b
## normal(0, 79.7229697409756) b
## normal(0, 3.82892016085826) b
## normal(0, 79.7229697409756) b
## normal(0, 79.7229697409756) b
## normal(0, 79.7229697409756) b
## (flat) b
## (flat) b
## (flat) b
## normal(51.4243506493507, 200) Intercept
## gamma(2, 0.1) nu
## student_t(3, 0, 18.2) sds
## student_t(3, 0, 12) sds
## student_t(3, 0, 6) sds
## student_t(3, 0, 18.2) sigma
## coef group resp dpar nlpar lb ub
##
## ICITM15
## IHLA_MMM5
## IKDPIM50
## infliximab
## Irec_ageM50
## male_sex
## male_sex_donor
## perfusion_event
## sGPL_BC_log2_1
## sGPL_BC_log2:infliximab_1
## sGPL_BC_log2:infliximab_2
##
## 1
## 0
## s(GPL_BC_log2, bs = "ps", k = 5) 0
## s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 0
## 0
## source
## default
## user
## user
## user
## user
## user
## user
## user
## user
## (vectorized)
## (vectorized)
## (vectorized)
## user
## default
## default
## user
## user
## default
tr2 <- round(fixef(model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2,
robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)
antibody_seq <- quantile(data_sens2$GPL_BC_log2,
probs = c(0.05, 0.95))
asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
## get Estimate for infliximab effect across antibody values
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p95')
infliximab_GPL_BC_log2_int <- quantile(
(prediction$p95 - prediction$p05)/scaling_unit,
probs = c(0.5, 1/40, 39/40))
tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR), after excluding patients which were lost during follow-up before 480th day post TX and while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
| Estimate | Q2.5 | Q97.5 | |
|---|---|---|---|
| male_sex | -1.06 | -7.56 | 5.51 |
| Irec_ageM50 | 0.05 | -0.25 | 0.35 |
| male_sex_donor | -2.57 | -9.26 | 4.05 |
| IKDPIM50 | -0.29 | -0.45 | -0.12 |
| ICITM15 | 0.29 | -0.15 | 0.71 |
| IHLA_MMM5 | -1.23 | -3.43 | 0.90 |
| perfusion_event | -3.56 | -10.19 | 2.95 |
| infliximab:GPL_BC_log2 | -17.76 | -37.37 | 1.55 |
14.1.3 Visualisation - penalized non-linear effect
Extract posterior draws
Open code
antibody_perc <- quantile(data_sens2$GPL_BC_log2,
probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))
antibody_seq <- seq(antibody_perc[1],
antibody_perc[length(antibody_perc)],
length.out = 101)
## create prediction
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
prediction <- data.frame(
posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2,
newdata = data_prediction) %>% posterior_summary(
robust = TRUE
) %>% data.frame() %>% select(-Est.Error),
group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
GPL_BC_log2 = data_prediction$GPL_BC_log2)Figure A
Open code
cole <- c('#CD7006', '#0028F0')
fig_a <- prediction %>%
mutate(group = factor(group, levels = c("infliximab", "control")),
`Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>%
ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) +
geom_line(aes(y = Estimate), linewidth = 1) +
scale_y_continuous(limits = c(0, 125),
breaks = c(seq(0, 125, by = 25))) +
geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
alpha = 0.4, color = NA) +
geom_point(data = data_sens2,
aes(x = GPL_BC_log2, y = GFR_MDRD_3, col = group, fill = group)) +
labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"),
y = "GFR (mL/min/1.73 m²)") +
scale_color_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_fill_manual(values = cole,
name = "group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
facet_grid(rows = vars(group)) +
theme(axis.text=element_text(size = 10),
axis.title=element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "none") +
geom_vline(xintercept = antibody_perc[3:7], linetype = 2,
color = "grey50", size = 0.3)Figure B
Open code
antibody_seq <- antibody_perc[c(3, 7)]
antibody_seq
## 5% 95%
## -1.778673 2.435576
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2,
newdata = data_prediction)
tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])
post_fix <- data.frame(
b_GPL_BC_log2 = tr_ctrl,
b_GPL_BC_log2_infliximab = tr_infliximab
)
tr <- post_fix %>%
mutate(control = b_GPL_BC_log2,
infliximab = b_GPL_BC_log2_infliximab) %>%
select(control, infliximab) %>%
data.frame()
CIS <- sapply(
tr,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## control infliximab
## 2.5% -6.7 -25.6
## 97.5% 19.9 3.5
## 50% 6.7 -11.2
## 0.1% -14.6 -33.4
## 99.9% 26.5 10.7
xpos <- 39.2
fig_b <- tr %>%
pivot_longer(values_to = 'value',
cols = c('control', 'infliximab'),
names_to = 'group') %>%
ggplot(aes(x = value, y = group, fill = group)) +
stat_halfeye(.width = c(0.95), slab_alpha=0.5,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = 'Effect of aCL IgG increase (p05 to p95) on eGFR',
y = 'Treatment group') +
scale_fill_manual(values = cole,
name = "Treatment group",
breaks = c('control', 'infliximab'),
labels = c('control', 'infliximab')) +
scale_y_discrete(expand = expansion(add = 0.1)) +
coord_cartesian(xlim = c(-50, 52)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 2.85 ,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85 ,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 2.6 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.6 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) Figure C
Open code
cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
asl <- length(antibody_seq)
data_prediction <- data.frame(
male_sex = rep(mmale_sex, 2*length(antibody_seq)),
`male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
`perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
`infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
`rec_age` = rep(mrec_age, 2*length(antibody_seq)),
`KDPI` = rep(mKDPI, 2*length(antibody_seq)),
`CIT` = rep(mCIT, 2*length(antibody_seq)),
`HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
`GPL_BC_log2` = c(antibody_seq, antibody_seq)
)
tr <- posterior_epred(
model_GFR_MDRD_3_GPL_BC_interaction_NL_sens2,
newdata = data_prediction)
prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]
prediction <- (
prediction_infliximab-
prediction_ctrl
) %>% data.frame()
names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')
CIS <- sapply(
prediction,
function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
) %>%
round(1)
CIS
## p05 p25 p50 p75 p95
## 2.5% -7.0 -7.3 -9.0 -13.2 -26.1
## 97.5% 15.6 8.4 4.2 1.2 -0.7
## 50% 4.3 0.5 -2.5 -6.1 -13.5
## 0.1% -13.3 -11.4 -13.1 -17.9 -33.5
## 99.9% 22.7 12.6 8.0 5.4 7.4
fig_c <- prediction %>%
pivot_longer(values_to = 'value',
cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
names_to = 'GPL_BC_percentile') %>%
ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
linewidth = 5,
shape = 18,
point_size = 5,
normalize = "groups",
p_limits = c(1e-3, 1-1e-3)) +
labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)",
y = 'Percentile of aCL IgG value') +
scale_fill_manual(values = cole,
name = "Percentile of aCL IgG value",
breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
coord_cartesian(xlim = c(-40, 40)) +
scale_y_discrete(expand = expansion(add = 0.1)) +
geom_vline(xintercept = 0, linetype = 2,
color = "red", size = 0.6) +
theme(axis.text = element_text(size = 12),
axis.title = element_text(size = 12)) +
theme(legend.position = "none") +
annotate("text", x = xpos, y = 5.85 ,
label = paste0("Estimate: ", CIS[3,5]),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.85,
label = paste0("Estimate: ", CIS[3,4]),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.85,
label = paste0("Estimate: ", CIS[3,3]),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.85,
label = paste0("Estimate: ", CIS[3,2]),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.85,
label = paste0("Estimate: ", CIS[3,1]),
color = cole[1] ) +
annotate("text", x = xpos, y = 5.5 ,
label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
color = cole[5] ) +
annotate("text", x = xpos, y = 4.5 ,
label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
color = cole[4] ) +
annotate("text", x = xpos, y = 3.5 ,
label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
color = cole[3] ) +
annotate("text", x = xpos, y = 2.5 ,
label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
color = cole[2] ) +
annotate("text", x = xpos, y = 1.5 ,
label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
color = cole[1] ) 14.1.3.1 Figure merged
Open code
plotac <- 'sup_figure_8'
path <- "gitignore/figures"
fig <- cowplot::plot_grid(fig_b, fig_c,
rel_heights = c(0.7, 1),
labels = c("B", "C"),
ncol = 1
)
assign(
plotac,
cowplot::plot_grid(
fig_a, fig,
rel_widths = c(0.6, 1),
labels = c("A", "")
)
)
get(plotac)
if (file.exists(paste0(path, "/", plotac)) == FALSE) {
ggsave(
path = paste0(path),
filename = plotac,
device = "pdf",
width = 9,
height = 6
)
}15 Tables and Figures: list with links
15.1 Figures
Figure 1: data distributions across groups
Supplementary Figure 1: Spearman correlations
Figure 2: DGF risk according to infliximab:aCL IgG non-linear interaction.
Supplementary Figure 2: DGF risk according to infliximab:aCL IgG non-linear interaction but after excluding the patients with large aCL IgG values
Supplementary Figure 3: DGF risk according to infliximab:aCL IgM non-linear interaction
Supplementary Figure 4: eGFR according to infliximab:aCL IgG non-linear interaction
Supplementary Figure 5: eGFR according to infliximab:aCL IgM non-linear interaction
Supplementary Figure 6: eGFR according to infliximab:aCL IgG non-linear interaction but after excluding the patients with large aCL IgG values
Supplementary Figure 7: eGFR according to infliximab:aCL IgG non-linear interaction but without imputing eGFR values in cases of graft loss
Supplementary Figure 8: eGFR according to infliximab:aCL IgG non-linear interaction, excluding patients with lost of follow up before 480th day after transplantation
Supplementary Figure 9: infection risk according to infliximab:aPE-ind IgG non-linear interaction.
Supplementary Figure 10: infection risk according to infliximab:aPE-dep IgG non-linear interaction.
15.2 Tables
Supplementary Table 1: demography stratified by treatment
Supplementary Table 1 - alternative: demography stratified by treatment and aCL IgG levls (below and at/above median)
Supplementary Table 3: post-transplant outcomes by treatment
Supplementary Table 4: post-transplant outcomes by DGF and treatment
Supplementary Table 5: unadjusted effect of different variables on DGF
Table 1: IFX x nAb non-linear interaction effects based on Bayesian logistic multivariable models
Table 2: IFX x nAb non-linear interaction effects based on Bayesian robust multivariable models modelling eGFR
Supplementary Table 6: unadjusted effect of different variables on eGFR
Supplementary Table 7: mediation analysis
Supplementary Table 9: unadjusted effect of different variables on infection risk
Supplementary Table 10: unadjusted effect of different variables on BKV infection
16 Reproducibility
Open code
sessionInfo()
## R version 4.4.3 (2025-02-28)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 22.04.5 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=cs_CZ.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=cs_CZ.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=cs_CZ.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=cs_CZ.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Europe/Prague
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] bayestestR_0.14.0 mice_3.17.0 ggbeeswarm_0.6.0 quantreg_5.98
## [5] SparseM_1.81 coxed_0.3.3 survival_3.7-0 rms_6.8-1
## [9] Hmisc_5.1-3 bayesplot_1.8.1 ggdist_3.3.2 kableExtra_1.4.0
## [13] lubridate_1.9.4 corrplot_0.92 arm_1.12-2 lme4_1.1-35.5
## [17] MASS_7.3-65 janitor_2.2.0 projpred_2.0.2 brms_2.21.0
## [21] Rcpp_1.0.13 glmnet_4.1-8 Matrix_1.7-0 boot_1.3-31
## [25] cowplot_1.1.1 pROC_1.18.0 mgcv_1.9-1 nlme_3.1-168
## [29] openxlsx_4.2.8 flextable_0.9.6 sjPlot_2.8.16 RJDBC_0.2-10
## [33] rJava_1.0-11 DBI_1.2.3 car_3.1-2 carData_3.0-5
## [37] skimr_2.1.5 gtsummary_2.0.2 emmeans_1.10.4 ggpubr_0.4.0
## [41] stringi_1.8.7 forcats_1.0.0 stringr_1.5.1 dplyr_1.1.4
## [45] purrr_1.0.4 readr_2.1.5 tidyr_1.3.1 tibble_3.3.0
## [49] ggplot2_3.5.1 tidyverse_1.3.1
##
## loaded via a namespace (and not attached):
## [1] fs_1.6.6 matrixStats_1.3.0 httr_1.4.2
## [4] insight_0.20.2 repr_1.1.7 tools_4.4.3
## [7] backports_1.5.0 sjlabelled_1.2.0 R6_2.6.1
## [10] jomo_2.7-3 withr_3.0.2 Brobdingnag_1.2-7
## [13] prettyunits_1.2.0 gridExtra_2.3 cli_3.6.5
## [16] textshaping_0.3.6 performance_0.12.2 gt_0.11.0
## [19] officer_0.6.6 sandwich_3.0-1 labeling_0.4.2
## [22] sass_0.4.9 mvtnorm_1.1-3 polspline_1.1.25
## [25] ggridges_0.5.3 askpass_1.1 QuickJSR_1.3.1
## [28] systemfonts_1.0.4 commonmark_1.9.1 StanHeaders_2.32.10
## [31] foreign_0.8-90 gfonts_0.2.0 svglite_2.1.3
## [34] readxl_1.3.1 rstudioapi_0.16.0 httpcode_0.3.0
## [37] generics_0.1.4 shape_1.4.6 distributional_0.4.0
## [40] zip_2.2.0 inline_0.3.19 loo_2.4.1
## [43] abind_1.4-5 lifecycle_1.0.4 multcomp_1.4-18
## [46] yaml_2.3.10 snakecase_0.11.1 grid_4.4.3
## [49] promises_1.2.0.1 crayon_1.5.3 mitml_0.4-3
## [52] lattice_0.22-5 haven_2.4.3 pillar_1.11.0
## [55] knitr_1.50 estimability_1.5.1 codetools_0.2-19
## [58] pan_1.6 glue_1.7.0 V8_4.4.2
## [61] fontLiberation_0.1.0 data.table_1.15.4 vctrs_0.6.5
## [64] cellranger_1.1.0 gtable_0.3.0 assertthat_0.2.1
## [67] datawizard_0.12.2 xfun_0.52 mime_0.12
## [70] coda_0.19-4 iterators_1.0.14 TH.data_1.1-0
## [73] fontquiver_0.2.1 rstan_2.32.6 tensorA_0.36.2.1
## [76] vipor_0.4.5 rpart_4.1.24 colorspace_2.0-2
## [79] nnet_7.3-20 tidyselect_1.2.1 processx_3.8.4
## [82] compiler_4.4.3 curl_6.4.0 rvest_1.0.2
## [85] htmlTable_2.4.0 xml2_1.3.3 fontBitstreamVera_0.1.1
## [88] posterior_1.6.0 checkmate_2.3.2 scales_1.3.0
## [91] callr_3.7.6 digest_0.6.37 minqa_1.2.4
## [94] rmarkdown_2.27 htmltools_0.5.8.1 pkgconfig_2.0.3
## [97] base64enc_0.1-3 dbplyr_2.1.1 fastmap_1.2.0
## [100] rlang_1.1.6 htmlwidgets_1.6.4 shiny_1.9.1
## [103] farver_2.1.0 zoo_1.8-9 jsonlite_2.0.0
## [106] magrittr_2.0.3 Formula_1.2-4 munsell_0.5.0
## [109] gdtools_0.3.7 plyr_1.8.6 pkgbuild_1.3.1
## [112] parallel_4.4.3 sjmisc_2.8.10 ggeffects_1.7.0
## [115] splines_4.4.3 hms_1.1.3 sjstats_0.19.0
## [118] ps_1.7.7 uuid_1.0-3 ggsignif_0.6.3
## [121] markdown_1.13 reshape2_1.4.4 stats4_4.4.3
## [124] rstantools_2.1.1 crul_1.5.0 reprex_2.0.1
## [127] evaluate_1.0.4 RcppParallel_5.1.8 modelr_0.1.8
## [130] nloptr_2.0.0 tzdb_0.5.0 foreach_1.5.2
## [133] httpuv_1.6.5 MatrixModels_0.5-3 cards_0.2.2
## [136] openssl_1.4.6 cardx_0.2.1 broom_1.0.6
## [139] xtable_1.8-4 rstatix_0.7.0 later_1.3.0
## [142] viridisLite_0.4.0 ragg_1.4.0 beeswarm_0.4.0
## [145] cluster_2.1.8.1 gamm4_0.2-6 timechange_0.3.0
## [148] cmdstanr_0.8.0.9000 bridgesampling_1.1-2