This vignette provides a practical
introduction to replicate-based imputation using repli. It
introduces the concepts behind missing value imputation, demonstrates
the basic workflow, and shows how repli can be integrated
into a complete proteomics workflow using SummarizedExperiment
objects with DEP.
Missing values are common in mass spectrometry-based proteomics data and can complicate downstream statistical analysis. Imputation can be used to retain proteins with incomplete measurements, providing valuable biological insights that might otherwise be missed.
In proteomics, missing values are classified as Missing At Random (MAR), when a protein is not detected in some replicates of a condition, or Missing Not At Randomn (MNAR), where a protein is not detected in all replicates of a condition. For example, in the dataset below, Protein B would be classified as MAR and Proteins C would be classified as MNAR.
Replicate 1 Replicate 2 Replicate 3
Protein A 20 21 19
Protein B 15 NA 16
Protein C NA NA NA
repli implements replicate-based imputation for
MAR data. Instead of estimating a missing value using similar
proteins or a global dataset metric, the method uses available
measurements from other replicates of the same protein. For each
protein-condition combination with missing values, the mean of the
available values is calculated to use for the imputation distribution. A
global standard deviation is derived from the standard deviations of all
protein-condition pairs in the dataset and used for the imputation
distribution.
In the example below, replicate 2 of Protein B would be imputed by sampling from a normal distribution with the mean set at 15.5 and a standard deviation set at 0.8535. For more details on how the global standard deviation is calculated, see the section below.
Replicate 1 Replicate 2 Replicate 3 mean sd
Protein A 20 21 19 NA 1
Protein B 15 NA 16 15.5 0.707
Protein C NA NA NA NA NA
repli expects samples to follow a condition-replicate
naming convention, with an underscore or period as separator.
For example:
control_1
control_2
control_3
treatment_1
treatment_2
treatment_3
The data should contain proteins in rows and samples in columns, with
log2-transformed protein abundances in the sample columns and missing
values represented as NA.
First, prepare the data using prepare_imputation_data().
Here, we use a modified dataset from Zijlmans et
al. 2025 as example. The resulting object contains the prepared data
as well as the information required for imputation.
data(example_dataset)
head(example_dataset)
#> E_T_T5C1_B_1 E_T_T5C1_B_2 E_T_T5C1_B_3 R1_B_1 R1_B_2 R1_B_3
#> Magohb 27.57022 27.06528 27.74464 26.67169 26.68886 26.45081
#> Srcap 25.73255 25.81372 25.60094 24.65223 24.47352 24.56506
#> Eloc 27.53096 27.64924 27.58864 25.48867 25.65196 25.77816
#> Agfg1 25.37885 25.56075 24.79397 NA NA NA
#> Ktn1 26.24842 26.46579 26.22523 26.86774 27.00721 27.08111
#> Resf1 25.67020 25.29432 25.23334 24.76172 24.85377 25.03183
prepared <- prepare_imputation_data(example_dataset, p = 0.05)
#The output is a list consisting of the data is the appropriate format,
# as well as a vector specifying the replicate columns and the global sd.
names(prepared)
#> [1] "data" "replicate_cols" "global_sd"
head(prepared$data)
#> # A tibble: 6 × 8
#> name condition `1` `2` `3` sd missingness row_mean
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <dbl>
#> 1 Magohb E_T_T5C1_B 27.6 27.1 27.7 0.353 Valid NA
#> 2 Magohb R1_B 26.7 26.7 26.5 0.133 Valid NA
#> 3 Srcap E_T_T5C1_B 25.7 25.8 25.6 0.107 Valid NA
#> 4 Srcap R1_B 24.7 24.5 24.6 0.0894 Valid NA
#> 5 Eloc E_T_T5C1_B 27.5 27.6 27.6 0.0591 Valid NA
#> 6 Eloc R1_B 25.5 25.7 25.8 0.145 Valid NAProtein-condition combinations are classified as:
Valid: no missing values;MAR: some missing values;MNAR: all missing values.The prepared data can be passed to
impute_replicate():
The random seed can be set to make the stochastic imputation reproducible.
The p argument controls the proportion of observations
with the highest standard deviations that are used to estimate the
global standard deviation.
For example:
uses the top 5% of standard deviations across the dataset to calculate the median global standard deviation.
A SummarizedExperiment
is a data structure for storing quantitative biological data together
with information about the samples and measured features. You can think
of it as a container holding the protein abundance matrix, information
about the samples and experimental conditions and replicate information.
Many Bioconductor packages use this format, which means that using a
SummarizedExperiment allows different packages to work
together.
For SummarizedExperiment objects,
impute_replicate_se() combines preparation, imputation, and
reconstruction into a single function. It requires a
SummarizedExperiment as input and will return a SummarizedExperiment
with the imputed assay as output.
data(example_se)
class(example_se)
#> [1] "SummarizedExperiment"
#> attr(,"package")
#> [1] "SummarizedExperiment"
set.seed(123)
imputed_se <- impute_replicate_se(example_se, p = 0.05)
class(imputed_se)
#> [1] "SummarizedExperiment"
#> attr(,"package")
#> [1] "SummarizedExperiment"
#The imputed data can be accessed using `assay()`:
head(SummarizedExperiment::assay(imputed_se))
#> E_T_T5C1_B_1 E_T_T5C1_B_2 E_T_T5C1_B_3 R1_B_1 R1_B_2 R1_B_3
#> Magohb 27.57022 27.06528 27.74464 26.67169 26.68886 26.45081
#> Srcap 25.73255 25.81372 25.60094 24.65223 24.47352 24.56506
#> Eloc 27.53096 27.64924 27.58864 25.48867 25.65196 25.77816
#> Agfg1 25.37885 25.56075 24.79397 NA NA NA
#> Ktn1 26.24842 26.46579 26.22523 26.86774 27.00721 27.08111
#> Resf1 25.67020 25.29432 25.23334 24.76172 24.85377 25.03183This workflow is intended to integrate directly with downstream
proteomics workflows based on DEP.
Replicate-based imputation is designed for MAR values, as it requires
at east some existing values for a condition. When a dataset contains
both MAR and MNAR values, impute_replicate_mixed_se() can
combine replicate-based imputation with a MNAR imputation method.
For example, MinProb can be used for MNAR values:
set.seed(123)
imputed_se <- impute_replicate_mixed_se(example_se,
p = 0.05,
MNAR_method = "MinProb",
MNAR_args = list(q = 0.01))
#> Imputing along margin 2 (samples/columns).
#> [1] 0.4216317The function performs replicate-based MAR imputation and the selected MNAR imputation method independently on the original dataset. The resulting imputed values are then combined, with replicate-based imputations used for partially missing protein-condition pairs and MNAR imputations used for completely missing protein-condition pairs. Originally observed values are retained.
If no MNAR imputation is desired, set MNAR method to
"none".
repli can be incorporated into proteomics workflows
based on the DEP
package.
Here, repli replaces the imputation step while the other
analysis steps can be performed using existing DEP
functions. Since proteomics data almost always contain both MAR and MNAR
missing values, using impute_replicate_mixed_se() is
advised. Below is an example DEP workflow.
#Load and clean data
data(UbiLength, package = "DEP")
data <- UbiLength
data <- dplyr::filter(data, Reverse != "+", Potential.contaminant != "+")
#Prepare SummarizedExperiment
data_unique <- DEP::make_unique(data, "Gene.names", "Protein.IDs", delim = ";")
LFQ_columns <- grep("LFQ.", colnames(data_unique))
data(UbiLength_ExpDesign, package = "DEP")
experimental_design <- UbiLength_ExpDesign
data_se <- DEP::make_se(data_unique, LFQ_columns, experimental_design)
#Data filtering and normalization
data_filt <- DEP::filter_missval(data_se, thr = 0)
data_norm <- DEP::normalize_vsn(data_filt)
#Imputation
data_imp <- impute_replicate_mixed_se(data_norm, # <-- use here
p = 0.05,
MNAR_method = "MinProb",
MNAR_args = list(q = 0.01))
#> Imputing along margin 2 (samples/columns).
#> [1] 0.2608395
#Differential enrichment analysis
data_diff <- DEP::test_diff(data_imp, type = "control", control = "Ctrl")
#> Tested contrasts: Ubi4_vs_Ctrl, Ubi6_vs_Ctrl, Ubi1_vs_Ctrl
dep <- DEP::add_rejections(data_diff, alpha = 0.05, lfc = log2(1.5))sessionInfo()
#> R version 4.6.2 (2026-10-29)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.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.32.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=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
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] repli_0.99.0 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] RColorBrewer_1.1-3 sys_3.4.3
#> [3] jsonlite_2.0.0 shape_1.4.6.1
#> [5] MultiAssayExperiment_1.39.1 magrittr_2.0.5
#> [7] farver_2.1.2 MALDIquant_1.22.3
#> [9] rmarkdown_2.32 GlobalOptions_0.1.4
#> [11] fs_2.1.0 vctrs_0.7.3
#> [13] htmltools_0.5.9 S4Arrays_1.13.2
#> [15] SparseArray_1.13.4 mzID_1.51.0
#> [17] sass_0.4.10 bslib_0.12.0
#> [19] htmlwidgets_1.6.4 plyr_1.8.9
#> [21] sandwich_3.1-3 impute_1.87.0
#> [23] zoo_1.9-1 cachem_1.1.0
#> [25] buildtools_1.0.0 igraph_2.3.4
#> [27] mime_0.13 lifecycle_1.0.5
#> [29] iterators_1.0.14 pkgconfig_2.0.3
#> [31] Matrix_1.7-6 R6_2.6.1
#> [33] fastmap_1.2.0 MatrixGenerics_1.25.0
#> [35] shiny_1.14.0 clue_0.3-68
#> [37] fdrtool_1.2.18 digest_0.6.39
#> [39] pcaMethods_2.5.0 colorspace_2.1-4
#> [41] S4Vectors_0.51.10 GenomicRanges_1.65.4
#> [43] Spectra_1.23.7 abind_1.4-8
#> [45] compiler_4.6.2 withr_3.0.3
#> [47] doParallel_1.0.17 S7_0.2.2
#> [49] PTMods_1.1.1 BiocParallel_1.47.0
#> [51] MASS_7.3-66 DelayedArray_0.39.8
#> [53] rjson_0.2.23 mzR_2.47.2
#> [55] tools_4.6.2 PSMatch_1.17.3
#> [57] otel_0.3.0 httpuv_1.6.17
#> [59] glue_1.8.1 QFeatures_1.23.2
#> [61] promises_1.5.0 grid_4.6.2
#> [63] cluster_2.1.8.3 reshape2_1.4.5
#> [65] generics_0.1.4 gtable_0.3.6
#> [67] tzdb_0.5.0 preprocessCore_1.75.3
#> [69] tidyr_1.3.2 data.table_1.18.6.1
#> [71] hms_1.1.4 MetaboCoreUtils_1.21.2
#> [73] utf8_1.2.6 XVector_0.53.0
#> [75] BiocGenerics_0.59.13 foreach_1.5.2
#> [77] pillar_1.11.1 stringr_1.6.0
#> [79] limma_3.99.4 later_1.4.8
#> [81] circlize_0.4.18 gmm_1.9-1
#> [83] dplyr_1.2.1 lattice_0.23-1
#> [85] tidyselect_1.2.1 ComplexHeatmap_2.29.0
#> [87] maketools_1.3.2 knitr_1.52
#> [89] IRanges_2.47.5 Seqinfo_1.3.2
#> [91] ProtGenerics_1.45.0 imputeLCMD_2.1
#> [93] SummarizedExperiment_1.43.0 stats4_4.6.2
#> [95] xfun_0.62 shinydashboard_0.7.3
#> [97] Biobase_2.73.2 statmod_1.5.2
#> [99] MSnbase_2.39.6 matrixStats_1.5.0
#> [101] DT_0.34.0 DEP_3.99.0
#> [103] stringi_1.8.9 lazyeval_0.2.3
#> [105] yaml_2.3.12 evaluate_1.0.5
#> [107] codetools_0.2-20 MsCoreUtils_1.25.4
#> [109] tibble_3.3.1 BiocManager_1.30.27
#> [111] cli_3.6.6 affyio_1.83.0
#> [113] xtable_1.8-8 jquerylib_0.1.4
#> [115] Rcpp_1.1.2 norm_1.0-11.1
#> [117] png_0.1-9 XML_3.99-0.25
#> [119] parallel_4.6.2 ggplot2_4.0.3
#> [121] readr_2.2.0 assertthat_0.2.1
#> [123] AnnotationFilter_1.37.0 mvtnorm_1.4-2
#> [125] scales_1.4.0 tmvtnorm_1.7
#> [127] affy_1.91.0 ncdf4_1.24
#> [129] purrr_1.2.2 crayon_1.5.3
#> [131] GetoptLong_1.1.1 rlang_1.3.0
#> [133] vsn_3.81.1