# annoying renames to match meta V sylph filecolnames(sy) <-gsub("_1", "", colnames(sy))colnames(sy) <-gsub("_merged", "", colnames(sy))colData(sy)$Sample_file <-gsub("_1", "", basename(colData(sy)$Sample_file))colData(sy)$Sample_file <-gsub("_merged", "", colnames(sy))### We'll skip filtering here# Checks before merging metadataall(colnames(sy) %in% meta$run_accession)
[1] TRUE
Show code
all(meta$run_accession %in%colnames(sy))
[1] TRUE
Show code
sy =modify_metadata(sy, meta, replace = T)dim(sy)
[1] 64415 3414
Global predictors from all data (leakage)
Show code
### Strains we used in the global prediction modeltaxonomy <-read_taxonomy("data/TAXONOMY/sylph_DB_taxonomy_99.tsv")global_fit =readRDS("output_rds/CRC_zib_q_99_ebp.rds")th =top_hits(global_fit, coef =2, method ="bonferroni", alpha =0.01)
Found 571 tophits for diseaseCRC at alpha = 0.01 using bonferroni
Predict the AUC for all datasets by training on each dataset indepdendently
Show code
studies =unique(meta$study)design <-as.formula("~ disease + age + sex + BMI + (1 | study)")output =matrix(NA, nrow =length(studies), ncol =length(studies))doParallel::registerDoParallel(cores = parallel::detectCores()-2)# study_x = as.character(studies[16])for(i_train in1:length(studies)){ study_x =as.character(studies[i_train])cat("Training using:", study_x, "\n")if(study_x =="YangY_2021"){# manual override for this study - it does not contain age,sex,BMI data. Can't train the usual model using itcat("YangY_2021 dataset does not contain age, sex, BMI data, skipping...\n") output[i_train, ] =0next }if(study_x =="c5_NSHII"){# manual override for this study - it does not contain age,sex,BMI data. Can't train the usual model using itcat("c5_NSHII is an adenoma dataset (only 14/897 CRC)...\n") output[i_train, ] =0next }# Get the data out sy_x =subset(sy, select =colData(sy)$study %in% study_x) sy_x <-filter_by_presence(sy_x, min_nonzero =ceiling(dim(sy_x)[2]/10)) # filter at ~10% save_path =file.path("output_rds/crc_separate_dsets", paste(study_x, ".rds", sep =""))if(file.exists(save_path)){ ZB_fit_x =readRDS(save_path) } else {if("CRC"%in% sy_x@colData$disease &"None"%in% sy_x@colData$disease){ ebp =compute_eb_priors(sy_x, strainspy:::nobars_(design), nthreads = parallel::detectCores(),low_cutoff =0, high_cutoff =Inf) ZB_fit_x <-glmZiBFit(sy_x, design, MAP_prior = ebp, nthreads = parallel::detectCores())saveRDS(ZB_fit_x, save_path) } else {cat("No variation in outcome in:", study_x, " - skipping... \n") output[i_train, ] =0next } }# We obviously lack the power to pick as many strains with smaller datasets, let's use the ranking instead th_x = strainspy:::add_tax2tophits(top_hits(ZB_fit_x, coef =2, alpha =1), taxonomy, c("Species", "Genus")) th_x = th_x[1:nrow(th), ] # keep the same number of predictors sy_mx_bf_x = strainspy::prep_for_prediction(sy_x, 'disease', th_x$Contig_name)if(min(table(sy_mx_bf_x$disease))>=10) { # If one class had less than 10, don't think we can trust it (arbitrary value)# Fit elastic net only using the training data enet_fit_bf_x <- caret::train(disease ~ .,data = sy_mx_bf_x,method ='glmnet',preProcess =c("center", "scale"),metric ="ROC",trControl =trainControl(method ="cv",classProbs =TRUE, # allow probabilitiessummaryFunction = twoClassSummary, # compute ROC, Sens, SpecsavePredictions ="final" ),weights =ifelse(sy_mx_bf_x$disease=="CRC", 2, 1))# Predict each study i_test =1for (study_test in studies){cat("Predicting", study_test, "\n") hold_out_sy =subset(sy, select =colData(sy)$study %in%as.character(study_test))if("CRC"%in% hold_out_sy@colData$disease &"None"%in% hold_out_sy@colData$disease){ hold_out_mx = strainspy::prep_for_prediction(hold_out_sy, 'disease', th_x$Contig_name) pred_lodo <-predict(enet_fit_bf_x, hold_out_mx , type ="prob")$CRC roc_lodo <-roc(factor(colData(hold_out_sy)$disease, levels =c("None", "CRC")), pred_lodo, levels =c("None","CRC")) output[i_train, i_test] =auc(roc_lodo) } else { output[i_train, i_test] =0 } i_test = i_test +1 } } else {cat("Train dataset has <10 observation of one class in:", study_x, " - skipping... \n") output[i_train, ] =0next }}
Training using: c1_AtezoTRIBE
Retained 21480 rows after filtering
No variation in outcome in: c1_AtezoTRIBE - skipping...
Training using: c6__IIGM_TU
Retained 24381 rows after filtering
Found 10465 tophits for diseaseNone at alpha = 1 using holm
Training using: c2_COLOBIOME
Retained 21979 rows after filtering
Found 9537 tophits for diseaseNone at alpha = 1 using holm
Prepared data: 203 samples and 571 predictors.
Train dataset has <10 observation of one class in: c2_COLOBIOME - skipping...
Training using: YachidaS_2019
Retained 19685 rows after filtering
Found 9552 tophits for diseaseNone at alpha = 1 using holm
Training using: YangY_2021
YangY_2021 dataset does not contain age, sex, BMI data, skipping...
Training using: FengQ_2015
Retained 22049 rows after filtering
Found 10873 tophits for diseaseNone at alpha = 1 using holm
# annoying renames to match meta V sylph filecolnames(sy) <-gsub("_1", "", colnames(sy))colnames(sy) <-gsub("_merged", "", colnames(sy))colData(sy)$Sample_file <-gsub("_1", "", basename(colData(sy)$Sample_file))colData(sy)$Sample_file <-gsub("_merged", "", colnames(sy))### We'll skip filtering here# Checks before merging metadataall(colnames(sy) %in% meta$run_accession)
[1] TRUE
Show code
all(meta$run_accession %in%colnames(sy))
[1] TRUE
Show code
sy =modify_metadata(sy, meta, replace = T)dim(sy)
[1] 64415 3414
Show code
studies =unique(colData(sy)$study)registerDoParallel(cores = parallel::detectCores() -1)AUCs_enet_lodo =list()for(d in studies){# Training set sy_sub =subset(sy, select =!(colData(sy)$study %in%as.character(d))) sy_sub =filter_by_presence(sy_sub, ceiling(dim(sy_sub)[2]/10))## Feature selection design <-as.formula("~ disease + age + sex + BMI + (1 | study)") save_path <-paste("output_rds/CRC_lodo/zib_q_99_ebp_testset_", d,".rds", sep ="")# Run with ebp - this looks a bit less noisyif(file.exists(save_path)){ ZB_fit <-readRDS(save_path) } else { ebp =compute_eb_priors(sy_sub, strainspy:::nobars_(design), nthreads = parallel::detectCores(),low_cutoff =0, high_cutoff =Inf) ZB_fit <-glmZiBFit(sy, design, MAP_prior = ebp, nthreads = parallel::detectCores())saveRDS(ZB_fit, save_path) } th =top_hits(ZB_fit, coef =2, method ="BH", alpha =0.05)# Train Matrix train_mx = strainspy::prep_for_prediction(sy_sub, 'disease', th$Contig_name)# Test Matrix hold_out_mx = strainspy::prep_for_prediction(subset(sy, select =colData(sy)$study %in% d), 'disease', th$Contig_name) save_path =paste("output_rds/CRC_lodo/enet_BH_a0.05_testset_", d ,".rds", collapse ="", sep ="")if(file.exists(save_path)) { enet_fit_lodo =readRDS(save_path) } else {# train_mx = strainspy::prep_for_prediction(train_sy, 'disease', th$Contig_name) y <-factor(sy_sub$disease, levels =c("None", "CRC")) x = sparsevctrs::coerce_to_sparse_matrix(train_mx[,-1]) enet_fit_lodo <- caret::train(x = x,y = y,# data = train_mx,method ='glmnet',# preProcess = c("center", "scale"),metric ="ROC",trControl = caret::trainControl(method ="cv",classProbs =TRUE,summaryFunction = twoClassSummary,# index = groupKFold(train_meta$study, k = length(unique(train_meta$study))),savePredictions ="final",allowParallel =TRUE# <- important )#,#weights = ifelse(y=="CRC", 2, 1) )saveRDS(enet_fit_lodo, save_path) }# hold_out_mx = strainspy::prep_for_prediction(hold_out_sy, 'disease', th$Contig_name)if(length(unique(hold_out_mx$disease)) ==2){ pred_lodo <-predict(enet_fit_lodo, hold_out_mx , type ="prob")$CRC roc_lodo <-roc(factor(hold_out_mx$disease, levels =c("None", "CRC")), pred_lodo, levels =c("None","CRC")) AUCs_enet_lodo[[d]] =auc(roc_lodo)cat('Done with', d, 'AUC = ', AUCs_enet_lodo[[d]], '\n') } else {cat('Done with', d, 'cannot compute AUC, dataset is all:', as.character(unique(hold_out_mx$disease)), '\n') }}
Retained 20513 rows after filtering
Found 5940 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3286 samples and 5940 predictors.
Prepared data: 128 samples and 5940 predictors.
Setting direction: controls < cases
Done with YuJ_2015 AUC = 0.8586086
Retained 20545 rows after filtering
Found 5725 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3308 samples and 5725 predictors.
Prepared data: 106 samples and 5725 predictors.
Setting direction: controls < cases
Done with VogtmannE_2016 AUC = 0.7532051
Retained 20317 rows after filtering
Found 6531 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3251 samples and 6531 predictors.
Prepared data: 163 samples and 6531 predictors.
Done with c1_AtezoTRIBE cannot compute AUC, dataset is all: CRC
Retained 20317 rows after filtering
Found 6698 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3211 samples and 6698 predictors.
Prepared data: 203 samples and 6698 predictors.
Setting direction: controls < cases
Done with c2_COLOBIOME AUC = 0.4179104
Retained 20498 rows after filtering
Found 7228 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3290 samples and 7228 predictors.
Prepared data: 124 samples and 7228 predictors.
Setting direction: controls < cases
Done with c3_IIGM_CZ AUC = 0.7027379
Retained 20541 rows after filtering
Found 6311 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3354 samples and 6311 predictors.
Prepared data: 60 samples and 6311 predictors.
Setting direction: controls < cases
Done with c4_IIGM_IT AUC = 0.6651429
Retained 20466 rows after filtering
Found 6068 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3332 samples and 6068 predictors.
Prepared data: 82 samples and 6068 predictors.
Setting direction: controls < cases
Done with WirbelJ_2018 AUC = 0.7825758
Retained 20375 rows after filtering
Found 5686 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3265 samples and 5686 predictors.
Prepared data: 149 samples and 5686 predictors.
Setting direction: controls < cases
Done with ZellerG_2014 AUC = 0.8185964
Retained 20340 rows after filtering
Found 6324 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3260 samples and 6324 predictors.
Prepared data: 154 samples and 6324 predictors.
Setting direction: controls < cases
Done with FengQ_2015 AUC = 0.8490338
Retained 20417 rows after filtering
Found 8283 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 2799 samples and 8283 predictors.
Prepared data: 615 samples and 8283 predictors.
Setting direction: controls < cases
Done with YachidaS_2019 AUC = 0.6824637
Retained 20256 rows after filtering
Found 5341 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3221 samples and 5341 predictors.
Prepared data: 193 samples and 5341 predictors.
Setting direction: controls < cases
Done with YangJ_2020 AUC = 0.8473684
Retained 20242 rows after filtering
Found 4911 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3251 samples and 4911 predictors.
Prepared data: 163 samples and 4911 predictors.
Setting direction: controls < cases
Done with LiuNN_2022 AUC = 0.8514329
Retained 20519 rows after filtering
Found 6627 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3214 samples and 6627 predictors.
Prepared data: 200 samples and 6627 predictors.
Setting direction: controls < cases
Done with YangY_2021 AUC = 0.7532
Retained 20377 rows after filtering
Found 6149 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3357 samples and 6149 predictors.
Prepared data: 57 samples and 6149 predictors.
Setting direction: controls < cases
Done with c6__IIGM_TU AUC = 0.8974359
Retained 21637 rows after filtering
Found 6020 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 2517 samples and 6020 predictors.
Prepared data: 897 samples and 6020 predictors.
Setting direction: controls < cases
Done with c5_NSHII AUC = 0.6348487
Retained 20516 rows after filtering
Found 6052 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3354 samples and 6052 predictors.
Prepared data: 60 samples and 6052 predictors.
Setting direction: controls < cases
Done with GuptaA_2019 AUC = 0.9277778
Retained 20415 rows after filtering
Found 6655 tophits for diseaseNone at alpha = 0.05 using BH
Prepared data: 3354 samples and 6655 predictors.
Prepared data: 60 samples and 6655 predictors.
Setting direction: controls < cases
Done with ThomasAM_2018b AUC = 0.8214286
Show code
summary(unlist(AUCs_enet_lodo))
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.4179 0.6977 0.8006 0.7665 0.8496 0.9278