3.3 Multi-factor comparison

Some RNA-seq experiments include multiple experimental factors, such as treatment, time point, tissue, genotype, and batch. A multi-factor model can account for these factors simultaneously and can also test whether the effect of one factor depends on another.

Common biological questions include:

  • Is there a difference between treatment and control?
  • Is there a difference between tissues?
  • Does the treatment effect depend on time point?
  • Does the genotype effect depend on tissue?
  • Within a treatment group, does gene expression differ between time points?

The statistical design should be selected according to the biological question.

In this example, we analyze soybean RNA-seq data from control and treated leaves collected at several time points after water-deficit treatment (Rodrigues et al. 2015). The dataset is available from the EBI Expression Atlas under accession E-GEOD-69469.

atlas <- getAtlasData("E-GEOD-69469")
se <- atlas[[1]]$rnaseq

count_data <- as.matrix(assay(se, "counts"))
keep <- rowSums(cpm(count_data) > 5) > ncol(count_data) / 2
count_data <- count_data[keep, , drop = FALSE]
count_data <- as.matrix(count_data)
head(count_data)
##                 SRR2048167 SRR2048168 SRR2048169 SRR2048170 SRR2048171 SRR2048172 SRR2048173 SRR2048174 SRR2048175 SRR2048176 SRR2048177 SRR2048178 SRR2048179 SRR2048180 SRR2048181 SRR2048182 SRR2048183 SRR2048184 SRR2048185 SRR2048186 SRR2048187 SRR2048188 SRR2048189 SRR2048190 SRR2048191 SRR2048192 SRR2048193 SRR2048194 SRR2048195 SRR2048196 SRR2048197 SRR2048198 SRR2048199 SRR2048200 SRR2048201 SRR2048202
## ENSRNA049760259         46         43         16         50         68         29         11         28         28         40         28          9         30         70         91         11         28         73         37         97         61         21         65         23         58         44        180         34         27         67         78         34         33         54         16         41
## ENSRNA050000373        130        104        104         84         52         48         35         88        111         87         59         25         93        110        207        127         27         72         73        124        204         49        178         47        177        114        387         96         40        144        200         66         60         82         38        109
## ENSRNA050000380       3372       2412       2216       3014       2822       1702       1151       2824       2202       1907       1641        983       2501       2704       6699       1265       1023       3336       1915       2989       3910        990       3840       1145       2698       2381       5155       1587        971       2131       3103       1267       1090       1379        632       1918
## ENSRNA050000423       2971       2103       1634       2091       1876       1647        749       1796       1602       1283       1220        447        662        949       3485        318        562       1336        875       2153       4403        414       1419        695       1574       1268       4420        754        692       1684       2685        909        929       1225        556       1231
## ENSRNA050000426       5143       4175       3686       5639       5197       2034       3378       6924       6188       5320       2876       2233       5349       5616      14272       2169       2437       6220       3927       7912       8149       1735       5653       2003       5786       3694       9436       2461       1668       3805       5656       2270       1932       2545       1140       3016
## ENSRNA050001862        163        133        125        185        185         69        110        198        234        170         93         80        141        173        417         80         80        180        125        231        214         65        177         55        177        135        295         75         49        125        191         52         56         79         53         94
col_data <- as.data.frame(colData(se))
exp_design <- data.frame(
    group = factor(ifelse(grepl('control', col_data[, c("environmental_stress")]), 'control', 'stress')),
    timepoint = factor(gsub("Zeitgeber time ", "", col_data[, c("sampling_time_point")])))
exp_design
##      group timepoint
## 1   stress         0
## 2   stress         0
## 3   stress         0
## 4  control         0
## 5  control         0
## 6  control         0
## 7   stress         4
## 8   stress         4
## 9   stress         4
## 10 control         4
## 11 control         4
## 12 control         4
## 13  stress         8
## 14  stress         8
## 15  stress         8
## 16 control         8
## 17 control         8
## 18 control         8
## 19  stress        12
## 20  stress        12
## 21  stress        12
## 22 control        12
## 23 control        12
## 24 control        12
## 25  stress        16
## 26  stress        16
## 27  stress        16
## 28 control        16
## 29 control        16
## 30 control        16
## 31  stress        20
## 32  stress        20
## 33  stress        20
## 34 control        20
## 35 control        20
## 36 control        20

