library(masbayes)
library(masreml)
# ββ CONFIG βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
config <- list(
seed = 42,
n_total = 300,
n_train = 200,
n_test = 100,
n_blocks = 50,
n_snp_per_block = 2,
h2_target = 0.3,
n_qtl = 10,
mcmc = list(
n_iter = 20000L,
n_burn = 10000L,
n_thin = 10L,
seed = 123L
),
bayesr = list(
pi_vec = c(0.90, 0.05, 0.03, 0.02),
variance_class = c(0, 0.01, 0.1, 1),
a0_e = 5,
a0_g = 5
),
bayesa = list(
nu = 4.5,
a0_e = 10
)
)
set.seed(config$seed)
n_total <- config$n_total
n_train <- config$n_train
n_test <- config$n_test
n_blocks <- config$n_blocks
n_snp_per_block <- config$n_snp_per_block
n_snp_total <- n_blocks * n_snp_per_block
# ββ 1. Generate SNP genotype βββββββββββββββββββββββββββββββββββββββββββββββββ
maf <- runif(n_snp_total, 0.1, 0.5)
geno_snp_all <- matrix(0L, nrow = n_total, ncol = n_snp_total)
for (j in 1:n_snp_total)
geno_snp_all[, j] <- as.integer(rbinom(n_total, 2, maf[j]))
# ββ 2. Phase SNP -> haplotype ββββββββββββββββββββββββββββββββββββββββββββββββ
hap_all <- matrix(0L, nrow = n_total, ncol = n_snp_total * 2)
for (j in 1:n_snp_total) {
for (i in 1:n_total) {
g <- geno_snp_all[i, j]
h1 <- if (g == 2) 1L else if (g == 0) 0L else as.integer(rbinom(1, 1, 0.5))
h2 <- as.integer(g - h1)
hap_all[i, 2*j-1] <- h1 + 1L
hap_all[i, 2*j ] <- h2 + 1L
}
}
storage.mode(hap_all) <- "integer"
# ββ 3. Reorder hap columns by block βββββββββββββββββββββββββββββββββββββββββ
hap_cols_per_block <- n_snp_per_block * 2
hap_reordered <- matrix(0L, nrow = n_total, ncol = n_snp_total * 2)
col_out <- 1
for (b in 1:n_blocks) {
for (j in ((b-1)*n_snp_per_block + 1):(b*n_snp_per_block)) {
hap_reordered[, col_out] <- hap_all[, 2*j-1]
hap_reordered[, col_out+1] <- hap_all[, 2*j ]
col_out <- col_out + 2
}
}
storage.mode(hap_reordered) <- "integer"
# ββ 4. Encode MH per block βββββββββββββββββββββββββββββββββββββββββββββββββββ
idx_train <- 1:n_train
idx_test <- (n_train+1):n_total
encode_hap <- function(mat)
apply(mat, 1, function(x) sum(x * 3^(seq_along(x)-1)))
hap_block_all <- matrix(0L, nrow = n_total, ncol = n_blocks * 2)
allele_freq_list <- list(haplotype=c(), allele=c(), freq=c())
for (b in 1:n_blocks) {
cols <- ((b-1)*hap_cols_per_block + 1):(b*hap_cols_per_block)
hap_sub <- hap_reordered[, cols]
h1_id <- encode_hap(hap_sub[, seq(1, hap_cols_per_block, 2), drop=FALSE])
h2_id <- encode_hap(hap_sub[, seq(2, hap_cols_per_block, 2), drop=FALSE])
hap_block_all[, 2*b-1] <- h1_id
hap_block_all[, 2*b ] <- h2_id
tbl <- table(c(h1_id[idx_train], h2_id[idx_train]))
freqs <- as.numeric(tbl) / sum(tbl)
alleles <- as.integer(names(tbl))
allele_freq_list$haplotype <- c(allele_freq_list$haplotype,
rep(paste0("block_", b), length(alleles)))
allele_freq_list$allele <- c(allele_freq_list$allele, alleles)
allele_freq_list$freq <- c(allele_freq_list$freq, freqs)
}
storage.mode(hap_block_all) <- "integer"
colnames_block <- paste0("block_", rep(1:n_blocks, each = 2))
# ββ 5. Construct W matrices ββββββββββββββββββββββββββββββββββββββββββββββββββ
wah_train <- construct_wah_matrix(
hap_block_all[idx_train,], colnames_block, allele_freq_list, NULL, TRUE)
W_mh_train <- wah_train$W_ah
ref_struct <- list(allele_info=wah_train$allele_info,
dropped_alleles=wah_train$dropped_alleles)
W_mh_test <- construct_wah_matrix(
hap_block_all[idx_test,], colnames_block, NULL, ref_struct, TRUE)$W_ah
snp_train_obj <- construct_snp_matrix(geno_snp_all[idx_train, ],
encoding = "zscore")
W_snp_train <- snp_train_obj$W
p_snp_tr <- snp_train_obj$freq
sd_snp_tr <- snp_train_obj$sd
W_snp_test <- construct_snp_matrix(geno_snp_all[idx_test, ],
encoding = "zscore",
ref_freq = p_snp_tr,
ref_sd = sd_snp_tr)$W
W_snp_all <- construct_snp_matrix(geno_snp_all,
encoding = "zscore",
ref_freq = p_snp_tr,
ref_sd = sd_snp_tr)$W
storage.mode(W_snp_train) <- "double"
storage.mode(W_snp_test) <- "double"
storage.mode(W_snp_all) <- "double"
wah_all <- construct_wah_matrix(
hap_block_all, colnames_block, allele_freq_list, NULL, TRUE)
W_mh_all <- wah_all$W_ah
# ββ 6. Simulate y (continuous and binary) βββββββββββββββββββββββββββββββββββ
simulate_y <- function(W_source, idx_tr, label, h2_target = 0.3,
n_qtl = 10, type = "snp") {
n_col <- ncol(W_source)
beta_true <- rep(0, n_col)
qtl_idx <- sample(n_col, n_qtl)
if (type == "snp") {
raw <- rgamma(n_qtl, shape=0.4, scale=1) * sample(c(-1,1), n_qtl, replace=TRUE)
beta_true[qtl_idx] <- raw / sqrt(sum(raw^2))
} else {
raw <- rnorm(n_qtl)
beta_true[qtl_idx] <- raw / sqrt(sum(raw^2))
}
tbv_all <- as.vector(W_source %*% beta_true)
tbv_mean <- mean(tbv_all[idx_tr])
tbv_sd <- sd(tbv_all[idx_tr])
tbv_std <- (tbv_all - tbv_mean) / tbv_sd
sg <- var(tbv_std[idx_tr])
se <- sg * (1 - h2_target) / h2_target
y_cont <- tbv_std + rnorm(length(tbv_std), 0, sqrt(se))
threshold <- median(y_cont[idx_tr])
y_bin <- as.numeric(y_cont > threshold)
h2_obs <- sg / (sg + se)
list(y_cont=y_cont, y_bin=y_bin, g=tbv_std, sigma2_g=sg, sigma2_e=se, h2=h2_obs)
}
set.seed(config$seed)
sc_snp <- simulate_y(W_snp_all, idx_train, "QTL@SNP",
h2_target = config$h2_target,
n_qtl = config$n_qtl,
type = "snp")
set.seed(config$seed)
sc_mh <- simulate_y(W_mh_all, idx_train, "QTL@MH",
h2_target = config$h2_target,
n_qtl = config$n_qtl,
type = "mh")
# ββ 7. Bayesian model fitting ββββββββββββββββββββββββββββββββββββββββββββββββ
mcmc_p <- config$mcmc
run_scenario <- function(sc, W_tr, W_te, y_tr, y_te, g_te,
marker_label, trait_type = "continuous") {
y_train <- y_tr
y_test <- y_te
resp <- if (trait_type == "binary") "binary" else "gaussian"
mtype <- if (identical(marker_label, "SNP")) "snp" else "multiallelic"
rows <- list()
se_init <- if (trait_type == "binary") 1.0 else sc$sigma2_e
sg_init <- if (trait_type == "binary") 1.0 else sc$sigma2_g
for (model in c("BayesR", "BayesA")) {
result <- tryCatch({
if (model == "BayesR") {
res <- run_bayesr(
w=W_tr, y=y_train,
marker_type = mtype,
pi_vec = config$bayesr$pi_vec,
sigma2_e_init = se_init,
sigma2_ah = sg_init,
prior_params = list(
a0_e = config$bayesr$a0_e,
a0_g = config$bayesr$a0_g,
variance_class = config$bayesr$variance_class
),
mcmc_params = mcmc_p,
method = "mcmc",
response_type = resp,
fold_id = 0L)
} else {
res <- run_bayesa(
w=W_tr, y=y_train,
marker_type = mtype,
nu = config$bayesa$nu,
sigma2_g = sg_init,
sigma2_e_init = se_init,
prior_params = list(a0_e = config$bayesa$a0_e),
mcmc_params = mcmc_p,
method = "mcmc",
response_type = resp,
fold_id = 0L)
}
gebv_tr <- res$GEBV
pred_te <- predict(res, W_te, y_test)
gebv_te <- pred_te$GEBV
r_test_y <- cor(gebv_te, y_test)
r_test_g <- cor(gebv_te, g_te)
if (trait_type == "binary" && !is.null(res$z_hat) && is.numeric(res$z_hat)) {
r_train <- cor(gebv_tr, res$z_hat)
bias_test <- pred_te$metrics$bias
sigma2_g_post <- var(gebv_tr)
h2_post <- sigma2_g_post / (sigma2_g_post + 1.0)
} else {
r_train <- cor(gebv_tr, y_train)
bias_test <- pred_te$metrics$bias
sigma2_g_post <- var(gebv_tr)
sigma2_e_post <- mean(res$sigma2_e_samples)
h2_post <- sigma2_g_post / (sigma2_g_post + sigma2_e_post)
}
auc <- if (trait_type == "binary") pred_te$metrics$AUC else NA
list(status="OK", r_train=round(r_train,3),
r_test_y=round(r_test_y,3), r_test_g=round(r_test_g,3),
bias=round(bias_test,3), h2=round(h2_post,3),
auc=round(auc,3), p=ncol(W_tr))
}, error = function(e)
list(status=paste("ERROR:", conditionMessage(e)),
r_train=NA, r_test_y=NA, r_test_g=NA,
bias=NA, h2=NA, auc=NA, p=ncol(W_tr)))
rows[[model]] <- data.frame(
Trait=trait_type, Marker=marker_label, Model=model,
Status=result$status, r_train=result$r_train,
r_test_y=result$r_test_y, r_test_g=result$r_test_g,
bias=result$bias, h2_post=result$h2, AUC=result$auc,
p=result$p, stringsAsFactors=FALSE)
}
do.call(rbind, rows)
}
# ββ 7b. GBLUP via masreml ββββββββββββββββββββββββββββββββββββββββββββββββββββ
rownames(geno_snp_all) <- as.character(1:n_total)
G_snp_full <- build_G_snp(geno_snp_all, ref_W = geno_snp_all[idx_train, ])
rownames(hap_block_all) <- as.character(1:n_total)
G_mh_full <- build_G_mh(
mh_list = hap_block_all,
ref_mh = hap_block_all[idx_train, ],
ids = as.character(1:n_total)
)
train_ids_ch <- as.character(idx_train)
test_ids_ch <- as.character(idx_test)
run_gblup_scenario <- function(sc, marker_label, G_full, y_tr, y_te, g_te,
trait_type = "continuous") {
G_tr <- G_full[train_ids_ch, train_ids_ch]
y_named <- setNames(y_tr, train_ids_ch)
fit <- tryCatch(
masreml(y = y_named, G = list(g = G_tr),
trait = trait_type, method = "auto"),
error = function(e) NULL
)
if (is.null(fit)) {
return(data.frame(Trait=trait_type, Marker=marker_label, Model="GBLUP",
Status="ERROR", r_train=NA, r_test_y=NA, r_test_g=NA,
bias=NA, h2_post=NA, AUC=NA, p=NA, stringsAsFactors=FALSE))
}
pred <- predict(fit, G_full = list(g = G_full),
train_ids = train_ids_ch, test_ids = test_ids_ch)
gebv_tr <- fit$total_gebv + fit$fixed_effects[1]
gebv_te <- pred$GEBV + fit$fixed_effects[1]
h2_post <- as.numeric(fit$varcomp$h2["g"])
ev <- evaluate_prediction(
gebv = gebv_te,
y = y_te,
h2 = h2_post,
tbv = g_te,
fitted_prob = if (trait_type == "binary") pred$prob else NULL
)
r_train <- cor(gebv_tr, y_tr)
data.frame(Trait=trait_type, Marker=marker_label, Model="GBLUP",
Status="OK",
r_train=round(r_train,3), r_test_y=ev$r_test_y,
r_test_g=ev$r_test_g, bias=round(ev$bias,3),
h2_post=round(h2_post,3), AUC=ev$AUC,
p=nrow(G_tr), stringsAsFactors=FALSE)
}
gblup_results <- list()
for (sc_name in c("QTL@SNP", "QTL@MH")) {
sc <- if (sc_name == "QTL@SNP") sc_snp else sc_mh
g_te <- sc$g[idx_test]
for (trait in c("continuous", "binary")) {
y_tr <- if (trait == "binary") sc$y_bin[idx_train] else sc$y_cont[idx_train]
y_te <- if (trait == "binary") sc$y_bin[idx_test] else sc$y_cont[idx_test]
r_snp <- run_gblup_scenario(sc, "SNP", G_snp_full, y_tr, y_te, g_te, trait)
r_mh <- run_gblup_scenario(sc, "MH", G_mh_full, y_tr, y_te, g_te, trait)
r_snp$Scenario <- r_mh$Scenario <- sc_name
gblup_results[[paste(sc_name, trait)]] <- rbind(r_snp, r_mh)
}
}
gblup_final <- do.call(rbind, gblup_results)
gblup_final <- gblup_final[, c("Scenario","Trait","Marker","Model",
"r_train","r_test_y","r_test_g",
"bias","h2_post","AUC","p","Status")]
# ββ 7c. GWABLUP via masreml ββββββββββββββββββββββββββββββββββββββββββββββββββ
run_gwablup_scenario <- function(sc, marker_type, y_tr, y_te, g_te,
G_full, geno_train, geno_all,
trait_type = "continuous") {
train_ids <- train_ids_ch
test_ids <- test_ids_ch
y_named <- setNames(y_tr, train_ids)
G_tr <- G_full[train_ids, train_ids]
comp_name <- if (marker_type == "SNP") "snp_add" else "mh_add"
result <- tryCatch({
fit_tr <- masreml(y = y_named, G = list(g = G_tr),
trait = trait_type, method = "auto")
if (marker_type == "SNP") {
markers_tr <- list(snp_add = geno_train)
ref_markers <- list(snp_add = geno_train)
} else {
hap_tr <- hap_block_all[idx_train, ]
rownames(hap_tr) <- train_ids
markers_tr <- list(mh_add = hap_tr)
ref_markers <- list(mh_add = hap_tr)
}
gwas_tr <- run_gwas(
markers = markers_tr,
y = y_named,
masreml_fit = fit_tr,
ref_markers = ref_markers
)
fit_wa <- gwablup(
y = y_named,
markers = markers_tr,
gwas_result = gwas_tr,
trait = trait_type,
ref_markers = ref_markers
)
g_full_named <- list(G_full)
names(g_full_named) <- comp_name
pred <- predict(fit_wa,
G_full = g_full_named,
train_ids = train_ids,
test_ids = test_ids)
gebv_tr <- fit_wa$total_gebv + fit_wa$fixed_effects[1]
gebv_te <- pred$GEBV + fit_wa$fixed_effects[1]
h2_post <- as.numeric(fit_wa$varcomp$h2[comp_name])
ev <- evaluate_prediction(
gebv = gebv_te,
y = y_te,
h2 = h2_post,
tbv = g_te,
fitted_prob = if (trait_type == "binary") pred$prob else NULL
)
list(status="OK",
r_train = round(cor(gebv_tr, y_tr), 3),
r_test_y = ev$r_test_y,
r_test_g = ev$r_test_g,
bias = ev$bias,
h2_post = round(h2_post, 3),
auc = ev$AUC,
p = length(fit_wa$total_gebv))
}, error = function(e)
list(status=paste("ERROR:", conditionMessage(e)),
r_train=NA, r_test_y=NA, r_test_g=NA,
bias=NA, h2_post=NA, auc=NA, p=NA))
data.frame(Trait=trait_type, Marker=marker_type, Model="GWABLUP",
Status=result$status,
r_train=result$r_train, r_test_y=result$r_test_y,
r_test_g=result$r_test_g, bias=result$bias,
h2_post=result$h2_post, AUC=result$auc,
p=result$p, stringsAsFactors=FALSE)
}
geno_train <- geno_snp_all[idx_train, ]
rownames(geno_train) <- train_ids_ch
storage.mode(geno_train) <- "double"
gwablup_results <- list()
for (sc_name in c("QTL@SNP", "QTL@MH")) {
sc <- if (sc_name == "QTL@SNP") sc_snp else sc_mh
g_te <- sc$g[idx_test]
for (trait in c("continuous", "binary")) {
y_tr <- if (trait == "binary") sc$y_bin[idx_train] else sc$y_cont[idx_train]
y_te <- if (trait == "binary") sc$y_bin[idx_test] else sc$y_cont[idx_test]
r_snp <- run_gwablup_scenario(sc, "SNP", y_tr, y_te, g_te,
G_snp_full, geno_train, geno_snp_all, trait)
r_mh <- run_gwablup_scenario(sc, "MH", y_tr, y_te, g_te,
G_mh_full, geno_train, geno_snp_all, trait)
r_snp$Scenario <- r_mh$Scenario <- sc_name
gwablup_results[[paste(sc_name, trait)]] <- rbind(r_snp, r_mh)
}
}
gwablup_final <- do.call(rbind, gwablup_results)
gwablup_final <- gwablup_final[, c("Scenario","Trait","Marker","Model",
"r_train","r_test_y","r_test_g",
"bias","h2_post","AUC","p","Status")]
# ββ 8. Run all Bayesian combinations βββββββββββββββββββββββββββββββββββββββββ
all_results <- list()
for (sc_name in c("QTL@SNP", "QTL@MH")) {
sc <- if (sc_name == "QTL@SNP") sc_snp else sc_mh
g_te <- sc$g[idx_test]
for (trait in c("continuous", "binary")) {
y_tr_use <- if (trait == "binary") sc$y_bin[idx_train] else sc$y_cont[idx_train]
y_te_use <- if (trait == "binary") sc$y_bin[idx_test] else sc$y_cont[idx_test]
r_mh <- run_scenario(sc, W_mh_train, W_mh_test,
y_tr_use, y_te_use,
g_te, "MH", trait)
r_snp <- run_scenario(sc, W_snp_train, W_snp_test,
y_tr_use, y_te_use,
g_te, "SNP", trait)
res <- rbind(r_mh, r_snp)
res$Scenario <- sc_name
all_results[[paste(sc_name, trait)]] <- res
}
}
# ββ 9. Combined results ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
final <- rbind(do.call(rbind, all_results), gblup_final, gwablup_final)
final <- final[, c("Scenario","Trait","Marker","Model",
"r_train","r_test_y","r_test_g",
"bias","h2_post","AUC","p","Status")]
final <- final[order(final$Scenario, final$Trait, final$Marker, final$Model), ]