In this set of simulations, we consider settings with both null and non-null tests with an informative and uninformative covariate. The informative covariate is sampled uniformly from the interval [0, 1], and the conditional probability of a test being non-null is a smooth (cubic) function of the covariate. The uninformative covariate is simply uninformly sampled independently from the interval [0, 1]. The uninformative covariate is included as a baseline to compare the informative covariate against. We include simulation results again with Gaussian distributed test statistics.
Additionally, with the informative covariate, a dependence is introduced between the coviarate the p-value under the null distribution.
library(dplyr)
library(ggplot2)
library(parallel)
library(cowplot)
## load helper functions
for (f in list.files("../../R", "\\.(r|R)$", full.names = TRUE)) {
source(f)
}
## new helper function
source("helpers-simulations-nulldependent.R")
## project data/results folders
resdir <- "results"
dir.create(resdir, showWarnings = FALSE, recursive = TRUE)
## intermediary files we create below
weak_file <- file.path(resdir, "nulldependent-cubic-benchmark-weaker.rds")
strong_file <- file.path(resdir, "nulldependent-cubic-benchmark-stronger.rds")
## number of cores for parallelization
cores <- 20
B <- 100
## define bechmarking design
bd <- initializeBenchDesign()
As described in simulations-null.Rmd
, we include Scott’s FDR Regression in the analysis since all settings here use Gaussian test statistics. Again, we include both nulltype = "empirical"
and nulltype = "theoretical"
.
bdplus <- bd
bdplus <- addBMethod(bdplus, "fdrreg-t",
FDRreg::FDRreg,
function(x) { x$FDR },
z = test_statistic,
features = model.matrix( ~ splines::bs(ind_covariate, df = 3) - 1),
nulltype = 'theoretical',
control = list(lambda = 0.01))
bdplus <- addBMethod(bdplus, "fdrreg-e",
FDRreg::FDRreg,
function(x) { x$FDR },
z = test_statistic,
features = model.matrix( ~ splines::bs(ind_covariate, df = 3) - 1),
nulltype = 'empirical',
control = list(lambda = 0.01))
All simulation settings will share the following parameters.
m <- 20000 # integer: number of hypothesis tests
pi0 <- pi0_cubic(0.90) # numeric: proportion of null hypotheses
icovariate <- runif # functional: independent covariate
es_dist <- rnorm_generator(3) # functional: dist of alternative test stats
ts_dist <- rnorm_perturber(1) # functional: sampling dist/noise for test stats
null_dist <- rnorm_2pvaluer(1) # functional: dist to calc p-values
null_inv <- function(p) { (2*rbinom(length(p), 1, .5) - 1) * qnorm(p / 2, 0, 1) }
seed <- 608
Simulation results will be presented excluding a subset of methods, and for certain plots (upset plots), a single alpha cutoff will be used.
excludeSet <- c("unadjusted", "bl-df02", "bl-df04", "bl-df05")
ualpha <- 0.05
Here, we show null dependence on the variate by just showing the distribution of p-values when all tests are null (pi0 = 1). We show the distribution of p-values for two settings: weaker and stronger dependence between the covariate and p-values under the null.
onerun_w <- simNullDependent(bdplus, m = 20000, pi0 = 1, es_dist = es_dist, ts_dist = ts_dist,
icovariate = icovariate, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.3, execute = FALSE)
rank_scatter(onerun_w, pvalue = "pval", covariate = "ind_covariate") +
ggtitle("Dist. of null p-values w/ weaker dependence")
strat_hist(onerun_w, pvalue = "pval", covariate = "ind_covariate", maxy = 7, numQ = 5) +
ggtitle("Dist. of null p-values w/ weaker dependence")
## Warning: `list_len()` is soft-deprecated as of rlang 0.2.0.
## Please use `new_list()` instead
## This warning is displayed once per session.
onerun_s <- simNullDependent(bdplus, m = 20000, pi0 = 1, es_dist = es_dist, ts_dist = ts_dist,
icovariate = icovariate, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.7, execute = FALSE)
rank_scatter(onerun_s, pvalue = "pval", covariate = "ind_covariate") +
ggtitle("Dist. of null p-values w/ stronger dependence")
strat_hist(onerun_s, pvalue = "pval", covariate = "ind_covariate", maxy = 7, numQ = 5) +
ggtitle("Dist. of null p-values w/ stronger dependence")
We also create the above plots as a multipanel plot.
gp_oW <- rank_scatter(onerun_w, pvalue = "pval", covariate = "ind_covariate") +
ggtitle("Dist. of null p-values w/ weaker dependence")
gp_oS <- rank_scatter(onerun_s, pvalue = "pval", covariate = "ind_covariate") +
ggtitle("Dist. of null p-values w/ stronger dependence")
gp_o <- plot_grid(gp_oW + expand_limits(y = c(0, 5)),
gp_oS + expand_limits(y = c(0, 5)),
labels = LETTERS[1:2], nrow = 1)
gp_o
We next run the simulations.
First, we take a look at the results with weaker dependence.
if (file.exists(weak_file)) {
res <- readRDS(weak_file)
} else {
res <- mclapply(X = 1:B, FUN = simNullDependent, bench = bdplus, m = m,
pi0 = pi0, es_dist = es_dist, icovariate = icovariate,
ts_dist = ts_dist, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.3,
seed = seed, mc.cores = cores)
saveRDS(res, file = weak_file)
}
res_dep <- lapply(res, `[[`, "null_dependent")
res_indep <- lapply(res, `[[`, "null_independent")
Here, we show the relationship between the independent covariate and p-values for a single replication of the experiment. Unlike the plots above, these include both null and non-null tests.
onerun <- simNullDependent(bdplus, m = m, pi0 = pi0, es_dist = es_dist, ts_dist = ts_dist,
icovariate = icovariate, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.3, execute = FALSE)
rank_scatter(onerun, pvalue = "pval", covariate = "ind_covariate")
strat_hist(onerun, pvalue = "pval", covariate = "ind_covariate", maxy = 7, numQ = 5)
We plot the averaged results across 100 replications.
resdf <- plotsim_standardize(res_dep, alpha = seq(0.01, 0.10, 0.01))
plotsim_average(resdf, met="rejections", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="TNR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
We also take a look at the distribution of rejects for each method as a function of the effect size and independent covariate.
covariateLinePlot(res_dep, alpha = ualpha, covname = "effect_size")
## Warning: Removed 50 rows containing missing values (geom_path).
## Warning: Removed 50 rows containing missing values (geom_errorbar).
covariateLinePlot(res_dep, alpha = ualpha, covname = "ind_covariate")
## Warning: Removed 50 rows containing missing values (geom_path).
## Warning: Removed 50 rows containing missing values (geom_errorbar).
We also look at the FDR as a function of the independent covariate.
covariateLinePlot(res_dep, alpha = ualpha, covname = "ind_covariate", metric = "FDR")
## Warning: Removed 61 rows containing missing values (geom_path).
## Warning: Removed 70 rows containing missing values (geom_errorbar).
Finally, (if enough methods produce rejections at 0.05) we take a look at the overlap of rejections between methods.
if (numberMethodsReject(resdf, alphacutoff = ualpha, filterSet = excludeSet) >= 3) {
aggupset(res_dep, alpha = ualpha, supplementary = FALSE, return_list = FALSE)
} else {
message("Not enough methods found rejections at alpha ", ualpha,
"; skipping upset plot")
}
We also compare the simulation results with and without dependence between the covariate under the nul.
resdfu <- plotsim_standardize(res_indep, alpha = seq(0.01, 0.10, 0.01))
resdfiu <- dplyr::full_join(select(resdf, rep, blabel, param.alpha, key,
performanceMetric, alpha, value),
select(resdfu, rep, blabel, param.alpha, key,
performanceMetric, alpha, value),
by = c("rep", "blabel", "param.alpha", "key",
"performanceMetric", "alpha"),
suffix = c(".dep", ".indep"))
resdfiu <- dplyr::mutate(resdfiu, value = value.dep - value.indep)
plotsim_average(resdfiu, met="rejections", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
ylab("rejections (dep - indep)")
plotsim_average(resdfiu, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("FDR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
plotsim_average(resdfiu, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TPR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
plotsim_average(resdfiu, met="TNR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TNR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
Here, we create a multipanel plot to consolidate the results to a single figure.
gp_wA <- plotsim_average(resdf, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
gp_wB <- plotsim_average(resdf, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
gp_wC <- plotsim_average(resdfiu, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("FDR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
gp_wD <- plotsim_average(resdfiu, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TPR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
gp_w <- plot_grid(gp_wA + theme(legend.position = "none"),
gp_wB + theme(legend.position = "none"),
gp_wC + theme(legend.position = "none"),
gp_wD + theme(legend.position = "none"),
labels = LETTERS[1:4], nrow = 2, ncol = 2)
gp_w <- plot_grid(gp_w, get_legend(gp_wA),
rel_widths = c(1, .2))
gp_w
Next, we take a look at the results with stronger dependence.
if (file.exists(strong_file)) {
res <- readRDS(strong_file)
} else {
res <- mclapply(X = 1:B, FUN = simNullDependent, bench = bdplus, m = m,
pi0 = pi0, es_dist = es_dist, icovariate = icovariate,
ts_dist = ts_dist, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.7,
seed = seed, mc.cores = cores)
saveRDS(res, file = strong_file)
}
res_dep <- lapply(res, `[[`, "null_dependent")
res_indep <- lapply(res, `[[`, "null_independent")
Here, we show the relationship between the independent covariate and p-values for a single replication of the experiment. Unlike the plots above, these include both null and non-null tests.
onerun <- simNullDependent(bdplus, m = m, pi0 = pi0, es_dist = es_dist, ts_dist = ts_dist,
icovariate = icovariate, null_dist = null_dist, null_inv = null_inv,
null_dependence = 0.7, execute = FALSE)
rank_scatter(onerun, pvalue = "pval", covariate = "ind_covariate")
strat_hist(onerun, pvalue = "pval", covariate = "ind_covariate", maxy = 7, numQ = 5)
We plot the averaged results across 100 replications.
resdf <- plotsim_standardize(res_dep, alpha = seq(0.01, 0.10, 0.01))
plotsim_average(resdf, met="rejections", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
plotsim_average(resdf, met="TNR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
We also take a look at the distribution of rejects for each method as a function of the effect size and independent covariate.
covariateLinePlot(res_dep, alpha = ualpha, covname = "effect_size")
## Warning: Removed 50 rows containing missing values (geom_path).
## Warning: Removed 50 rows containing missing values (geom_errorbar).
covariateLinePlot(res_dep, alpha = ualpha, covname = "ind_covariate")
## Warning: Removed 50 rows containing missing values (geom_path).
## Warning: Removed 50 rows containing missing values (geom_errorbar).
We also look at the FDR as a function of the independent covariate.
covariateLinePlot(res_dep, alpha = ualpha, covname = "ind_covariate", metric = "FDR")
## Warning: Removed 58 rows containing missing values (geom_path).
## Warning: Removed 64 rows containing missing values (geom_errorbar).
Finally, (if enough methods produce rejections at 0.05) we take a look at the overlap of rejections between methods.
if (numberMethodsReject(resdf, alphacutoff = ualpha, filterSet = excludeSet) >= 3) {
aggupset(res_dep, alpha = ualpha, supplementary = FALSE, return_list = FALSE)
} else {
message("Not enough methods found rejections at alpha ", ualpha,
"; skipping upset plot")
}
We also compare the simulation results with and without dependence between the covariate under the nul.
resdfu <- plotsim_standardize(res_indep, alpha = seq(0.01, 0.10, 0.01))
resdfiu <- dplyr::full_join(select(resdf, rep, blabel, param.alpha, key,
performanceMetric, alpha, value),
select(resdfu, rep, blabel, param.alpha, key,
performanceMetric, alpha, value),
by = c("rep", "blabel", "param.alpha", "key",
"performanceMetric", "alpha"),
suffix = c(".dep", ".indep"))
resdfiu <- dplyr::mutate(resdfiu, value = value.dep - value.indep)
plotsim_average(resdfiu, met="rejections", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
ylab("rejections (dep - indep)")
plotsim_average(resdfiu, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("FDR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
plotsim_average(resdfiu, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TPR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
plotsim_average(resdfiu, met="TNR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TNR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
Here, we create a multipanel plot to consolidate the results to a single figure.
gp_sA <- plotsim_average(resdf, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
gp_sB <- plotsim_average(resdf, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE)
gp_sC <- plotsim_average(resdfiu, met="FDR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("FDR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
gp_sD <- plotsim_average(resdfiu, met="TPR", filter_set = excludeSet,
merge_ihw = TRUE, errorBars = TRUE, diffplot = TRUE) +
scale_y_continuous("TPR (dep - indep)", labels = scales::percent)
## Scale for 'y' is already present. Adding another scale for 'y', which
## will replace the existing scale.
gp_s <- plot_grid(gp_sA + theme(legend.position = "none"),
gp_sB + theme(legend.position = "none"),
gp_sC + theme(legend.position = "none"),
gp_sD + theme(legend.position = "none"),
labels = LETTERS[1:4], nrow = 2, ncol = 2)
gp_s <- plot_grid(gp_s, get_legend(gp_sA),
rel_widths = c(1, .2))
gp_s
sessionInfo()
## R version 3.5.0 (2018-04-23)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: CentOS Linux 7 (Core)
##
## Matrix products: default
## BLAS: /usr/lib64/libblas.so.3.4.2
## LAPACK: /usr/lib64/liblapack.so.3.4.2
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] splines stats4 parallel stats graphics grDevices utils
## [8] datasets methods base
##
## other attached packages:
## [1] bindrcpp_0.2.2 hexbin_1.27.2
## [3] truncnorm_1.0-8 adaptMT_1.0.0
## [5] FDRreg_0.1 fda_2.4.8
## [7] Matrix_1.2-14 fdrtool_1.2.15
## [9] swfdr_1.6.0 qvalue_2.12.0
## [11] ashr_2.2-7 IHW_1.8.0
## [13] SummarizedBenchmarkFDR_0.99.2 mclust_5.4.1
## [15] stringr_1.3.1 rlang_0.3.0.1
## [17] UpSetR_1.3.3 SummarizedExperiment_1.10.1
## [19] DelayedArray_0.6.6 BiocParallel_1.14.2
## [21] matrixStats_0.54.0 Biobase_2.40.0
## [23] GenomicRanges_1.32.7 GenomeInfoDb_1.16.0
## [25] IRanges_2.14.12 S4Vectors_0.18.3
## [27] BiocGenerics_0.26.0 tidyr_0.8.1
## [29] magrittr_1.5 cowplot_0.9.3
## [31] ggplot2_3.1.0 dplyr_0.7.8
##
## loaded via a namespace (and not attached):
## [1] ggdendro_0.1-20 foreach_1.4.4 assertthat_0.2.0
## [4] ggstance_0.3.1 GenomeInfoDbData_1.1.0 ggrepel_0.8.0
## [7] mosaic_1.4.0 yaml_2.2.0 slam_0.1-43
## [10] pillar_1.3.0 backports_1.1.2 lattice_0.20-35
## [13] glue_1.3.0 digest_0.6.18 XVector_0.20.0
## [16] colorspace_1.3-2 htmltools_0.3.6 plyr_1.8.4
## [19] pkgconfig_2.0.2 broom_0.5.0 zlibbioc_1.26.0
## [22] purrr_0.2.5 scales_1.0.0 mosaicData_0.17.0
## [25] tibble_1.4.2 withr_2.1.2 lazyeval_0.2.1
## [28] crayon_1.3.4 evaluate_0.12 nlme_3.1-137
## [31] doParallel_1.0.14 MASS_7.3-51 tools_3.5.0
## [34] munsell_0.5.0 compiler_3.5.0 grid_3.5.0
## [37] RCurl_1.95-4.11 iterators_1.0.10 labeling_0.3
## [40] mosaicCore_0.6.0 bitops_1.0-6 rmarkdown_1.10
## [43] gtable_0.2.0 codetools_0.2-15 reshape2_1.4.3
## [46] R6_2.3.0 gridExtra_2.3 knitr_1.20
## [49] ggformula_0.9.0 bindr_0.1.1 rprojroot_1.3-2
## [52] lpsymphony_1.8.0 stringi_1.2.4 pscl_1.5.2
## [55] SQUAREM_2017.10-1 Rcpp_1.0.0 tidyselect_0.2.5