4.1 Custom normalization functions

normpatch provides DEGES-based normalization workflows. The workflow requires both a normalization function and a DEG screening function. By default, normpatch uses normalization and test functions from widely used packages, edgeR and DESeq2. In addition to the provided functions, normpatch also supports custom functions.

Here, we show an example of using a custom normalization function with calc_nf(). The normalization function should receive x as a count matrix and exp_design as an experimental design data frame, then return normalization factors. Following this rule, users can define their own normalization steps.

Here, we implement upper-quartile normalization and pass it to calc_nf().

norm_uq <- function(x, exp_design, ...) {
    x <- as.matrix(x)
    keep <- rowSums(x > 0) > 0
    x <- x[keep, , drop = FALSE]
    uq <- apply(x, 2, quantile, probs = 0.75, names = FALSE)
    nf <- uq / colSums(x)
    nf <- nf / exp(mean(log(nf)))
    nf
}

In this example, we customize only the normalization function. The test function uses the default edgeR quasi-likelihood test, so no custom test function is needed.

After defining the function, load the required packages and prepare the data as in the basic workflow.

library(edgeR)
library(baySeq)
library(normpatch)

count_data <- read.table("data/ath.E-MTAB-4391.txt",
                         header = TRUE, sep = "\t", row.names = 1)
keep <- rowSums(edgeR::cpm(count_data) > 5) > (ncol(count_data) / 2)
count_data <- as.matrix(count_data[keep, , drop = FALSE])

group <- sapply(strsplit(colnames(count_data), "_"), "[", 1)
exp_design <- data.frame(group = factor(group))

x <- newSeqCountData(count_data, exp_design = exp_design)

Then run calc_nf() with the custom norm_uq() function specified through the norm_func argument.

x <- calc_nf(x, norm_func = norm_uq)
x@meta$nf
## control_1 control_2 control_3  stress_1  stress_2  stress_3 
## 1.0111804 1.0045374 1.0104885 0.9820282 0.9761763 1.0155891

The example above implements upper-quartile normalization to demonstrate how a custom normalization function can be integrated into calc_nf().

However, edgeR can also perform upper-quartile normalization through calcNormFactors() by setting method = "upperquartile". The workflow can therefore be changed from TMM to upper-quartile normalization as follows. Additional arguments supplied to calc_nf() are forwarded to the normalization function. In this example, method = "upperquartile" is passed to calcNormFactors().

x <- newSeqCountData(count_data, exp_design = exp_design)
x <- calc_nf(x, method="upperquartile")
x@meta$nf
## control_1 control_2 control_3  stress_1  stress_2  stress_3 
## 1.0111804 1.0045374 1.0104885 0.9820282 0.9761763 1.0155891