suppressPackageStartupMessages({
library(masbayes); library(masreml); library(dplyr); library(ggplot2)
})
d <- masbayes::load_data("large")$multigen
bid <- attr(d$gen1$mh, "block_id")
MCMC_P <- list(n_iter = 2000L, n_burn = 1000L, n_thin = 5L, seed = 123L)
N_BOOT <- 200L
get_train_arch <- function(scenario, arch) {
pheno_col <- paste0("y_cont_qtl_", arch)
if (scenario == "A") {
list(y = d$gen1$pheno[[pheno_col]],
sx = d$gen1$pheno$sex, ids = d$gen1$pheno$id)
} else {
cohort <- d[[paste0("gen2_", arch)]]
list(y = c(d$gen1$pheno[[pheno_col]], cohort$pheno[[pheno_col]]),
sx = factor(c(as.character(d$gen1$pheno$sex),
as.character(cohort$pheno$sex)),
levels = c("F", "M")),
ids = c(d$gen1$pheno$id, cohort$pheno$id))
}
}
get_test_arch <- function(scenario, arch) {
cohort <- if (scenario == "A") d[[paste0("gen2_", arch)]]
else d[[paste0("gen3_", arch)]]
list(snp = cohort$snp, mh = cohort$mh,
sx = cohort$pheno$sex, ids = cohort$pheno$id,
y = cohort$pheno[[paste0("y_cont_qtl_", arch)]],
tbv = cohort$pheno[[paste0("tbv_qtl_", arch, "_true")]])
}
build_marker_matrices <- function(scenario, arch, marker) {
tr <- get_train_arch(scenario, arch)
te <- get_test_arch(scenario, arch)
ids_tr <- tr$ids; ids_te <- te$ids
ids_all <- c(ids_tr, ids_te)
if (scenario == "A") {
snp_full <- rbind(d$gen1$snp, te$snp)
mh_full <- rbind(d$gen1$mh, te$mh)
} else {
cohort2 <- d[[paste0("gen2_", arch)]]
snp_full <- rbind(d$gen1$snp, cohort2$snp, te$snp)
mh_full <- rbind(d$gen1$mh, cohort2$mh, te$mh)
}
rownames(snp_full) <- ids_all; rownames(mh_full) <- ids_all
if (marker == "snp") {
snp_train_obj <- construct_snp_matrix(snp_full[ids_tr, ])
W_tr <- snp_train_obj$W
W_te <- construct_snp_matrix(snp_full[ids_te, ],
ref_freq = snp_train_obj$freq)$W
G_full <- build_G_snp(snp_full, ref_W = snp_full[ids_tr, ])
G_key <- "snp_add"; mtype <- "snp"
} else {
ref_struct <- if (scenario == "A") d$reference_structure_gen1
else if (arch == "snp") d$reference_structure_gen1_gen2_snp
else d$reference_structure_gen1_gen2_mh
W_tr <- ref_struct$W_ah
W_te <- construct_wah_matrix(mh_full[ids_te, , drop = FALSE], bid, NULL,
reference_structure = ref_struct)$W_ah
G_full <- build_G_mh(mh_full, ref_mh = mh_full[ids_tr, ], ids = ids_all)
G_key <- "mh_add"; mtype <- "multiallelic"
}
X_tr <- model.matrix(~ tr$sx - 1); X_te <- model.matrix(~ te$sx - 1)
colnames(X_tr) <- colnames(X_te) <- c("F", "M")
rownames(X_tr) <- ids_tr; rownames(X_te) <- ids_te
list(y_tr = tr$y, X_tr = X_tr, X_te = X_te,
W_tr = W_tr, W_te = W_te,
G_full = G_full, G_key = G_key,
ids_tr = ids_tr, ids_te = ids_te,
tbv_te = te$tbv, y_te = te$y, marker_type = mtype)
}
fit_bayesa <- function(p) {
vy <- var(p$y_tr)
fit <- run_bayesa(w = p$W_tr, X = p$X_tr, y = p$y_tr,
marker_type = p$marker_type,
nu = 4.5, sigma2_g = vy * 0.5, sigma2_e_init = vy * 0.5,
prior_params = list(a0_e = 10), mcmc_params = MCMC_P,
method = "mcmc", save_rds = FALSE, verbose = FALSE)
predict(fit, p$W_te, p$y_te, X_new = p$X_te)$GEBV
}
fit_bayesr <- function(p) {
vy <- var(p$y_tr)
fit <- run_bayesr(w = p$W_tr, X = p$X_tr, y = p$y_tr,
marker_type = p$marker_type,
pi_vec = c(0.90, 0.05, 0.03, 0.02),
sigma2_e_init = vy * 0.5, sigma2_ah = vy * 0.5,
prior_params = list(a0_e = 10, a0_g = 10,
variance_class = c(0, 0.01, 0.1, 1)),
mcmc_params = MCMC_P,
method = "mcmc", save_rds = FALSE, verbose = FALSE)
predict(fit, p$W_te, p$y_te, X_new = p$X_te)$GEBV
}
fit_gblup <- function(p) {
G_train <- p$G_full[p$ids_tr, p$ids_tr]
fit <- masreml(y = setNames(p$y_tr, p$ids_tr), X = p$X_tr,
G = setNames(list(G_train), p$G_key),
method = "auto", solver = "auto", trait = "continuous")
predict(fit, G_full = setNames(list(p$G_full), p$G_key),
train_ids = p$ids_tr, test_ids = p$ids_te,
X_new = p$X_te, y_new = setNames(p$y_te, p$ids_te))$GEBV
}
stat_fn <- function(stat) switch(stat,
cor = function(g, t) cor(g, t),
r2 = function(g, t) cor(g, t) ^ 2)
boot_se_stat <- function(gebv, tbv, n_boot, seed, stat) {
fn <- stat_fn(stat); set.seed(seed)
rs <- replicate(n_boot, {
idx <- sample(seq_along(tbv), replace = TRUE)
suppressWarnings(fn(gebv[idx], tbv[idx]))
}); sd(rs, na.rm = TRUE)
}
boot_paired_diff <- function(gebv_mh, gebv_snp, tbv, n_boot, seed, stat) {
fn <- stat_fn(stat); set.seed(seed)
diffs <- replicate(n_boot, {
idx <- sample(seq_along(tbv), replace = TRUE)
suppressWarnings(fn(gebv_mh[idx], tbv[idx]) - fn(gebv_snp[idx], tbv[idx]))
})
diffs <- diffs[is.finite(diffs)]
2 * min(mean(diffs >= 0), mean(diffs <= 0))
}
sig_code <- function(p) {
ifelse(is.na(p), "",
ifelse(p < 0.001, "***",
ifelse(p < 0.01, "**",
ifelse(p < 0.05, "*", "ns"))))
}
fitters <- list(bayesa = fit_bayesa, bayesr = fit_bayesr, gblup = fit_gblup)
combos <- expand.grid(scenario = c("A","B"), arch = c("snp","mh"),
marker = c("snp","mh"), model = names(fitters),
stringsAsFactors = FALSE)
sink_path <- tempfile()
res <- combos; res$r_test_g <- NA_real_; res$r_se <- NA_real_
gebv_list <- vector("list", nrow(combos)); tbv_list <- vector("list", nrow(combos))
for (i in seq_len(nrow(combos))) {
sink(sink_path)
pack <- build_marker_matrices(combos$scenario[i], combos$arch[i],
combos$marker[i])
gebv <- fitters[[combos$model[i]]](pack)
sink()
tbv <- pack$tbv_te
if (!is.null(names(gebv))) tbv <- tbv[match(names(gebv),
names(setNames(tbv, pack$ids_te)))]
gebv_list[[i]] <- as.numeric(gebv); tbv_list[[i]] <- as.numeric(tbv)
res$r_test_g[i] <- cor(gebv, tbv)
res$r_se[i] <- boot_se_stat(gebv, tbv, N_BOOT, 1000L + i, "cor")
}
unlink(sink_path)
res$reliability <- res$r_test_g ^ 2
res <- res %>%
left_join(res %>% filter(marker == "snp") %>%
transmute(scenario, arch, model, baseline_reliability = reliability),
by = c("scenario","arch","model")) %>%
mutate(rel_reliability = reliability / baseline_reliability)
res$p_cor <- NA_real_
for (sc in c("A","B")) for (a in c("snp","mh")) for (md in names(fitters)) {
i_snp <- which(res$scenario == sc & res$arch == a &
res$marker == "snp" & res$model == md)
i_mh <- which(res$scenario == sc & res$arch == a &
res$marker == "mh" & res$model == md)
res$p_cor[i_mh] <- boot_paired_diff(gebv_list[[i_mh]], gebv_list[[i_snp]],
tbv_list[[i_snp]], N_BOOT,
5000L + i_mh, "cor")
}
res$sig_cor <- sig_code(res$p_cor)
plot_df <- res %>%
mutate(Scenario = factor(scenario, levels = c("A","B"),
labels = c("1-generation forward",
"2-generation forward (cumulative)")),
Arch = factor(paste0("QTL@", toupper(arch)),
levels = c("QTL@SNP","QTL@MH")),
Marker = factor(toupper(marker), levels = c("SNP","MH")),
Model = factor(model, levels = c("bayesa","bayesr","gblup"),
labels = c("BayesA","BayesR","GBLUP")),
sig_cor = ifelse(marker == "mh", sig_cor, ""))
marker_colors <- c(SNP = "#56B4E9", MH = "#E69F00")