Relative transcript abundance has proven to be a valuable tool for understanding the function of genes in biological systems. For the differential analysis of transcript abundance using RNA sequencing data, the negative binomial model is by far the most frequently adopted. However, common methods that are based on a negative binomial model are not robust to extreme outliers, which we found to be abundant in public datasets. So far, no rigorous and probabilistic methods for detection of outliers have been developed for RNA sequencing data, leaving the identification mostly to visual inspection. Recent advances in Bayesian computation allow large-scale comparison of observed data against its theoretical distribution given in a statistical model. Here we propose ppcseq, a key quality-control tool for identifying transcripts that include outlier data points in differential expression analysis, which do not follow a negative binomial distribution. Applying ppcseq to analyse several publicly available datasets using popular tools, we show that from 3 to 10 percent of differentially abundant transcripts across algorithms and datasets had statistics inflated by the presence of outliers.
The input data set is a tidy representation of a differential gene transcript abundance analysis
To install:
Before install, for linux systems, in order to exploit multi-threading, from R write:
fileConn<-file("~/.R/Makevars")
writeLines(c( "CXX14FLAGS += -O3","CXX14FLAGS += -DSTAN_THREADS", "CXX14FLAGS += -pthread"), fileConn)
close(fileConn)
Multi-threading allows the sampling or variational bayes to share the computation on multiple cores.
Then, install with
if(!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("ppcseq")
You can get the test dataset with
## # A tibble: 394,821 × 9
## sample symbol logCPM LR PValue FDR value W Label
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <int> <dbl> <chr>
## 1 10922PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 160 -0.129 High
## 2 10935PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 150 -0.127 High
## 3 10973PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 146 -0.426 High
## 4 10976PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 347 -0.0164 High
## 5 10985PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 175 -0.135 High
## 6 11026PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 244 0.125 High
## 7 11045PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 399 -0.0892 High
## 8 11082PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 100 0.261 Neoadjuvant
## 9 11086PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 37 -0.132 Neoadjuvant
## 10 11103PP SLC16A12 1.39 41.1 1.46e-10 0.00000274 73 0.146 Neoadjuvant
## # ℹ 394,811 more rows
You can identify anrtefactual calls from your differential transcribt anundance analysis, due to outliers.
# Import libraries
if(Sys.info()[['sysname']] == "Linux")
counts.ppc =
counts %>%
mutate(is_significant = FDR < 0.0001) %>%
identify_outliers(
formula = ~ Label,
.sample = sample,
.transcript = symbol,
.abundance = value,
.significance = PValue,
.do_check = is_significant,
percent_false_positive_genes = 5,
approximate_posterior_inference = FALSE,
cores = 1,
# This is ONLY for speeding up the Vignette execution
draws_after_tail = 1
)
The new posterior predictive check has been added to the original data frame
## # A tibble: 1 × 4
## symbol sample_wise_data ppc_samples_failed tot_deleterious_outliers
## <chr> <list> <int> <int>
## 1 SLC16A12 <tibble [21 × 13]> 0 0
The new data frame contains plots for each gene
We can visualise the top five differentially transcribed genes
## [[1]]
## R version 4.4.1 (2024-06-14)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
## [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
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ppcseq_1.15.0 rstan_2.32.6 StanHeaders_2.32.10
## [4] dplyr_1.1.4 knitr_1.48 BiocStyle_2.35.0
##
## loaded via a namespace (and not attached):
## [1] benchmarkmeData_1.0.4 gtable_0.3.6 tensorA_0.36.2.1
## [4] xfun_0.48 bslib_0.8.0 ggplot2_3.5.1
## [7] QuickJSR_1.4.0 inline_0.3.19 lattice_0.22-6
## [10] vctrs_0.6.5 tools_4.4.1 generics_0.1.3
## [13] stats4_4.4.1 curl_5.2.3 parallel_4.4.1
## [16] tibble_3.2.1 fansi_1.0.6 highr_0.11
## [19] pkgconfig_2.0.3 Matrix_1.7-1 checkmate_2.3.2
## [22] distributional_0.5.0 RcppParallel_5.1.9 lifecycle_1.0.4
## [25] farver_2.1.2 stringr_1.5.1 compiler_4.4.1
## [28] statmod_1.5.0 munsell_0.5.1 codetools_0.2-20
## [31] htmltools_0.5.8.1 sys_3.4.3 buildtools_1.0.0
## [34] sass_0.4.9 yaml_2.3.10 pillar_1.9.0
## [37] jquerylib_0.1.4 tidyr_1.3.1 arrayhelpers_1.1-0
## [40] cachem_1.1.0 limma_3.63.0 iterators_1.0.14
## [43] foreach_1.5.2 abind_1.4-8 posterior_1.6.0
## [46] tidybayes_3.0.7 tidyselect_1.2.1 locfit_1.5-9.10
## [49] digest_0.6.37 svUnit_1.0.6 stringi_1.8.4
## [52] purrr_1.0.2 labeling_0.4.3 maketools_1.3.1
## [55] fastmap_1.2.0 grid_4.4.1 colorspace_2.1-1
## [58] cli_3.6.3 magrittr_2.0.3 loo_2.8.0
## [61] pkgbuild_1.4.5 utf8_1.2.4 withr_3.0.2
## [64] edgeR_4.4.0 scales_1.3.0 backports_1.5.0
## [67] httr_1.4.7 rmarkdown_2.28 matrixStats_1.4.1
## [70] benchmarkme_1.0.8 gridExtra_2.3 coda_0.19-4.1
## [73] evaluate_1.0.1 doParallel_1.0.17 V8_6.0.0
## [76] ggdist_3.3.2 rstantools_2.4.0 rlang_1.1.4
## [79] Rcpp_1.0.13 glue_1.8.0 BiocManager_1.30.25
## [82] jsonlite_1.8.9 R6_2.5.1