Create a SeqCountData object from the prepared count matrix and experimental design.

x <- newSeqCountData(count_data, exp_design = exp_design)

During DEGES-based normalization, candidate DEGs are removed from the data before the normalization factors are recomputed from the remaining genes. By default, calc_nf() screens candidate DEGs using the available experimental design, so genes associated with any modeled effect can be excluded from normalization factor estimation.

x <- calc_nf(x)

If normalization should remove candidate DEGs for a specific comparison, such as control versus treatment after adjusting for time point, see the Advanced Usage chapter.

Then convert the normalized object into a edgeR DGEList and run a edgeR quasi-likelihood test for the treatment effect while adjusting for time point; that is, coef = 2 in this design.

d <- as_DGEList(x)

design <- model.matrix(~ group + timepoint, data = exp_design)

d <- estimateDisp(d, design = design)
fit <- glmQLFit(d, design = design)
qlf <- glmQLFTest(fit, coef = 2)

Do not assume that a biological effect is always represented by coef = 2. The coefficient number depends on the factor levels, their reference levels, the order of terms in the model, and the presence of interaction terms. Before running a statistical test, inspect the design matrix column names. After confirming the meaning of each coefficient, test the coefficient of interest. In this example, coef = 2 corresponds to the treatment effect used above.

colnames(design)
## [1] "(Intercept)" "groupstress" "timepoint12" "timepoint16" "timepoint20" "timepoint4"  "timepoint8"

Extract the results.

test_stats <- topTags(qlf, n = nrow(d$counts), sort.by = "none")$table
head(test_stats)
##                         logFC   logCPM            F     PValue       FDR
## ENSRNA049760259 -0.3372351845 2.694545 6.639535e+00 0.01425689 0.0620473
## ENSRNA050000373 -0.0958208298 3.861405 3.310878e-01 0.56862490 0.7237248
## ENSRNA050000380 -0.1593806127 8.333032 4.934011e+00 0.03275791 0.1109259
## ENSRNA050000423 -0.0003588716 7.738853 9.163468e-06 0.99760154 0.9988933
## ENSRNA050000426  0.0110208839 9.273367 3.896653e-02 0.84463327 0.9109317
## ENSRNA050001862 -0.0942038960 4.316354 1.342311e+00 0.25431019 0.4369289

Here, the analysis compares treatment groups while accounting for differences among time points. When the model includes interaction terms, the coefficient for a main effect describes that effect only at the reference level of the other factor. It should not be interpreted as the average effect across all tissues, time points, or developmental stages. Therefore, the coefficient or contrast must be selected according to the specific biological comparison of interest.

The same multi-factor comparison can be performed with DESeq2.

library(DESeq2)

x <- newSeqCountData(count_data, exp_design = exp_design)
x <- calc_nf(x, norm_func = norm_rle, test_func = test_deseq2)

dds <- as_DESeqDataSet(x, design = ~ group + timepoint)

dds <- estimateDispersions(dds)
dds <- nbinomLRT(dds, full = ~ group + timepoint, reduced = ~ timepoint)
test_stats <- results(dds)
head(test_stats)
## log2 fold change (MLE): timepoint 8 vs 0 
## LRT p-value: '~ group + timepoint' vs '~ timepoint' 
## DataFrame with 6 rows and 6 columns
##                  baseMean log2FoldChange     lfcSE       stat    pvalue      padj
##                 <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
## ENSRNA049760259   47.8538      -0.419818 0.2282933 5.96967911 0.0145539 0.0598528
## ENSRNA050000373  110.1385      -0.202770 0.2897823 0.27864507 0.5975907 0.7477595
## ENSRNA050000380 2456.5260      -0.600964 0.1196823 4.47284045 0.0344377 0.1107921
## ENSRNA050000423 1625.7716      -1.671562 0.2133009 0.00811839 0.9282061 0.9609125
## ENSRNA050000426 4715.0534      -0.267795 0.0818337 0.24745743 0.6188711 0.7634494
## ENSRNA050001862  152.0347      -0.418654 0.1291651 0.75774444 0.3840353 0.5680314

The interpretation of an LRT is determined by the difference between the full and reduced models. Here, the reduced model removes all terms containing group. The test therefore asks whether treatment-related terms improve model fit. It does not represent one simple pairwise contrast.